java線程經典之生產者與消費者

java線程經典之生產者與消費者

---------------------- ASP.Net+Android+IOS開發.Net培訓、期待與您交流! ----------------------

無論是課本還是視頻教學都會有這麼一個例子生產者與消費者,可以說是一個經典例子了!

生產者-消費者(producer-consumer)問題,也稱作有界緩衝區(bounded-buffer)問題,兩個進程共享一個公共的固定大小的緩衝區。其中一個是生產者,用於將消息放入緩衝區;另外一個是消費者,用於從緩衝區中取出消息。問題出現在當緩衝區已經滿了,而此時生產者還想向其中放入一個新的數據項的情形,其解決方法是讓生產者此時進行休眠,等待消費者從緩衝區中取走了一個或者多個數據後再去喚醒它。同樣地,當緩衝區已經空了,而消費者還想去取消息,此時也可以讓消費者進行休眠,等待生產者放入一個或者多個數據時再喚醒它。

一,首先定義公共資源類,其中的變量number是保存的公共數據。並且定義兩個方法,增加number的值和減少number的值。由於多線程的原因,必須加上synchronized關鍵字,注意while判斷的條件。

Java代碼 

/** 

* 公共資源類 

*/ 

public class PublicResource { 

private int number = 0; 

/** 

* 增加公共資源 

*/ 

10 public synchronized void increace() { 

11 while (number != 0) { 

12 try { 

13 wait(); 

14 catch (InterruptedException e) { 

15 e.printStackTrace(); 

16 

17 

18 number++; 

19 System.out.println(number); 

20 notify(); 

21 

22 

23 /** 

24 * 減少公共資源 

25 */ 

26 public synchronized void decreace() { 

27 while (number == 0) { 

28 try { 

29 wait(); 

30 catch (InterruptedException e) { 

31 e.printStackTrace(); 

32 

33 

34 number--; 

35 System.out.println(number); 

36 notify(); 

37 

38 

/**

 * 公共資源類

 */

public class PublicResource {

    private int number = 0;

 

    /**

     * 增加公共資源

     */

    public synchronized void increace() {

        while (number != 0) {

            try {

                wait();

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

        number++;

        System.out.println(number);

        notify();

    }

 

    /**

     * 減少公共資源

     */

    public synchronized void decreace() {

        while (number == 0) {

            try {

                wait();

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

        }

        number--;

        System.out.println(number);

        notify();

    }

}

 

二,分別定義生產者線程和消費者線程,並模擬多次生產和消費,即增加和減少公共資源的number值

Java代碼 

39 /** 

40 * 生產者線程,負責生產公共資源 

41 */ 

42 public class ProducerThread implements Runnable { 

43 private PublicResource resource; 

44 

45 public ProducerThread(PublicResource resource) { 

46 this.resource = resource; 

47 

48 

49 @Override 

50 public void run() { 

51 for (int i = 0; i < 10; i++) { 

52 try { 

53 Thread.sleep((long) (Math.random() * 1000)); 

54 catch (InterruptedException e) { 

55 e.printStackTrace(); 

56 

57 resource.increace(); 

58 

59 

60 

61 /** 

62 * 消費者線程,負責消費公共資源 

63 */ 

64 public class ConsumerThread implements Runnable { 

65 private PublicResource resource; 

66 

67 public ConsumerThread(PublicResource resource) { 

68 this.resource = resource; 

69 

70 

71 @Override 

72 public void run() { 

73 for (int i = 0; i < 10; i++) { 

74 try { 

75 Thread.sleep((long) (Math.random() * 1000)); 

76 catch (InterruptedException e) { 

77 e.printStackTrace(); 

78 

79 resource.decreace(); 

80 

81 

82 

/**

 * 生產者線程,負責生產公共資源

 */

public class ProducerThread implements Runnable {

    private PublicResource resource;

    public ProducerThread(PublicResource resource) {

        this.resource = resource;

    }

    @Override

    public void run() {

        for (int i = 0; i < 10; i++) {

            try {

                Thread.sleep((long) (Math.random() * 1000));

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            resource.increace();

        }

    }

}

/**

 * 消費者線程,負責消費公共資源

 */

public class ConsumerThread implements Runnable {

    private PublicResource resource;

    public ConsumerThread(PublicResource resource) {

        this.resource = resource;

    }

    @Override

    public void run() {

        for (int i = 0; i < 10; i++) {

            try {

                Thread.sleep((long) (Math.random() * 1000));

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            resource.decreace();

        }

    }

}

三,模擬多個生產者和消費者操作公共資源的情形,結果須保證是在允許的範圍內。

Java代碼 

83 public class ProducerConsumerTest { 

84 public static void main(String[] args) { 

85 PublicResource resource = new PublicResource(); 

86 new Thread(new ProducerThread(resource)).start(); 

87 new Thread(new ConsumerThread(resource)).start(); 

88 new Thread(new ProducerThread(resource)).start(); 

89 new Thread(new ConsumerThread(resource)).start(); 

90 new Thread(new ProducerThread(resource)).start(); 

91 new Thread(new ConsumerThread(resource)).start(); 

92 

93 

我的總結:生產者和消費者

if判斷標記,只有一次,會導致不該運行的線程運行了,出現了數據錯誤的情況。

while判斷標記,解決了線程獲取執行權後,是否要運行!

notify:只能喚醒以一個線程,如果本方喚醒了本方,就沒有意義。而且while判斷標記+notify會導致死鎖。

notifyAll 解決了本方線程一定會喚醒對方線程的問題。

---------------------- ASP.Net+Android+IOS開發.Net培訓、期待與您交流! ----------------------

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章