java多线程编程(六)-线程间通信

时间:2022-01-06 17:31:09

一:线程通信介绍

  线程通信是通过主动放弃对资源的使用,而让给其它线程的过程。合理的安排多个线程对同一资源的使用,即设计线程间的通信,可以完成很多复杂的任务。

 

 

二:线程通信实现  

  1,java.lang.Object超类

java多线程编程(六)-线程间通信

    a,上图为Object类的常用方法,其中提供的notify(),notifyAll(),wait(),wait(long timeout) 和 wait(long timeout,int nanos)五个方法可以实现线程间通信。

    b,五个方法都是被final修饰,所以不能被重写

  

 

  2,notify方法

    notify()使用介绍:Wakes up a single thread that is waiting for this object's monitor.            

    notifyAll()使用介绍:Wakes up all threads that are waiting for this object's monitor.

 

 

  3,wait方法

    wait()使用介绍:Causes the current thread to wait until another thread invokes the notify() or the notifyAll() method for this object.

    wait(long timeout)使用介绍:Causes the current thread to wait until either another thread invokes the notify() or notifyAll() method for this object,or a specified amount of time has elapsed.

    wait(long timeout, int nanos)使用介绍:Causes the current thread to wait until another thread invokes the notify() or the notifyAll() method for this object,or some other thread interrupts the current thread ,or a centain amount of the real time has elapsed.

 

 

  4,个人总结和附录

    a,wait后的线程只能通过notify方法唤醒,从而重新进入就绪状态。

    b,notify()方法只能唤醒一个在wait的线程,且是随机的。

    c,从使用介绍中的 ‘current thread’,解读wait方法的使用需要使用线程必须拥有目标对象的锁,而notify()中使用介绍是主动唤醒其它线程,所以也必须拥有目标对象的锁才有资格去唤醒其它线程。所以wait()和notify方法的使用线程必须拥有目标对象的锁,即在使用时,wait方法和notify方法必须放在synchronized方法或sysnchronized代码块中

    d,wait方法是主动放弃锁,使线程进入等待锁,发生等待阻塞。而sleep方法并没有让线程放弃对象的锁。

    

    附录

      wake up:唤醒

      monitor:监视器,即lock,锁。

      causer:导致,引起

      invokes:调用

      specified time:指定的时间

      elapsed:逝去的

 

 

 

 

三:设计案例(1010..案例)

   1,基础案例

     下述案利用合理设计线程间的通信例,实现了1010..的打印。

java多线程编程(六)-线程间通信java多线程编程(六)-线程间通信
 1 package com.thread.www;
 2 /**
 3  * 得到 1010的输出结果
 4  * @author xiaojia
 5  *
 6  */
 7 //目标对象
 8 class NumberHolder {
 9     private int num = 0;
10     //加数
11     public synchronized void increaseNum(){
12         if(0 != num){
13             try {
14                 wait();
15             } catch (InterruptedException e) {
16                 e.printStackTrace();
17             }
18         }
19         num ++;
20         System.out.print(num);
21         
22         notify();
23     }
24     //减数
25     public synchronized void decreaseNum(){
26         if(0 == num){
27             try {
28                 wait();
29             } catch (InterruptedException e) {
30                 e.printStackTrace();
31             }
32         }
33         num --;
34         System.out.print(num);
35         notify();
36     }
37 }
38 
39 //加数线程 和 减数线程
40 class IncreaseThread extends Thread{
41     NumberHolder nholder;
42     
43     public IncreaseThread(NumberHolder nholder) {
44         this.nholder = nholder;
45     }
46     
47     @Override
48     public void run() {
49         
50         for (int i = 0; i < 10; i++) {
51             nholder.increaseNum();
52         }
53     }
54 }
55 
56 class DecreaseThread extends Thread{
57     NumberHolder nholder;
58     
59     public DecreaseThread(NumberHolder nholder) {
60         this.nholder = nholder;
61     }
62     
63     @Override
64     public void run() {
65         
66         for (int i = 0; i < 10; i++) {
67             nholder.decreaseNum();
68         }
69     }
70 }
71 
72 //启动线程
73 public class Test7线程间的通信1 {
74 
75     public static void main(String[] args) {
76         NumberHolder nholder = new NumberHolder();
77         
78         IncreaseThread inTh = new IncreaseThread(nholder);
79         DecreaseThread deTh = new DecreaseThread(nholder);
80         
81         inTh.start();
82         deTh.start();
83     }
84 
85 }
basics Code

 

   2,问题案例

     如果创建多个线程,进行加数和减数,基础案例就得不到1010..有规律的打印了,main方法修改如下:

 1 public class Test8线程间的通信2 {
 2 
 3     public static void main(String[] args) {
 4         NumberHolder numHolder = new NumberHolder();
 5         
 6         IncreaseThread inTh = new IncreaseThread(numHolder);
 7         DecreaseThread deTh = new DecreaseThread(numHolder);
 8         inTh.start();
 9         deTh.start();
10         
11         IncreaseThread inTh2 = new IncreaseThread(numHolder);
12         DecreaseThread deTh2 = new DecreaseThread(numHolder);
13         inTh2.start();
14         deTh2.start();
15     }
16 }

 

  3,完整案例

  问题案例中,由于有四个创建的线程,拥有锁对象的线程唤醒wait的其它三个线程是随机的,因此不能按规律打印1010..。

  解决办法:将加数和减数方法进入wait的if判断修改为while条件,这样当线程被唤醒后还是要进行进行零和非零的判断,才能加数或减数。

java多线程编程(六)-线程间通信java多线程编程(六)-线程间通信
 1 package com.thread.www;
 2 
 3 class NumberHolder3 {
 4     private int num = 0;
 5     public synchronized void increaseNum(){
 6         while(num != 0){
 7             try {
 8                 wait();
 9             } catch (InterruptedException e) {
10                 e.printStackTrace();
11             }
12         }
13         num ++;
14         System.out.print(num+" ");
15         
16         notify();
17     }
18     
19     public synchronized void decreaseNum(){
20         while(num == 0){
21             try {
22                 wait();
23             } catch (InterruptedException e) {
24                 e.printStackTrace();
25             }
26         }
27         num --;
28         System.out.print(num+" ");
29         
30         notify();
31     }
32 }
33 
34 class IncreaseThread3 extends Thread{
35     private NumberHolder3 numHolder;
36     public IncreaseThread3(NumberHolder3 numHolder) {
37         this.numHolder = numHolder;
38     }
39     @Override
40     public void run() {
41         for (int i = 0; i < 10; i++) {
42             try {
43                 sleep(1000);
44             } catch (InterruptedException e) {
45                 e.printStackTrace();
46             }
47             numHolder.increaseNum();
48         }
49     }
50 }
51 
52 class DecreaseThread3 extends Thread{
53     private NumberHolder3 numHolder;
54     public DecreaseThread3(NumberHolder3 numHolder) {
55         this.numHolder = numHolder;
56     }
57     @Override
58     public void run() {
59         for (int i = 0; i < 10; i++) {
60             try {
61                 sleep((long)Math.random()*1000);
62             } catch (InterruptedException e) {
63                 e.printStackTrace();
64             }
65             numHolder.decreaseNum();
66         }
67     }
68 }
69 
70 public class Test9线程间的通信3 {
71 
72     public static void main(String[] args) {
73         NumberHolder3 numHolder = new NumberHolder3();
74         
75         IncreaseThread3 inTh = new IncreaseThread3(numHolder);
76         DecreaseThread3 deTh = new DecreaseThread3(numHolder);
77         inTh.start();
78         deTh.start();
79         
80         IncreaseThread3 inTh3 = new IncreaseThread3(numHolder);
81         DecreaseThread3 deTh3 = new DecreaseThread3(numHolder);
82         inTh3.start();
83         deTh3.start();
84 
85     }
86 
87 }
complete code

 

 

 

 

 

 

 

参考资料:https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#notify()

     http://www.cnblogs.com/mengdd/archive/2013/02/20/2917956.html

原文路径:http://www.cnblogs.com/xiaojia-new/p/8604606.html