线程方法wait()和notify()的使用

实现需求:

开启2个线程,1个线程对某个int类型成员变量加1,另外1个减1,但是要次序执行,即如果int型的成员变量是0,则输出01010101这样的结果

代码如下

 1 package test;
 2 
 3 public class Sample {
 4 
 5     private int i;
 6 
 7     public synchronized void increase() {
 8 
 9         if(i != 0) { // 值不为0时,已经加过,释放锁,等待其他线程减为0
10             try {
11                 wait();
12             } catch (Exception e) {
13                 e.printStackTrace();
14             }
15         }
16 
17         // 值为0,需要增加
18         i++;
19         System.out.println(i);
20         // 通知其他线程,可以进行减1的操作了
21         notify();
22     }
23 
24     public synchronized void decrease() {
25         if(i == 0) { // 值为0时,已经减过,释放锁,等待其他线程加为1
26             try {
27                 wait();
28             } catch (Exception e) {
29                 e.printStackTrace();
30             }
31         }
32 
33         // 值为1,需要减少
34         i--;
35         System.out.println(i);
36         // 通知其他线程,可以进行加1的操作了
37         notify();
38     }
39 
40     public static void main(String[] args) {
41 
42         Sample sample = new Sample();
43 
44         Thread t1 = new IncreaseThread(sample);
45         Thread t2 = new DecreaseThread(sample);
46 
47         t1.start();
48         t2.start();
49     }
50 }
51 
52 class DecreaseThread extends Thread {
53 
54     private Sample sample;
55 
56     public DecreaseThread(Sample sample) {
57         this.sample = sample;
58     }
59 
60     @Override
61     public void run() {
62         for (int i = 0; i < 20; i++) {
63             try {
64                 Thread.sleep((long) Math.random() * 1000);
65             } catch (Exception e) {
66                 e.printStackTrace();
67             }
68 
69             sample.decrease();
70         }
71     }
72 }
73 
74 class IncreaseThread extends Thread {
75 
76     private Sample sample;
77 
78     public IncreaseThread(Sample sample) {
79         this.sample = sample;
80     }
81 
82     @Override
83     public void run() {
84         for (int i = 0; i < 20; i++) {
85             try {
86                 Thread.sleep((long) Math.random() * 1000);
87             } catch (Exception e) {
88                 e.printStackTrace();
89             }
90 
91             sample.increase();
92         }
93     }
94 }

 

 

需求稍作改变,变成:

开启4个线程,2个线程对某个int类型成员变量加1,另外2个减1,但是要次序执行,即如果int型的成员变量是0,则输出01010101这样的结果

如果是直接再生成t3 t4分别是IncreaseThread和DecreaseThread的实例(即t1/t3为IncreaseThread类的实例,t2/t4为DecreaseThread的实例),假设执行流程如下:

(1)t2执行,由于i=0,所以线程等待,释放锁,随机通知一条线程进行执行(notify()方法是通知随机一条线程的)

(2)假设通知到了t4,由于i=0,所以t4线程又等待,锁释放,又随机通知到一条线程进行执行

(3)假设又通知到了t2线程,这个时候,线程的执行是从wait()方法后面开始执行的,不会再去判断i是否等于0了,继续执行,会进行i的自减操作,出现i=-1的局面

 

所以代码需要修改

 1 package test;
 2 
 3 public class Sample {
 4 
 5     private int i;
 6 
 7     public synchronized void increase() {
 8 
 9         while(i != 0) { // 值不为0时,已经加过,释放锁,等待其他线程减为0
10             try {
11                 wait();
12             } catch (Exception e) {
13                 e.printStackTrace();
14             }
15         }
16 
17         // 值为0,需要增加
18         i++;
19         System.out.println(i);
20         // 通知其他线程,可以进行减1的操作了
21         notify();
22     }
23 
24     public synchronized void decrease() {
25         while(i == 0) { // 值为0时,已经减过,释放锁,等待其他线程加为1
26             try {
27                 wait();
28             } catch (Exception e) {
29                 e.printStackTrace();
30             }
31         }
32 
33         // 值为1,需要减少
34         i--;
35         System.out.println(i);
36         // 通知其他线程,可以进行加1的操作了
37         notify();
38     }
39 
40     public static void main(String[] args) {
41 
42         Sample sample = new Sample();
43 
44         Thread t1 = new IncreaseThread(sample);
45         Thread t2 = new DecreaseThread(sample);
46         Thread t3 = new IncreaseThread(sample);
47         Thread t4 = new DecreaseThread(sample);
48 
49         t1.start();
50         t2.start();
51         t3.start();
52         t4.start();
53     }
54 }
55 
56 class DecreaseThread extends Thread {
57 
58     private Sample sample;
59 
60     public DecreaseThread(Sample sample) {
61         this.sample = sample;
62     }
63 
64     @Override
65     public void run() {
66         for (int i = 0; i < 20; i++) {
67             try {
68                 Thread.sleep((long) Math.random() * 1000);
69             } catch (Exception e) {
70                 e.printStackTrace();
71             }
72 
73             sample.decrease();
74         }
75     }
76 }
77 
78 class IncreaseThread extends Thread {
79 
80     private Sample sample;
81 
82     public IncreaseThread(Sample sample) {
83         this.sample = sample;
84     }
85 
86     @Override
87     public void run() {
88         for (int i = 0; i < 20; i++) {
89             try {
90                 Thread.sleep((long) Math.random() * 1000);
91             } catch (Exception e) {
92                 e.printStackTrace();
93             }
94 
95             sample.increase();
96         }
97     }
98 }

 

这里把if判断改成了while循环,因为wait方法之后,应该是需要重复判断一次i的情况的,这样就不会出现数字不对的情况了

 

这里有一条基本原则:

永远在while循环里而不是if语句下使用wait。这样,会在线程暂停恢复后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知

 

posted @ 2018-05-16 21:12  无名草110  阅读(296)  评论(0编辑  收藏  举报