java 中线程之间的通信问题,有这么一个模型:一个线程修改了一个对象的值,而另一个线程感知到了变化,然后进行相应的操作,整个过程开始于一个线程,而最终执行又是另一个线程。前者是生产者,后者就是消费者,也可以叫做生产者-消费者问题
生产者生产了产品,如何通知消费者?下面就介绍下java线程中的等待-通知机制。其它语言类似,自行研究。代码附上
下面是以买小米5手机为例子,来说明等待通知机制
1 /**
2 * 买小米5手机
3 * @author zhanghongjun
4 *
5 */
6 public class BuyXiaoMi5 {
7 static boolean hasXiaoMi5 = false;
8 static Object lock = new Object();
9
10 public static void main(String[] args) throws InterruptedException {
11 //消费者
12 Thread miFansThread = new Thread(new MiFans(),"MiFans");
13
14 //生产者
15 Thread leiBS = new Thread(new LeiBuShi(),"LeiBuShi");
16
17 miFansThread.start();
18 leiBS.start();
19
20 }
21
22 /**
23 * 雷布斯,生产者
24 * @author zhanghongjun
25 *
26 */
27 static class LeiBuShi implements Runnable{
28 @Override
29 public void run() {
30 synchronized (lock) {
31 System.out.println("Are you ok ? 我们开始生产小米5了,大家等一等啊");
32 try {
33 System.out.println("Are you ok ? 小米5手机生产ing中,大家等一等啊");
34 Thread.sleep(3000); //6个月后,小米5终于上市了
35 } catch (InterruptedException e) {
36 e.printStackTrace();
37 }
38
39 System.out.println("Are you ok? 小米5上市啦,大家可以哄抢啦");
40 lock.notifyAll(); //通知所有的人,可以抢手机了
41 hasXiaoMi5 = true; //终于有小米5手机了
42 }
43 }
44
45 }
46
47
48 /**
49 * 米粉,消费者
50 * @author zhanghongjun
51 *
52 */
53 static class MiFans implements Runnable{
54 @Override
55 public void run() {
56 synchronized (lock) {
57 //没有小米5手机,只有等待了
58 while(!hasXiaoMi5){
59 System.out.println("雷军耍猴,不知道要等多久,才能买到小米5...");
60 try {
61 lock.wait();
62 } catch (InterruptedException e) {
63 e.printStackTrace();
64 }
65 }
66 }
67
68 System.out.println("我是米粉,终于买到一台发烧的小米5了,开森中。。。");
69 }
70 }
71
72 }
上面代码可以看到,开始的时候,米粉线程要买小米5手机,结果条件不满足,hasXiaoMi5 = false; 当条件不满足的时候,就需要等待, lock.wait();
此时线程进入等待队列中,线程会阻塞,需要注意 lock.wait() ,是会释放锁的,进而进入到线程的等待队列中,这时候,因为wait()已经释放了锁,所以,LeiBuShi 线程就可以
获得锁,进而去生产手机,等到手机生产出来以后,既 hasXiaoMi5 = true了,这时候就通知在此锁上等待的线程,lock.notify()或者lock.notifyAll,之后,离开同步块,进而释放锁,这时候 61行,lock.wait() 函数返回,条件成立,进而继续向下运行,买到手机。
这里需要注意的几点如下:
1 使用wait(),notify(),notifyAll()时需要先对调用对象加锁
2 调用wait()方法后,线程状态由Running状态变为 waiting状态,并将当前线程放置到线程的等待队列中
3 notify()或者notifyAll()方法调用后,等待线程依旧不会从wait()返回,需要调用notify()或者nofityAll()的线程释放锁之后,等待线程才有机会从wait()返回
4 从wait()方法返回的前提是获得了调用对象的锁.
等待/通知的经典范式
等待方步骤如下:
1 获取对象的锁
2 如果条件满足,那么调用对象的wait()方法,被通知后仍要检查条件。
3 条件满足则执行相应的业务逻辑
对应的伪代码如下:
synchronized(对象){
while(条件不满足时){
对象.wait()
}
对应的逻辑
}
通知方步骤如下:
1 获得对象的锁
2 改变条件
3 通知所有等待对象上的线程
对应的伪代码如下:
synchronized(对象){
改变条件
对象.notifyAll()
}
以上就是典型的通知等待机制。能力有限,希望对大家有所帮助