wait/notify為什么必須synchronized包裹

首先,jvm內(nèi)部在notify與wait邏輯中都強(qiáng)制判斷是否有對等待對象加鎖,所以如下代碼邏輯會拋異常

static class BlockingQ {
        private static final int MAX_SIZE = 10;
        private final List<String> queue = new ArrayList<>(MAX_SIZE);
                private final Object putWait = new Object();
                private final Object getWait = new Object();
        public void put(String s) throws InterruptedException {
            synchronized (queue) { //這里鎖住的是queue對象
                while (queue.size() >= MAX_SIZE)
                    putWait.wait(); //這里的wait必須是針對queue對象進(jìn)行wait
                queue.add(s);
                getWait.notifyAll(); //同理
            }
        }

        public String get() throws InterruptedException {
            synchronized (queue) {
                while (queue.isEmpty()) {
                    getWait.wait(); //同理
                }
                String result = queue.remove(0);
                putWait.notifyAll(); //同理
                return result;
            }
        }
    }

修改后的正確代碼實(shí)現(xiàn)為:

static class BlockingQ {
        private static final int MAX_SIZE = 10;
        private final List<String> queue = new ArrayList<>(MAX_SIZE);

        public void put(String s) throws InterruptedException {
            synchronized (queue) {
                while (queue.size() >= MAX_SIZE)
                    queue.wait();
                queue.add(s);
                queue.notifyAll();
            }
        }

        public String get() throws InterruptedException {
            synchronized (queue) {
                while (queue.isEmpty()) {
                    queue.wait();
                }
                String result = queue.remove(0);
                queue.notifyAll();
                return result;
            }
        }
    }

要實(shí)現(xiàn)條件隊(duì)列細(xì)化,必須使用ReentrantLock與condition這對叼逼組合

jvm為什么強(qiáng)制wait/notify必須包裹在synchronized塊中

queue.wait();這句話被調(diào)用時,jvm會釋放自身這把鎖,如果沒有同步鎖或者鎖不是自己這個對象,將會報錯。
原因-----------摘自stackoverflow

class BlockingQueue {
    Queue<String> buffer = new LinkedList<String>();

    public void give(String data) {
        buffer.add(data);
        notify();                   // Since someone may be waiting in take!
    }

    public String take() throws InterruptedException {
        while (buffer.isEmpty())    // don't use "if" due to spurious wakeups.
            wait();
        return buffer.remove();
    }
}

This is what could potentially happen:

1.A consumer thread calls take() and sees that the buffer.isEmpty().
2.Before the consumer thread goes on to call wait(), a producer thread comes along and invokes a full give(), that is, buffer.add(data); notify();
3.The consumer thread will now call wait() (and miss the notify() that was just called).
4.If unlucky, the producer thread won't produce more give() as a result of the fact that the consumer thread never wakes up, and we have a dead-lock.

Once you understand the issue, the solution is obvious: Always perform give/notify and isEmpty/wait atomically.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,569評論 19 139
  • PLEASE READ THE FOLLOWING APPLE DEVELOPER PROGRAM LICENSE...
    念念不忘的閱讀 13,660評論 5 6
  • **2014真題Directions:Read the following text. Choose the be...
    又是夜半驚坐起閱讀 11,116評論 0 23
  • “老師大概喜歡素色,因?yàn)樗囊路际呛谏桶咨摹!? 這句話,是我在批閱學(xué)生日記的時候看到的,低下頭看看自己...
    夏以狐閱讀 650評論 1 2
  • 跟鋼總聊了我們的情況,她堅(jiān)持是我自己想太多,你對我根本沒到喜歡那步,甚至?xí)崦炼紱]有,一切都是我自己加的戲。that...

友情鏈接更多精彩內(nèi)容