生產者消費者模式的Java實現

1.在《Java編程思想》第4版併發一章的“21.5.3 生產者與消費者”節看到的生產者和消費者定義了兩個對象,分別在對象內部使用自身調用wait(就是synchronized(this)內部 調用了 wait() , 後面的notify再synchronized(另外一個對象 比如restaurant.chef) 調用另外一個對象的notifyAll();
這種方法相當於是生產者和消費者都要加鎖和通知,有些繁瑣?(或者有誰覺得更好?歡迎討論)

之前面試有遇到生產者消費者的問題。
我:想到的是使用兩個同步的對象。
面試官:太複雜了,一個就可以。
我:那應該也可以,但是當時沒有具體的用語言實現,所以細節上面沒有考慮的太多。

剛上網搜索了一下,發現有使用多種實現方法來實現的(強!)應該是花了一些時間的。

Java生產者消費者的三種實現
https://www.cnblogs.com/xindoo/p/11426659.html

看他的第一種實現,使用了一個隊列。把這個隊列作爲鎖對象。於是想到能不能簡化一下,使用一個產品對象來做互斥呢?
具體實現:定義了一個String的product對象。
然後使用product做同步。初值賦值的是“”。
生產者:當product != ""時,使用product.wait等待。否則就給product賦值當前時間的字符串。然後調用product.notifyAll()通知。
消費者:當product == ""時,使用product.wait等待。否則就給product賦值"",然後調用product.notifyAll()通知。
初看起來好像是沒有問題,但是運行起來就是一直在不停的循環執行下去。
這裏犯了幾個錯誤:
1)開始的時候沒有加入通知對方的方法,生產者和消費者都只加了wait,使得兩個線程啓動之後,只執行了一個. 當時只執行了生產者的方法。消費者根本沒有執行。
2)加入product.notifyAll()的方法。但是執行還是一次。返回去對比前面文章的實現。
3)對比發現沒有在生產者和消費者的run()方法裏面加入死循環,導致執行一次就結束了。
4)加入死循環,但是會不停的執行下去,沒有按照設定的方式交替運行。

這個可能是什麼原因呢?
思考?
對了這裏synchronized的對象是String對象,被賦值不同的值的時候,會發生改變!!!從而使得同步失效!!!
於是定義了一個final的Object對象,作爲生產者和消費者的公用的一個同步對象,問題解決(記錄下來備忘)。
代碼如下:

package com.study.arch.studyalgrithom.thread;

public class ProducerConsumer {
    private final Object syncObject = new Object();  //注意這裏synchronized使用的同步對象不能是變化的,否則就鎖不住了,會出錯!!
    private String product = "";  //注意不能使用這個對象來做鎖,因爲這個對象在變化。但是如果使用隊列,因爲一開始就new了一個對象,所以不會變化,可以作爲同步的對象的。

    class Producer implements Runnable {

        @Override
        public void run() {
            while (!Thread.interrupted()) {
                synchronized (syncObject) {
                    while (product != "") {
                        try {
                            System.out.println("Producer#####product.wait()-------" + product);
                            syncObject.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    product = System.currentTimeMillis() + "------";
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println("Producer#####" + product);
                    syncObject.notifyAll();
                }
            }
        }
    }

    class Consumer implements Runnable {

        @Override
        public void run() {
            while (!Thread.interrupted()) {
                synchronized (syncObject) {
                    while (product == "") {
                        System.out.println("Consumer#####product.wait()-------" + product);
                        try {
                            syncObject.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println("Consumer######product=" + product);
                    product = "";
                    syncObject.notifyAll();
                }
            }
        }
    }

    public void work() {
        Thread producerThread = new Thread(new Producer());
        Thread consumerThread = new Thread(new Consumer());
        producerThread.start();
        consumerThread.start();
        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章