1. 程式人生 > 實用技巧 >Java多執行緒詳解(五)------多執行緒間的通訊

Java多執行緒詳解(五)------多執行緒間的通訊

1、常規版的生產者與消費者(synchronized,wait,notify)

  1 package com.study.thread;
  2 
  3 public class TestThread919 {
  4     public static void main(String[] args) {
  5         AirConditioner ac = new AirConditioner();
  6         //A,B執行緒增加空調溫度
  7         new Thread(() -> {
  8             for (int i = 0; i < 10; i++) {
9 try { 10 ac.increament(); 11 } catch (Exception e) { 12 e.printStackTrace(); 13 } 14 } 15 }, "A").start(); 16 new Thread(() -> { 17 for (int i = 0; i < 10; i++) {
18 try { 19 ac.increament(); 20 } catch (Exception e) { 21 e.printStackTrace(); 22 } 23 } 24 }, "B").start(); 25 26 //C,D執行緒減小溫度 27 new Thread(() -> { 28 for
(int i = 0; i < 10; i++) { 29 try { 30 ac.decreament(); 31 } catch (Exception e) { 32 e.printStackTrace(); 33 } 34 } 35 }, "C").start(); 36 new Thread(() -> { 37 for (int i = 0; i < 10; i++) { 38 try { 39 ac.decreament(); 40 } catch (Exception e) { 41 e.printStackTrace(); 42 } 43 } 44 }, "D").start(); 45 46 47 } 48 } 49 50 class AirConditioner {//資源類 51 private int num = 0;//num表示溫度大小 52 53 //多執行緒之間的相互通知,口訣:判斷-》幹活-》通知 54 public synchronized void increament() throws Exception {//增加一度 55 while (num != 0) {//這裡判斷不用if,用while,while可以防止虛假喚醒 56 this.wait(); 57 } 58 num++; 59 System.out.println(Thread.currentThread().getName() + "\t" + num); 60 this.notifyAll(); 61 } 62 63 public synchronized void decreament() throws Exception {//減小一度 64 while (num == 0) { 65 this.wait(); 66 } 67 num--; 68 System.out.println(Thread.currentThread().getName() + "\t" + num); 69 this.notifyAll(); 70 } 71 } 72 73 輸出列印: 74 "C:\Program Files\Java\jdk1.8.0_131\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.4\lib\idea_rt.jar=56512:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_131\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar;D:\java-project\suanfa\out\production\juc" com.study.thread.TestThread919 75 A 1 76 C 0 77 B 1 78 C 0 79 A 1 80 C 0 81 B 1 82 C 0 83 A 1 84 C 0 85 B 1 86 C 0 87 A 1 88 C 0 89 B 1 90 D 0 91 A 1 92 C 0 93 B 1 94 D 0 95 A 1 96 C 0 97 B 1 98 D 0 99 A 1 100 C 0 101 B 1 102 D 0 103 A 1 104 D 0 105 B 1 106 D 0 107 A 1 108 D 0 109 B 1 110 D 0 111 A 1 112 D 0 113 B 1 114 D 0

2、新版的生產者與消費者(Lock,Condition,await,signal)

  1 package com.study.thread;
  2 
  3 import java.util.concurrent.locks.Condition;
  4 import java.util.concurrent.locks.Lock;
  5 import java.util.concurrent.locks.ReentrantLock;
  6 
  7 public class TestThread919 {
  8     public static void main(String[] args) {
  9         AirConditioner ac = new AirConditioner();
 10         //A,B執行緒增加空調溫度
 11         new Thread(() -> {
 12             for (int i = 0; i < 10; i++) {
 13                 try {
 14                     ac.increament();
 15                 } catch (Exception e) {
 16                     e.printStackTrace();
 17                 }
 18             }
 19         }, "A").start();
 20         new Thread(() -> {
 21             for (int i = 0; i < 10; i++) {
 22                 try {
 23                     ac.increament();
 24                 } catch (Exception e) {
 25                     e.printStackTrace();
 26                 }
 27             }
 28         }, "B").start();
 29 
 30         //C,D執行緒減小溫度
 31         new Thread(() -> {
 32             for (int i = 0; i < 5; i++) {
 33                 try {
 34                     ac.decreament();
 35                 } catch (Exception e) {
 36                     e.printStackTrace();
 37                 }
 38             }
 39         }, "C").start();
 40         new Thread(() -> {
 41             for (int i = 0; i < 5; i++) {
 42                 try {
 43                     ac.decreament();
 44                 } catch (Exception e) {
 45                     e.printStackTrace();
 46                 }
 47             }
 48         }, "D").start();
 49 
 50 
 51     }
 52 }
 53 
 54 class AirConditioner {//資源類
 55     private int num = 0;//num表示溫度大小
 56     private Lock l = new ReentrantLock();
 57     private Condition condition = l.newCondition();
 58 
 59     //多執行緒之間的相互通知,口訣:判斷-》幹活-》通知
 60 //    public synchronized void increament() throws Exception {//增加一度
 61 //        while (num != 0) {//這裡判斷不用if,用while,while可以防止虛假喚醒
 62 //            this.wait();
 63 //        }
 64 //        num++;
 65 //        System.out.println(Thread.currentThread().getName() + "\t" + num);
 66 //        this.notifyAll();
 67 //    }
 68 //
 69 //    public synchronized void decreament() throws Exception {//減小一度
 70 //        while (num == 0) {
 71 //            this.wait();
 72 //        }
 73 //        num--;
 74 //        System.out.println(Thread.currentThread().getName() + "\t" + num);
 75 //        this.notifyAll();
 76 //    }
 77     public void increament() throws Exception {//增加一度
 78         l.lock();
 79         try {
 80             while (num != 0) {//這裡判斷不用if,用while,while可以防止虛假喚醒
 81                 condition.await();
 82             }
 83             num++;
 84             System.out.println(Thread.currentThread().getName() + "\t" + num);
 85             condition.signalAll();
 86         } finally {
 87             l.unlock();
 88         }
 89     }
 90 
 91     public void decreament() throws Exception {//增加一度
 92         l.lock();
 93         try {
 94             while (num == 0) {//這裡判斷不用if,用while,while可以防止虛假喚醒
 95                 condition.await();
 96             }
 97             num--;
 98             System.out.println(Thread.currentThread().getName() + "\t" + num);
 99             condition.signalAll();
100         } finally {
101             l.unlock();
102         }
103     }
104 }
105 
106 列印輸出:
107 "C:\Program Files\Java\jdk1.8.0_131\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.4\lib\idea_rt.jar=57081:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_131\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar;D:\java-project\suanfa\out\production\juc" com.study.thread.TestThread919
108 A    1
109 C    0
110 A    1
111 C    0
112 A    1
113 C    0
114 A    1
115 C    0
116 A    1
117 D    0
118 A    1
119 D    0
120 A    1
121 D    0
122 A    1
123 D    0
124 A    1
125 D    0
126 A    1
127 C    0
128 B    1

3、新版的生產者與消費者(Lock,Condition,await,signal) 的精準通知(較普通版的優勢)

  例子:有A,B,C三個執行緒,要求A列印5次,B列印10次,C列印15次,迴圈10次

  1 package com.study.thread;
  2 
  3 import java.util.concurrent.locks.Condition;
  4 import java.util.concurrent.locks.Lock;
  5 import java.util.concurrent.locks.ReentrantLock;
  6 
  7 public class ThreadOfCondition {
  8     public static void main(String[] args) {
  9         PrintSourse printSourse = new PrintSourse();
 10         new Thread(() -> {
 11             for (int i = 0; i < 5; i++) {
 12                 printSourse.print5();
 13             }
 14         }, "A").start();
 15         new Thread(() -> {
 16             for (int i = 0; i < 5; i++) {
 17                 printSourse.print10();
 18             }
 19         }, "B").start();
 20         new Thread(() -> {
 21             for (int i = 0; i < 5; i++) {
 22                 printSourse.print15();
 23             }
 24         }, "C").start();
 25     }
 26 }
 27 
 28 class PrintSourse {
 29     //condition實現精準通知執行緒,
 30 
 31     private int num = 1;//標誌位,為不同的執行緒設定不同的標誌位,喚醒通知的時候用
 32     private Lock lock = new ReentrantLock();
 33     private Condition condition1 = lock.newCondition();
 34     private Condition condition2 = lock.newCondition();
 35     private Condition condition3 = lock.newCondition();
 36 
 37     //建立3個方法,分別列印5次,10,15次
 38     public void print5() {
 39         lock.lock();
 40         try {
 41             //判斷
 42             while (num != 1) {
 43                 condition1.await();
 44             }
 45             //幹活
 46             for (int i = 1; i <= 5; i++) {
 47                 System.out.println(Thread.currentThread().getName() + "\t" + i);
 48             }
 49             //通知
 50             num = 2;//修改標誌位
 51             condition2.signal();//通知第二把鑰匙condition2
 52 
 53         } catch (Exception e) {
 54             e.printStackTrace();
 55         } finally {
 56             lock.unlock();
 57         }
 58     }
 59 
 60     public void print10() {
 61         lock.lock();
 62         try {
 63             //判斷
 64             while (num != 2) {
 65                 condition2.await();
 66             }
 67             //幹活
 68             for (int i = 1; i <= 10; i++) {
 69                 System.out.println(Thread.currentThread().getName() + "\t" + i);
 70             }
 71             //通知
 72             num = 3;//修改標誌位
 73             condition3.signal();//通知第三把鑰匙condition3
 74 
 75         } catch (Exception e) {
 76             e.printStackTrace();
 77         } finally {
 78             lock.unlock();
 79         }
 80     }
 81 
 82     public void print15() {
 83         lock.lock();
 84         try {
 85             //判斷
 86             while (num != 3) {
 87                 condition3.await();
 88             }
 89             //幹活
 90             for (int i = 1; i <= 15; i++) {
 91                 System.out.println(Thread.currentThread().getName() + "\t" + i);
 92             }
 93             //通知
 94             num = 1;//修改標誌位
 95             condition1.signal();//通知第一把鑰匙condition1
 96         } catch (Exception e) {
 97             e.printStackTrace();
 98         } finally {
 99             lock.unlock();
100         }
101     }
102 
103 }
104 
105 結果列印:
106 A    1
107 A    2
108 A    3
109 A    4
110 A    5
111 B    1
112 B    2
113 B    3
114 B    4
115 B    5
116 B    6
117 B    7
118 B    8
119 B    9
120 B    10
121 C    1
122 C    2
123 C    3
124 C    4
125 C    5
126 C    6
127 C    7
128 C    8
129 C    9
130 C    10
131 C    11
132 C    12
133 C    13
134 C    14
135 C    15