您好,登錄后才能下訂單哦!
本篇內容主要講解“怎么理解Java線程間通信與等待/通知機制”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“怎么理解Java線程間通信與等待/通知機制”吧!
在操作系統中,線程是個獨立的個體,但是在線程執行過程中,如果處理同一個業務邏輯,可能會產生資源爭搶,導致并發問題,通常使用互斥鎖來控制該邏輯。但是在還有這樣一類場景,任務執行是有順序控制的。
啟動數據分析任務,生成報表數據;
報表數據存入指定位置數據容器;
通知數據搬運任務,把數據寫入報表庫;
該場景在相對復雜的系統中非常常見,如果基于多線程來描述該過程,則需要線程之間通信協作,才能有條不紊的處理該場景業務。
如上的業務場景,如果線程A生成數據過程中,線程B一直在訪問數據容器,判斷該過程的數據是否已經生成,則會造成資源浪費。正常的流程應該如圖,線程A和線程B同時啟動,線程A開始處理數據生成任務,線程B嘗試獲取容器數據,數據還沒過來,線程B則進入等待狀態,當線程A的任務處理完成,則通知線程B去容器中獲取數據,這樣基于線程等待和通知的機制來協作完成任務。
等待/通知機制的相關方法是Java中Object層級的基礎方法,任何對象都有該方法:
notify:隨機通知一個在該對象上等待的線程,使其結束wait狀態返回;
notifyAll:喚醒在該對象上所有等待的線程,進入對象鎖爭搶隊列中;
wait:線程進入waiting等待狀態,不會爭搶鎖對象,也可以設置等待時間;
線程的等待通知機制,就是基于這幾個基礎方法。
等待/通知機制,該模式下指線程A在不滿足任務執行的情況下調用對象wait()方法進入等待狀態,線程B修改了線程A的執行條件,并調用對象notify()或者notifyAll()方法,線程A收到通知后從wait狀態返回,進而執行后續操作。兩個線程通過基于對象提供的wait()/notify()/notifyAll()等方法完成等待和通知間交互,提高程序的可伸縮性。
通過線程通信解決上述數據生成和存儲任務的解耦流程。
public class NotifyThread01 { static Object lock = new Object() ; static volatile List<String> dataList = new ArrayList<>(); public static void main(String[] args) throws Exception { Thread saveThread = new Thread(new SaveData(),"SaveData"); saveThread.start(); TimeUnit.SECONDS.sleep(3); Thread dataThread = new Thread(new AnalyData(),"AnalyData"); dataThread.start(); } // 等待數據生成,保存 static class SaveData implements Runnable { @Override public void run() { synchronized (lock){ while (dataList.size()==0){ try { System.out.println(Thread.currentThread().getName()+"等待..."); lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("SaveData .."+ dataList.get(0)+dataList.get(1)); } } } // 生成數據,通知保存 static class AnalyData implements Runnable { @Override public void run() { synchronized (lock){ dataList.add("hello,"); dataList.add("java"); lock.notify(); System.out.println("AnalyData End..."); } } } }
注意:除了dataList滿足寫條件,還要在AnalyData線程執行通知操作。
基本概念
管道流主要用于在不同線程間直接傳送數據,一個線程發送數據到輸出管道,另一個線程從輸入管道中讀取數據,進而實現不同線程間的通信。
實現分類
管道字節流:PipedInputStream和PipedOutputStream;
管道字符流:PipedWriter和PipedReader;
新IO管道流:Pipe.SinkChannel和Pipe.SourceChannel;
public class NotifyThread02 { public static void main(String[] args) throws Exception { PipedInputStream pis = new PipedInputStream(); PipedOutputStream pos = new PipedOutputStream(); // 鏈接輸入流和輸出流 pos.connect(pis); // 寫數據線程 new Thread(new Runnable() { public void run() { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 將從鍵盤讀取的數據寫入管道流 PrintStream ps = new PrintStream(pos); while (true) { try { System.out.print(Thread.currentThread().getName()); ps.println(br.readLine()); Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } } } }, "輸入數據線程:").start(); // 讀數據線程 new Thread(new Runnable() { public void run() { BufferedReader br = new BufferedReader(new InputStreamReader(pis)); while (true) { try { System.out.println(Thread.currentThread().getName() + br.readLine()); } catch (IOException e) { e.printStackTrace(); } } } }, "輸出數據線程:").start(); } }
寫線程向管道流寫入數據,讀線程讀取數據,完成基本通信流程。
基于線程等待通知機制:實現工廠生產一件商品,通知商店賣出一件商品的業務流程。
public class NotifyThread03 { public static void main(String[] args) { Product product = new Product(); ProductFactory productFactory = new ProductFactory(product); ProductShop productShop = new ProductShop(product); productFactory.start(); productShop.start(); } } // 產品 class Product { public String name ; public double price ; // 產品是否生產完畢,默認沒有 boolean flag ; } // 產品工廠:生產 class ProductFactory extends Thread { Product product ; public ProductFactory (Product product){ this.product = product; } @Override public void run() { int i = 0 ; while (i < 20) { synchronized (product) { if (!product.flag){ if (i%2 == 0){ product.name = "鼠標"; product.price = 79.99; } else { product.name = "鍵盤"; product.price = 89.99; } System.out.println("產品:"+product.name+"【價格:"+product.price+"】出廠..."); product.flag = true ; i++; // 通知消費者 product.notifyAll(); } else { try { // 進入等待狀態 product.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } } // 產品商店:銷售 class ProductShop extends Thread { Product product ; public ProductShop (Product product){ this.product = product ; } @Override public void run() { while (true) { synchronized (product) { if (product.flag == true ){ System.out.println("產品:"+product.name+"【價格"+(product.price*2)+"】賣出..."); product.flag = false ; product.notifyAll(); //喚醒生產者 } else { try { product.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } }
流程描述:ProductFactory生成一件商品,通知商店售賣,通過flag標識判斷控制是否進入等待狀態,商店賣出商品后,再次通知工廠生產商品。
到此,相信大家對“怎么理解Java線程間通信與等待/通知機制”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。