多线程相关wait()和notify()

  • wait()和notify()

  wait会释放锁,notify不会释放锁。必须与synchronize使用。。。

 1 /**
 2  * 曾经的面试题:(淘宝?)
 3  * 实现一个容器,提供两个方法,add,size
 4  * 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束
 5  * 
 6  * 给lists添加volatile之后,t2能够接到通知,但是,t2线程的死循环很浪费cpu,如果不用死循环,该怎么做呢?
 7  * 
 8  * 这里使用wait和notify做到,wait会释放锁,而notify不会释放锁
 9  * 需要注意的是,运用这种方法,必须要保证t2先执行,也就是首先让t2监听才可以
10  * 14  * 
15  * notify之后,t1必须释放锁,t2退出后,也必须notify,通知t1继续执行
16  * 整个通信过程比较繁琐
17  * @author mashibing
18  */
19 package com.concurrent.c019;
20 
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.concurrent.TimeUnit;
24 
25 
26 public class MyContainer4 {
27 
28     //添加volatile,使t2能够得到通知
29     volatile List lists = new ArrayList();
30 
31     public void add(Object o) {
32         lists.add(o);
33     }
34 
35     public int size() {
36         return lists.size();
37     }
38     
39     public static void main(String[] args) {
40         MyContainer4 c = new MyContainer4();
41         
42         final Object lock = new Object();
43         
44         new Thread(() -> {
45             synchronized(lock) {
46                 System.out.println("t2启动");
47                 if(c.size() != 5) {
48                     try {
49                         lock.wait();
50                     } catch (InterruptedException e) {
51                         e.printStackTrace();
52                     }
53                 }
54                 System.out.println("t2 结束");
55                 //通知t1继续执行
56                 lock.notify();
57             }
58             
59         }, "t2").start();
60         
61         try {
62             TimeUnit.SECONDS.sleep(1);
63         } catch (InterruptedException e1) {
64             e1.printStackTrace();
65         }
66 
67         new Thread(() -> {
68             System.out.println("t1启动");
69             synchronized(lock) {
70                 for(int i=0; i<10; i++) {
71                     c.add(new Object());
72                     System.out.println("add " + i);
73                     
74                     if(c.size() == 5) {
75                         lock.notify();
76                         //释放锁,让t2得以执行
77                         try {
78                             lock.wait();
79                         } catch (InterruptedException e) {
80                             e.printStackTrace();
81                         }
82                     }
83                     
84                     try {
85                         TimeUnit.SECONDS.sleep(1);
86                     } catch (InterruptedException e) {
87                         e.printStackTrace();
88                     }
89                 }
90             }
91         }, "t1").start();
92         
93         
94     }
95 }

==============================

另一种使用CountDown

 1 /**
 2  * 曾经的面试题:(淘宝?)
 3  * 实现一个容器,提供两个方法,add,size
 4  * 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,线程2给出提示并结束
 5  * 
 6  * 给lists添加volatile之后,t2能够接到通知,但是,t2线程的死循环很浪费cpu,如果不用死循环,该怎么做呢?
 7  * 
 8  * 这里使用wait和notify做到,wait会释放锁,而notify不会释放锁
 9  * 需要注意的是,运用这种方法,必须要保证t2先执行,也就是首先让t2监听才可以
10  * 
11  * 阅读下面的程序,并分析输出结果
12  * 可以读到输出结果并不是size=5时t2退出,而是t1结束时t2才接收到通知而退出
13  * 想想这是为什么?
14  * 
15  * notify之后,t1必须释放锁,t2退出后,也必须notify,通知t1继续执行
16  * 整个通信过程比较繁琐
17  * 
18  * 使用Latch(门闩)替代wait notify来进行通知
19  * 好处是通信方式简单,同时也可以指定等待时间
20  * 使用await和countdown方法替代wait和notify
21  * CountDownLatch不涉及锁定,当count的值为零时当前线程继续运行
22  * 当不涉及同步,只是涉及线程通信的时候,用synchronized + wait/notify就显得太重了
23  * 这时应该考虑countdownlatch/cyclicbarrier/semaphore
24  * @author mashibing
25  */
26 package com.concurrent.c019;
27 
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.concurrent.CountDownLatch;
31 import java.util.concurrent.TimeUnit;
32 
33 public class MyContainer5 {
34 
35     // 添加volatile,使t2能够得到通知
36     volatile List lists = new ArrayList();
37 
38     public void add(Object o) {
39         lists.add(o);
40     }
41 
42     public int size() {
43         return lists.size();
44     }
45 
46     public static void main(String[] args) {
47         MyContainer5 c = new MyContainer5();
48 
49         CountDownLatch latch = new CountDownLatch(1);
50 
51         new Thread(() -> {
52             System.out.println("t2启动");
53             if (c.size() != 5) {
54                 try {
55                     latch.await();
56                     
57                     //也可以指定等待时间
58                     //latch.await(5000, TimeUnit.MILLISECONDS);
59                 } catch (InterruptedException e) {
60                     e.printStackTrace();
61                 }
62             }
63             System.out.println("t2 结束");
64 
65         }, "t2").start();
66 
67         try {
68             TimeUnit.SECONDS.sleep(1);
69         } catch (InterruptedException e1) {
70             e1.printStackTrace();
71         }
72 
73         new Thread(() -> {
74             System.out.println("t1启动");
75             for (int i = 0; i < 10; i++) {
76                 c.add(new Object());
77                 System.out.println("add " + i);
78 
79                 if (c.size() == 5) {
80                     // 打开门闩,让t2得以执行
81                     latch.countDown();
82                 }
83 
84                 try {
85                     TimeUnit.SECONDS.sleep(1);
86                 } catch (InterruptedException e) {
87                     e.printStackTrace();
88                 }
89             }
90 
91         }, "t1").start();
92 
93     }
94 }
原文地址:https://www.cnblogs.com/zchok/p/12972209.html