为何wait和notify方法必须加锁?
是为了避免Lost Wake Up问题,即丢失唤醒问题。
所谓Lost Wake Up,指的是:线程A调用wait()方法进入阻塞状态,接下来没有其他线程去唤醒线程A,或者其他线程唤醒的时机不对(早于线程A的wait()),导致线程A永远阻塞下去。
下面以一个生产者和消费者的案例来说明上述问题。
假如我们有两个线程,一个消费者线程,一个生产者线程。生产者线程的任务可以简化成将count加一,而后唤醒消费者;消费者则是将count减一,而后在减到0的时候陷入睡眠,代码如下:
先定义一个 obj 对象,并将其 count 属性的初始值设置为 0:
Object obj = new Object();
obj.count = 0;
- 生产者
obj.count++;
obj.notify();
- 消费者
while(obj.count<=0)
obj.wait();
obj.count--;
很明显,上述代码会出现问题,因为生产者和消费者的操作均不是原子的。两个线程启动,消费者检查 obj.count 的值,发现 obj.count <= 0 条件成立,但这时由于 CPU 的调度,发生上下文切换,生产者开始工作,执行了 count+1 和 obj.notify(),也就是发出通知,准备唤醒一