日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【JUC并发编程03】线程间通信

發布時間:2025/3/20 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【JUC并发编程03】线程间通信 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 3 線程間通信
      • 3.1 synchronized 實現案例
      • 3.2 虛假喚醒問題
      • 3.3 Lock 實現案例

3 線程間通信

線程間通信有兩種實現方法:

關鍵字 synchronized 與 wait()/notify() 這兩個方法一起使用可以實現等待/通知模式

Lock 接口中的 newContition() 方法返回 Condition 對象,Condition 類也可以實現等待/通知模式

用 notify()通知時,JVM 會隨機喚醒某個等待的線程

使用 Condition 類可以進行選擇性通知, Condition 比較常用的兩個方法:

1. await() 會使當前線程等待,同時會釋放鎖,當其他線程調用 signal()時,線程會重新獲得鎖并繼續執行2. signal() 用于喚醒一個等待的線程

操作線程的時候,等待線程使用wait()
通知另外的線程操作用notify()、notifyAll()
假設有兩個線程,該線程在執行過程中,判斷值(不是該值等待,讓其他線程搶),操作值,通知另外一個線程的調度

3.1 synchronized 實現案例

實現兩個線程對 num 這個值操作,一個線程加1,一個線程減1,交替實現多次

// 創建一個資源類 class Share{// 設置臨界資源private int number = 0;// 實現+1操作public synchronized void incr() throws InterruptedException {// 操作:判斷、干活、通知if (number != 0) {// number不為0,等待// wait 有一個特點,在哪里睡,就在哪里醒this.wait(); }number++;System.out.print(Thread.currentThread().getName()+"::"+number);// 喚醒其他線程// 注意這里的通知是隨機的,就是只能通知全部this.notifyAll();}// 實現-1操作public synchronized void decr() throws InterruptedException {// 操作:判斷、干活、通知if (number != 1) {// number不為0,等待this.wait();}number--;System.out.println(Thread.currentThread().getName()+"::"+number);this.notifyAll();} } public class InterThreadCommunication {public static void main(String[] args) {Share share = new Share();new Thread(new Runnable() {@Overridepublic void run() {try {for (int i = 0; i < 100; i++) {share.incr();}} catch (InterruptedException e) {e.printStackTrace();}}},"A").start();new Thread(new Runnable() {@Overridepublic void run() {try {for (int i = 0; i < 100; i++) {share.decr();}} catch (InterruptedException e) {e.printStackTrace();}}},"B").start();} }

輸出結果如下

3.2 虛假喚醒問題

虛假喚醒主要出現在多線程中出現。

同樣使用上述案例,現在有四個線程,分別為A,B,C,D,其中A,C線程做+1操作,B,D線程做-1操作,想要的結尾應該是A,C線程輸出值為1,B,D線程輸出值為0 。修改上述代碼如下:

// 創建一個資源類 class Share{// 設置臨界資源private int number = 0;// 實現+1操作public synchronized void incr() throws InterruptedException {// 操作:判斷、干活、通知if (number != 0) {// number不為0,等待this.wait();}number++;System.out.print(Thread.currentThread().getName()+"::"+number+"--->");// 喚醒其他線程this.notifyAll();}// 實現-1操作public synchronized void decr() throws InterruptedException {// 操作:判斷、干活、通知if (number != 1) {// number不為0,等待this.wait();}number--;System.out.println(Thread.currentThread().getName()+"::"+number);this.notifyAll();} } public class InterThreadCommunication {public static void main(String[] args) {Share share = new Share();new Thread(new Runnable() {@Overridepublic void run() {try {for (int i = 0; i < 100; i++) {share.incr();}} catch (InterruptedException e) {e.printStackTrace();}}},"A").start();new Thread(new Runnable() {@Overridepublic void run() {try {for (int i = 0; i < 100; i++) {share.decr();}} catch (InterruptedException e) {e.printStackTrace();}}},"B").start();new Thread(new Runnable() {@Overridepublic void run() {try {for (int i = 0; i < 100; i++) {share.incr();}} catch (InterruptedException e) {e.printStackTrace();}}},"C").start();new Thread(new Runnable() {@Overridepublic void run() {try {for (int i = 0; i < 100; i++) {share.decr();}} catch (InterruptedException e) {e.printStackTrace();}}},"D").start();} }

輸出結尾如下,顯然最后輸出的結果和我們預想的是不一樣的。那么問題出在哪里呢?

查找 JDK1.8 文檔,在 Object 的 wait() 方法中有如下介紹

在一個參數版本中,中斷和虛假喚醒是可能的,并且該方法應該始終在循環中使用

也就是說,這種現象叫做【虛假喚醒】。所謂虛假喚醒,就是 wait()方法的一個特點,總結來說 wait() 方法使線程在哪里睡就在哪里醒。 這是什么意思呢?那就以上述代碼為例。

當 A 進入臨界區,BCD三個線程在 if 判斷后進入 wait() 等待,當A線程完成操作,此時 number 值為1,notifyAll() 會隨機喚醒一個線程。

現在C被喚醒,由于 wait() 方法使線程在哪里睡就在哪里醒,所以接下來C在執行時不會再通過 if 判斷而是直接+1,此時 number 就是2了。從而導致最后輸出的結果和我們預想的不一致。

按照 JDK1.8 文檔的提示,將資源類的 incr() 方法和 decr() 方法中的if語句改為循環語句,修改代碼如下:

// 創建一個資源類 class Share{// 設置臨界資源private int number = 0;// 實現+1操作public synchronized void incr() throws InterruptedException {// 操作:判斷、干活、通知while (number != 0) {// number不為0,等待// 哪里睡哪里起this.wait();}number++;System.out.print(Thread.currentThread().getName()+"::"+number+"--->");// 喚醒其他線程this.notifyAll();}// 實現-1操作public synchronized void decr() throws InterruptedException {// 操作:判斷、干活、通知while (number != 1) {// number不為0,等待this.wait();}number--;System.out.println(Thread.currentThread().getName()+"::"+number);this.notifyAll();} }

此時輸出結果符合我們預期:

3.3 Lock 實現案例

在 Lock 接口中,有一個 newCondition() 方法,該方法返回一個新 Condition 綁定到該實例 Lock 實例。

Condition 類中有 await() 和 signalAll() 等方法,和 synchronized 實現案例中的 wait() 和 notifyAll() 方法相同。所以通過 Lock 接口創建一個 Condition 對象,由該對象的方法進行等待和喚醒操作

實例代碼如下,主要改動的是資源類,main方法中代碼不變。

class Share {// 設置臨界資源private int number = 0;// 創建一個Comprivate Lock lock = new ReentrantLock();private Condition condition = lock.newCondition();// 實現+1操作public void incr() {// 上鎖lock.lock();try {// 判斷while (number != 0) {condition.await();}// 干活number++;System.out.print(Thread.currentThread().getName() + "::" + number + "--->");// 通知condition.signalAll();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}// 實現-1操作public void decr() throws InterruptedException {// 上鎖lock.lock();try {// 判斷while (number != 1) {condition.await();}// 干活number--;System.out.println(Thread.currentThread().getName() + "::" + number);// 通知condition.signalAll();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}} }

測試結尾如下:

總結

以上是生活随笔為你收集整理的【JUC并发编程03】线程间通信的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。