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

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

同步方法 obj 包含 not tac 問題: err 為我 方法

一、問題引入:首先實現一個線程通信的實例,使用兩個線程交替打印輸出100以內的數字。

代碼實現如下:

 1 package com.baozi.exer;
 2 
 3 public class CommunicationTest {
 4     public static void main(String[] args) {
 5         Number number = new Number();
 6         Thread t1 = new Thread(number);
 7         Thread t2 = new Thread(number);
8 t1.setName("線程1"); 9 t2.setName("線程2"); 10 t1.start(); 11 t2.start(); 12 } 13 14 } 15 16 class Number implements Runnable { 17 private int number = 1; 18 19 @Override 20 public void run() { 21 while (true) { 22 synchronized
(this) { 23 notify(); 24 if (number <= 100) { 25 try { 26 Thread.sleep(100); 27 } catch (InterruptedException e) { 28 e.printStackTrace(); 29 } 30 System.out.println(Thread.currentThread().getName() + ":" + number);
31 number++; 32 try { 33 wait(); 34 } catch (InterruptedException e) { 35 e.printStackTrace(); 36 } 37 } else { 38 break; 39 } 40 } 41 } 42 } 43 }

wait()、notify()、notifyAll()三個方法的介紹:

  • wait():某個對象調用wait()方法能讓當前線程阻塞,並且當前線程還會釋放所擁有的鎖
  • 調用某個對象的notify()方法能夠喚醒一個正在等待這個對象的monitor的線程,如果有多個線程都在等待這個對象的monitor,則只能喚醒其中一個線程;
  • 調用notifyAll()方法能夠喚醒所有正在等待這個對象的monitor的線程;

備註:wait()、notify()、notifyAll()三個方法都是定義在同步代碼塊或者是同步方法中的,並且都是同步代碼塊或者同步方法的同步監視器進行調用這些方法。

二、為什麽這三個方法都是定義在Object類中,而不是定義在Thread類中?

  這三個方法都是定義在Object類中,因為我們知道,這三個方法都是存在於同步代碼塊或者同步方法中的,而且必須是該代碼塊的同步監視器進行調用這些方法,那麽因為同步監視器是任何一個類的對象都可以充當,如果要保證任何一個類的對象都有這三個方法並且能進行調用,就只能把這三個方法方法所有類的父類--Object類中。

三、Sleep()方法和Wait()方法有什麽異同?

相同點:一旦執行這兩個方法,都會使當前線程進入阻塞狀態

不同點:

  • 兩個方法聲明的位置不同:sleep()方法是在Thread類中聲明為一個靜態方法,而wait()方法是定義在Object類中
  • 兩個方法的使用位置不同:sleep可以在任何位置使用,但是wait()方法只能在同步代碼塊或者是同步方法中使用
  • sleep()方法執行完之後雖然會使當前線程進入阻塞狀態,但是並不會使當前線程釋放所擁有的鎖,但是wait()方法不但會讓當前的線程進入阻塞狀態,還會是當前的線程釋放擁有的鎖。

四、經典的線程通信問題:生產者和消費者問題

  1 package com.baozi.java2;
  2 
  3 /**
  4  * 線程通信的應用:生產者消費者問題
  5  * 分析:
  6  * 1、是否是多線程的問題:是多線程問題,至少要包含生產者線程和消費者線程
  7  * 2、是否有共享數據的問題?有共享數據:產品(這裏只用了一個產品的個數進行表示)
  8  * 3、如何解決線程的安全問題:使用同步機制
  9  * 4、如何解決線程之間的通信問題?wait()和notify()/notifyAll()
 10  */
 11 //店員類
 12 class Clerk {
 13     private int productNumber = 0;
 14     //生產產品
 15     public synchronized void produceProductor() {
 16         if(productNumber<20){
 17             productNumber++;
 18             System.out.println(Thread.currentThread().getName()+":開始生產第"+productNumber+"個產品");
 19           //只要生產者生產出至少一個產品,就能喚醒消費者線程進行消費
 20             notify();
 21         }else{
 22             //當產品的個數大於20的時候,生產者線程就要進入阻塞狀態,等待消費者線程消費產品之後在進行生產
 23             try {
 24                 wait();
 25             } catch (InterruptedException e) {
 26                 e.printStackTrace();
 27             }
 28         }
 29     }
 30     //消費產品
 31     public synchronized void consumerProduct() {
 32         if(productNumber>0){
 33             System.out.println(Thread.currentThread().getName()+":開始消費第"+productNumber+"個產品");
 34             productNumber--;
 35             //只要消費者線程進行了一次消費,就能喚醒生產者線程進行生產
 36             notify();
 37         }else{
 38             //當產品的個數小於等於0的時候,消費者線程就要進入阻塞狀態,等待生產者生產出產品之後在進行消費
 39             try {
 40                 wait();
 41             } catch (InterruptedException e) {
 42                 e.printStackTrace();
 43             }
 44         }
 45     }
 46 }
 47 
 48 //生產者類
 49 class Productor extends Thread {
 50     private Clerk clerk;
 51 
 52     public Productor(Clerk clerk) {
 53         this.clerk = clerk;
 54     }
 55 
 56     @Override
 57     public void run() {
 58         System.out.println(Thread.currentThread().getName() + ":開始生產產品.....");
 59         while (true) {
 60             try {
 61                 Thread.sleep(100);
 62             } catch (InterruptedException e) {
 63                 e.printStackTrace();
 64             }
 65             clerk.produceProductor();
 66         }
 67     }
 68 }
 69 
 70 //消費者類
 71 class Consumer extends Thread {
 72     private Clerk clerk;
 73 
 74     public Consumer(Clerk clerk) {
 75         this.clerk = clerk;
 76     }
 77 
 78     @Override
 79     public void run() {
 80         System.out.println(Thread.currentThread().getName() + ":開始消費產品.....");
 81         while (true) {
 82             try {
 83                 Thread.sleep(100);
 84             } catch (InterruptedException e) {
 85                 e.printStackTrace();
 86             }
 87             clerk.consumerProduct();
 88         }
 89     }
 90 }
 91 //測試類,創建一個生產者生產商品,創建一個消費者消費產品
 92 public class ProductorTest {
 93     public static void main(String[] args) {
 94         Clerk clerk = new Clerk();
 95         Thread p1 = new Productor(clerk);
 96         p1.setName("生產者1");
 97         Thread c1 = new Consumer(clerk);
 98         c1.setName("消費者1");
 99         p1.start();
100         c1.start();
101     }
102 }

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