我爱编程程序员

Java多线程--基础概念

2018-04-13  本文已影响44人  sunhaiyu

Java多线程--基础概念

必须知道的几个概念

同步和异步

同步方法一旦开始,调用者必须等到方法调用返回后,才能执行后续行为;而异步方法调用,一旦开始,方法调用就立即返回,调用者不用等待就可以继续执行后续行为。

更具体地说,同步调用就是调用者调用当前方法后,就一直等待着该方法执行完毕并返回结果;而异步调用是调用者调用方法后,可以不用等待,直接开始其他行为的执行,等到某一个时间点原来的方法执行结束后要返回结果,会通知调用者。

并发和并行

临界区

可以被多个线程使用的公共资源或共享资源。但是每一次只能有一个线程使用它,一旦临界区资源被(某一个线程)占用,其他线程若想要使用这个资源,就必须等待。

阻塞和非阻塞

某一个线程占用了临界区资源,其他想要使用这个资源的线程就必须等待,等待导致线程挂起,这就是阻塞。非阻塞与之相反:没有一个线程可以妨碍其他线程的执行

死锁、饥饿和活锁

死锁。都占用着对方想要的资源不释放,如A占用B想要的不释放,B也占用着A的不释放,形成了“环”。

饥饿。一个或者多个线程无法获得所需的资源,迟迟不能得到执行。饥饿有如下两种情况:

饥饿有可能在未来的一段时间内解决,比如低优先级的线程终于拿到了资源,或者线程执行完成不再一直占用资源了。

活锁。线程都主动礼让,将资源释放给其他线程使用。比如A将资源给B,B也礼让给A,就导致了资源在A、B之间跳动,从而没有一个线程可以拿到资源。就好像“踢皮球”。

并发级别

两个关于并行的定律

Amdahl定律

$$T_n = T_1(F + 1/n(1-F))$$

$$T_n = \frac{1}{F+1/n(1-F)}$$

$T_n$定义为加速比

加速比 = 优化前系统耗时 / 优化后系统耗时

其中$n$是处理器的个数,F是串行化比例。即必须串行的步骤数 / 总步骤数,$F = 1$表示所有步骤只能串行完成,加速比为1(没有加速);$F = 0$表示所有步骤可以由多核同时执行,加速比为处理器个数$n$。

可以看出Amdahl定律优化效果取决于处理器的个数,以及串行化比例。CPU越多,串行化比例越低,优化效果越好。一味的增加CPU的个数,不降低串行化比例的化,也无法提高系统性能。

Guastafon定律

$$s(n) = n - F(n - 1)$$

$S(n)$和上面一样表示加速比,$n$和$F$的意义也与上面相同。

Amdahl定律强调:当串行比例F固定时,加速比是有上限的,无论增加多少CPU都不能突破该上限(上限可以计算极限得到)

Gustafson定律强调:当串行化比例F固定时,只要串行化比例足够小(可并行化的代码比重足够大),那么加速比可以随着CPU的数量线性增长。(F是常数时,S(n)是n的一次函数)

JMM(Java内存模型)

原子性

原子性指一个操作不可中断:一个线程一旦开始,直到执行完成都不会被其他线程干扰。

可见性

可见性指当一个线程修改了某个共享变量的值,其他线程是否能立即知道这个修改。串行中不存在可见性问题,因为某个线程修改了某个值,在后续步骤中,其他线程读取到这个值时,一定时修改后的值了。在并行程序中,如编译器优化的原因,在CPU1上对变量a进行了优化,将其缓存在cache或寄存器中,此时如果CPU2修改了a的实际值,CPU1可能无法意识到a已经被修改,依然会读取缓存里的旧值。

除了编译器优化,指令重排以及编辑器优化都可能产生可见性问题。

有序性

代码不按照本来的顺序执行,即写在前面的代码跑到了后面去执行。指令的执行顺序乱了,这就是有序性问题。

程序在执行时,可能会进行指令重排,重排后的顺序依然保持着串行语义一致,但不保证在并行下语义也一致。

之所以要进行指令重排,是出于优化的考虑,为了减少中断流水线,即中断产生的等待时间,提高CPU处理性能

Happen-Before规则

有些指令是可以重排的,有些指令是不可重排的。下面是一些基本原则:


by @sunhaiyu

2018.4.10

上一篇 下一篇

猜你喜欢

热点阅读