等待喚醒機制---Day25

来源:https://www.cnblogs.com/hpcz190911/archive/2019/11/29/11955116.html
-Advertisement-
Play Games

線程間通信 概念:多個線程在處理同一個資源,但是處理的動作(線程的任務)卻不相同。 比如:線程A用來生成包子的,線程B用來吃包子的,包子可以理解為同一資源,線程A與線程B處理的動作,一個 是生產,一個是消費,那麼線程A與線程B之間就存線上程通信問題。 為什麼要處理線程間通信: 多個線程併發執行時, ...


線程間通信

  概念:多個線程在處理同一個資源,但是處理的動作(線程的任務)卻不相同。

  比如:線程A用來生成包子的,線程B用來吃包子的,包子可以理解為同一資源,線程A與線程B處理的動作,一個 是生產,一個是消費,那麼線程A與線程B之間就存線上程通信問題。

  為什麼要處理線程間通信:

    多個線程併發執行時, 在預設情況下CPU是隨機切換線程的,當我們需要多個線程來共同完成一項任務時,我們都知道執行任務時一般都是按規律或者規則來執行,所以多線程執行任務也是一樣,需要規律來協調通信,以此來幫我們達到多線程共同操作一項任務(一份數據)。

  如何保證線程間通信有效執行任務(利用資源):

    多個線程在處理同一個資源,並且任務不同時,需要線程通信來幫助解決線程之間對同一個變數的使用或操作。 因為多個線程在操作同一份數據時, 要避免對同一共用變數的爭奪。因此我們需要通過一定的手段使各個線程能有效的利用資源。而這種手段即—— 等待喚醒機制

等待喚醒機制

  什麼時等待喚醒機制

    這是多個線程間的一種協作機制。談到線程我們經常想到的是線程間的競爭(race),比如去爭奪鎖,但這並不是故事的全部,線程間也會有協作機制,就是在一個線程進行了規定操作後,就進入等待狀態(wait()), 等待其他線程執行完他們的指定代碼過後再將其喚醒(notify());在有多個線程進行等待時, 如果需要,可以使用 notifyAll()來喚醒所有的等待線程

    wait/notify 就是線程間的一種協作機制

等待喚醒中的方法

  等待喚醒機制就是用於解決線程間通信的問題的,使用到的3個方法的含義如下

    1. wait:線程不再活動,不再參與調度,進入 wait set 中,因此不會浪費 CPU 資源,也不會去競爭鎖了,這時的線程狀態即是WAITING。它還要等著別的線程執行一個特別的動作,也即是“通知(notify)”在這個對象上等待的線程從wait set 中釋放出來,重新進入到調度隊列(ready queue)中

    2. notify:則選取所通知對象的 wait set 中的一個線程釋放;例如,餐館有空位置後,等候就餐最久的顧客最先入座。

    3. notifyAll:則釋放所通知對象的 wait set 上的全部線程。

    註意:哪怕只通知了一個等待的線程,被通知線程也不能立即恢復執行,因為它當初中斷的地方是在同步塊內,而此刻它已經不再持有鎖,所以需要再次嘗試去獲取鎖(很可能面臨其它線程的競爭),獲取鎖成功後才能在當初調用 wait 方法之後的地方恢復執行

  總結:如果能獲取鎖,線程就從 WAITING 狀態變成 RUNNABLE 狀態; 否則,從 wait set 出來,又進入 entry set,線程就從 WAITING 狀態又變成 BLOCKED 狀態 

調用wait和notify方法需要註意的細節

  1. wait方法與notify方法必須要由同一個鎖對象調用。因為:對應的鎖對象可以通過notify喚醒使用同一個鎖對 象調用的wait方法後的線程。

  2. wait方法與notify方法是屬於Object類的方法的。因為:鎖對象可以是任意對象,而任意對象的所屬類都是繼 承了Object類的。

  3. wait方法與notify方法必須要在同步代碼塊或者是同步函數中使用。因為:必須要通過鎖對象調用這2個方法。

等待喚醒機制是“生產者與消費者之間的關係”

  就拿生產包子消費包子來說等待喚醒機制如何有效利用資源:

    包子鋪線程生產包子,吃貨線程消費包子。當包子沒有時(包子狀態為false),吃貨線程等待,包子鋪線程生產包子 (即包子狀態為true),並通知吃貨線程(解除吃貨的等待狀態),因為已經有包子了,那麼包子鋪線程進入等待狀態。 接下來,吃貨線程能否進一步執行則取決於鎖的獲取情況。如果吃貨獲取到鎖,那麼就執行吃包子動作,包子吃完(包 子狀態為false),並通知包子鋪線程(解除包子鋪的等待狀態),吃貨線程進入等待。包子鋪線程能否進一步執行則取決於鎖的獲取情況

包子類

 1 package demosummary.waitingandwake;
 2 
 3 /**
 4     包子鋪線程生產包子,吃貨線程消費包子。當包子沒有時(包子狀態為false),吃貨線程等待,
 5     包子鋪線程生產包子 (即包子狀態為true)
 6     並通知吃貨線程(解除吃貨的等待狀態),因為已經有包子了,那麼包子鋪線程進入等待狀態。
 7     接下來,吃貨線程能否進一步執行則取決於鎖的獲取情況。
 8     如果吃貨獲取到鎖,那麼就執行吃包子動作,包子吃完(包 子狀態為false),並通知包子鋪線程(解除包子鋪的等待狀態),
 9     吃貨線程進入等待。包子鋪線程能否進一步執行則取決於鎖的獲取情況
10  */
11 public class BaoZi {
12     private String pi;
13     private String xian;
14     boolean flag = false;
15 
16     public BaoZi() {
17     }
18 
19     public BaoZi(String pi, String xian, boolean flag) {
20         this.pi = pi;
21         this.xian = xian;
22         this.flag = flag;
23     }
24 
25     public String getPi() {
26         return pi;
27     }
28 
29     public void setPi(String pi) {
30         this.pi = pi;
31     }
32 
33     public String getXian() {
34         return xian;
35     }
36 
37     public void setXian(String xian) {
38         this.xian = xian;
39     }
40 
41     public boolean isFlag() {
42         return flag;
43     }
44 
45     public void setFlag(boolean flag) {
46         this.flag = flag;
47     }
48 
49     @Override
50     public String toString() {
51         return "BaoZi{" +
52                 "pi='" + pi + '\'' +
53                 ", xian='" + xian + '\'' +
54                 ", flag=" + flag +
55                 '}';
56     }
57 }

包子鋪類

 1 package demosummary.waitingandwake;
 2 
 3 public class BaoZiPu extends Thread{
 4     private BaoZi bz;
 5 
 6     public BaoZiPu(String name, BaoZi bz) {
 7         super(name);
 8         this.bz = bz;
 9     }
10 
11     @Override
12     public void run() {
13         //定義一個變數來判斷做什麼皮和餡的包子
14         int count = 0;
15         while (true) {
16             synchronized (bz) {
17                 if (bz.flag == true) {//包子存在
18                     try {
19                         bz.wait();//進入等待狀態,既不需要做包子
20                     } catch (InterruptedException e) {
21                         e.printStackTrace();
22                     }
23                 }
24                 //沒有包子,包子鋪開始做包子
25                 System.out.println("包子鋪開始做包子");
26                 //判斷做什麼包子
27                 if (count != 0) {
28                     //做冰皮蛋黃包子
29                     bz.setPi("冰皮");
30                     bz.setXian("蛋黃");
31                 } else {
32                     //做薄皮豆沙餡
33                     bz.setPi("薄皮");
34                     bz.setXian("豆沙");
35                 }
36                 count++;
37                 //改變包子的狀態為有包子
38                 bz.flag = true;
39                 System.out.println("包子做好了:"+bz.getPi()+bz.getXian()+"包子");
40                 System.out.println("請等待的顧客可以來拿包子了");
41                 bz.notify();
42             }
43         }
44     }
45 }

顧客類

 1 package demosummary.waitingandwake;
 2 
 3 public class GuKe extends Thread{
 4     private BaoZi bz;
 5 
 6     public GuKe(String name, BaoZi bz) {
 7         super(name);
 8         this.bz = bz;
 9     }
10 
11     @Override
12     public void run() {
13         while (true) {
14             synchronized (bz) {
15                 if (bz.flag == false) {
16                     try {
17                         bz.wait();
18                     } catch (InterruptedException e) {
19                         e.printStackTrace();
20                     }
21                 }
22 
23                 System.out.println("顧客已拿到" + bz.getPi() + bz.getXian()+"包子");
24                 bz.flag = false;
25                 bz.notify();
26             }
27         }
28     }
29 }

測試類

 1 package demosummary.waitingandwake;
 2 
 3 public class Test {
 4     public static void main(String[] args) {
 5         //創建包子、包子鋪、顧客對象
 6         BaoZi baoZi = new BaoZi();
 7         BaoZiPu baoZiPu = new BaoZiPu("包子鋪", baoZi);
 8         GuKe guKe = new GuKe("顧客", baoZi);
 9         //調用包子鋪和顧客線程
10         baoZiPu.start();
11         guKe.start();
12     }
13 }

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 基於博主也是個菜鳥,親身體驗後步驟如下: 首先,我們需要安裝node.js, https://www.runoob.com/nodejs/nodejs-install-setup.html 安裝完成後,打開命定行直接輸入node -v 就可以查看到當前安裝的node 版本了 接下來我們需要下載exp ...
  • 引入: //計算兩個數字的和 function f1(x, y) { return x + y; } //計算三個數字的和 function f2(x, y, z) { return x + y + z; } //計算四個數字的和 function f3(x, y, z, k) { return x ...
  • 前言 本篇文章預設您大概瞭解什麼是TypeScript,主要講解如何在React舊項目中安裝並使用TypeScript。 寫這個的目的主要是網上關於TypeScript這塊的講解雖然很多,但都是一些語法概念或者簡單例子,真正改造一個React舊項目使用TypeScript的文章很少。 所以在這裡記錄 ...
  • 單例模式是老生常談的一種設計模式,同時它是最簡單也是最容易被忽視的一種設計模式。單例類應該是密封類,不能被繼承,同時建議在任何情況下都要保證線程安全。 ...
  • 5. 分散式事務解決方案之可靠消息最終一致性 5.1. 什麼是可靠消息最終一致性事務 可靠消息最終一致性方案是指當事務發起執行完全本地事務後併發出一條消息,事務參與方(消息消費者)一定能夠接收消息並處理事務成功,此方案強調的是只要消息發給事務參與方最終事務要達到一致。此方案是利用消息中間件完成,如下 ...
  • 從程式員到架構師的進階過程,就像是用時間精力澆灌培植一棵樹,讓小樹苗逐漸長成參天大樹,先有主幹,後有枝葉,待到枝繁葉茂就能開花結果了,也就是說等到架構師所需技能全都儲備好了,那我們就有信心勝任新崗位工作了。 ...
  • 本文主要學習如何在Windows環境中下載並安裝Tomcat伺服器。 ...
  • 由於這個是畢業設計的內容,而且還是跨專業的。爬蟲程式肯定是很簡單的,就是調用Yahoo的API進行爬取圖片。這篇博客主要講的是基礎的界面設計。 放上源碼,然後分部解析一下重要的地方。註:flickrapi需要翻牆 代碼複製的時候可能掉幾個字母或者符號,不建議複製代碼,如需複製請自行檢查是否有拼寫錯誤 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...