1. 程式人生 > >Java線程通信-生產者消費者問題

Java線程通信-生產者消費者問題

rgs 經典的 java線程 link notifyall 對象 sync 優先級 product

線程通信示例——生產者消費者問題

這類問題描述了一種情況,假設倉庫中只能存放一件產品,生產者將生產出來的產品放入倉庫,消費者將倉庫中的產品取走消費.假設倉庫中沒有產品,則生產者可以將 產品放入倉庫,有產品,則停止生產並等待,直到倉庫中的產品被消費這取走為止. 如果倉庫中放油產品,則消費者可以將產品取走消費,否則停止消費並等待,直到 倉庫中再次放入產品為止. 顯然,這是一個同步問題,生產者和消費這共享同一資源, 並且生產者和消費這之間彼此依賴,互為條件向前推進.Java提供了3個方法解決了線程間的通信問題,分別是wait() notify() 和 notifyAll()
* (1)調用wait()方法: 使調用該方法的線程釋放共享資源的鎖,然後從運行狀態退出, 進入等待隊列,直到被再次喚醒


* (2)調用notify()方法: 喚醒等待隊列中第一個等待同一共享資源的線程,並使該線程退出等待,進入就緒狀態
* (3)調用notifyAll()方法: 使所有正在等待隊列中同一共享資源的線程從等待狀態退出,此時優先級最高的那個線程最先執行

  1 package com.iotek.productconsumerdemo;
  2 
  3 import java.util.LinkedList;
  4 
  5 public class ProductorConsumerDemo {
  6 
  7     /**
  8      * 線程通信-wait() notify() notifyAll() 
9 * 在現實應用中,很多時候需要讓那個多個線程按照i定的次序來訪問共享資源,例如經典的生產者消費者問題: 10 * 這類問題描述了這樣一種情況,假設倉庫中只能存放一件產品,生產者將生產出來的產品放入倉庫,消費者 11 * 將倉庫中的產品取走消費,如果倉庫中沒有產品,在生產者可以將產品放入倉庫,否則停止生產並等待,直到 12 * 倉庫中的產品被消費這取完為止,如果倉庫中放有產品,則消費者可以將產品取走消費,否則停止消費並等待, 13 * 直到倉庫中再次放入產品為止 14 * @param args 15 *
16 */ 17 public static void main(String[] args) { 18 Basket basket = new Basket(); 19 Productor productor = new Productor(basket);//創建生產者對象 20 Consumer consumer = new Consumer(basket);//創建消費者對象 21 productor.start(); //生產者啟動生產 22 consumer.start(); //消費者開始消費 23 } 24 25 } 26 27 class Consumer extends Thread { 28 private Basket basket = null; 29 30 public Consumer(Basket basket) { 31 this.basket = basket; 32 } 33 @Override 34 public void run() { 35 basket.popApple(); //消費者從籃子裏取蘋果 36 } 37 } 38 39 class Productor extends Thread { 40 private Basket basket = null; 41 42 public Productor(Basket basket) { 43 this.basket = basket; 44 } 45 46 @Override 47 public void run() { 48 basket.pushApple(); // 生產者向籃子裏放蘋果 49 } 50 } 51 52 // 籃子類,用來存放蘋果(需要一個容器來存放,頻繁存取,用LinkedList),或者取蘋果 53 class Basket { 54 private LinkedList<Apple> basket = new LinkedList<Apple>(); 55 56 // 放四輪蘋果 57 public synchronized void pushApple() { 58 // synchronized 加鎖,放蘋果的時候不能取蘋果 59 for (int i = 0; i < 20; i++) { 60 Apple apple = new Apple(i); 61 push(apple); 62 } 63 } 64 65 // 取4輪蘋果 66 public synchronized void popApple() { 67 for (int i = 0; i < 20; i++) { 68 pop(); 69 } 70 } 71 72 // 向籃子裏面放蘋果 這個方法不對外使用,因此設置為private私有的 73 /* public */private void push(Apple apple) { 74 // 如果籃子裏已經有5個蘋果了,就等待並通知消費者來消費 75 if (basket.size() == 5) { 76 try { 77 wait();// 等待,並釋放當前對象的鎖 78 /* 註意!!!調用wait()方法進入等待的線程,必須要通過其他線程調用notify()或notifyAll()方法來喚醒 */ 79 } catch (InterruptedException e) { 80 e.printStackTrace(); 81 } 82 } 83 // 如果沒滿5個蘋果,那麽就繼續放蘋果 84 try { 85 Thread.sleep(500);// 每隔500ms放一個蘋果 86 // sleep()使當前線程每隔設定的休眠時間後,就自動啟動線程 87 } catch (InterruptedException e) { 88 e.printStackTrace(); 89 } 90 basket.addFirst(apple);// 存放蘋果 91 System.out.println("存放:" + apple.toString()); 92 notify();// 通知消費者來消費 93 } 94 95 // 從籃子中取蘋果 96 /* public */private void pop() { 97 // 當籃子中蘋果數為0 的時候就等待並通知生產者來生產 98 if (basket.size() == 0) { 99 try { 100 wait(); 101 } catch (InterruptedException e) { 102 e.printStackTrace(); 103 } 104 } 105 // 如果籃子中蘋果不為0,那麽就消費,每隔一定間隔,消費一個蘋果 106 try { 107 Thread.sleep(500); 108 } catch (InterruptedException e) { 109 e.printStackTrace(); 110 } 111 Apple apple = basket.removeFirst();// 取出一個蘋果 112 System.out.println("吃掉:" + apple.toString()); 113 notify(); // 通知生產者來生產 114 115 } 116 } 117 118 // 蘋果類 119 class Apple { 120 private int id; 121 122 public Apple(int id) { 123 this.id = id; 124 } 125 126 @Override 127 public String toString() { 128 return "蘋果:" + (id + 1); 129 } 130 }

Java線程通信-生產者消費者問題