1. 线程状态图
这是线程的7状态模型图,常见的7大状态之间的转换关系也在上面。多线程之间的通信主要用到4个方法,wait()、wait(long time)、notify()、notifyAll(),其他方法在多线程基础中都有介绍。
1. wait():作用是使当前线程从调用处中断并且释放锁转入等待队列,直到收到notify或者notifyAll的通知才能从等待队列转入锁池队列,没有收到停止会一直死等。
2. wait(long time):相比wait多了一个等待的时间time,如果经过time(毫秒)时间后没有收到notify或者notifyAll的通知,自动从等待队列转入锁池队列。
3. notify():随机从等待队列中通知一个持有相同锁的一个线程,如果没有持有相同锁的wait线程那么指令忽略无效。注意是持有相同锁,并且是随机没有固定的,顺序这一点在生产者消费者模型中很重要,会造成假死的状态。
4. notifyAll():通知等待队列中的持有相同锁的所有线程,让这些线程转入锁池队列。如果没有持有相同锁的wait线程那么指令忽略无效。
5. wait的两个方法都需要注意中断的问题,wait中断是从语句处中断并且释放锁,当再次获得锁时(在锁池队列中)是从中断处继续向下执行。
6. 在while循环里而不是if语句下使用wait,这样,会在线程暂停恢复后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知
7. notify 和 notifyAll方法通知是延迟通知,必须等待当前线程体执行完所有的同步方法/代码块中的语句退出释放锁才通知wait线程。
8. 这四个方法都必须在获得锁的情况下才能调用,否则会出现非法监视状态异常。
2.永远在循环(loop)里调用 wait 和 notify,不是在 If 语句
我们现在已经知道了wait()应该永远在被synchronized同步代码块或同步方法中进行调用,而需要着重注意的一点是:应该永远在while循环,而不是if语句中调用wait。
为线程是在某些条件下等待的————我们在实际开发中往往会设定一些条件,而使线程进入等待,这个时候你可能直觉就会写一个if语句。但if语句存在一些微妙的小问题,导致即使条件没被满足,但是你的线程你也有可能被错误地唤醒,此时使用if会使线程在没有满足条件的情况下向下执行。所以如果你不在线程被唤醒后再次使用while循环检查唤醒条件是否被满足,你的程序就有可能会出错。
所以,根据JDK给出的代码示例,应该这样去使用wait():
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
// Perform action appropriate to condition
// Do something......
}
在while循环里使用wait的目的,是在线程被唤醒的前后都持续检查条件是否被满足。如果条件并未改变,wait被调用之前notify的唤醒通知就来了,那么这个线程并不能保证被唤醒,有可能会导致死锁问题。