多线程环境中,经常出现这样一种场景。一个线程修改了一个对象的值,而另一个线程感知到了变化,然后进行相应的操作,整个过程开始于一个线程,最终结束于另一个线程。这就是传说中的生产者/消费者模型(前者是生产者,后者是消费者)。
而实现这种功能比较简单的方法就是让消费者线程不断的循环变量判断是否符合预期。如下所示
while (!isOK(...)){
Thread.sleep(1000);
}
doIt();
while 循环中设置不满足的条件,如果条件满足则退出循环(睡眠可以防止过快的“无效尝试”)
如果isOK方法的判断逻辑比较简单,操作耗时较短,而且并发冲突量不大的情况下,使用这种方案也未尝不可。但是如果判断逻辑比较复杂,或者并发冲突较大时。这种方案就不行了,while循环会执行很多很多次,CPU消耗较大。
针对这种问题,Java内置的等待通知机制
能够较好的解决。当条件不满足时,线程阻塞自己,进入等待状态。当线程条件满足时,通知等待的线程重新执行。线程阻塞避免了循环等待带来的CPU消耗问题。
首先我们来考虑一个问题?
在Lock出现之前我们一直使用synchronized来实现同步访问。那为什么还要提供lock呢?
我们知道如果一个代码块被synchronized修饰了,当有一个线程获取了对应的锁,并执行该代码快时,其他线程就只能在一旁等待。
而获取锁的线程只有在线程正常执行完该代码
或者线程执行过程中发生异常
才会释放对锁的占有。
在synchronized这种机制下,程序就有可能出现如下问题:
破坏不可抢占条件
synchronized 没有办法解决。原因是 synchronized 申请资源的时候,如果申请不到,线程直接进入阻塞状态了,而线程进入阻塞状态,啥都干不了,也释放不了线程已经占有的资源。正是由于这些因素的限制,需要开发出一种满足如下条件的同步机制。
一门技术的出现必然有其出现的道理,后来需要了解它出现的时代环境和因素,扩充自己的视野,发掘技术发展的经过。分析其优缺点,以便更好的运用。
一直以来,硬件的发展极其迅速,也有一个很著名的 摩尔定律
,然而事实证明摩尔定律的有效性超过半个世纪就失效了。为了进一步提升计算速度,放弃了一味追求单独的计算单元,将多个计算单元整合到一起,也就是形成了多核CPU。在多核CPU的环境下,并发编程的形式可以将多核CPU的计算能力发挥到极致,性能得到提升。