欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

java的wait/notify/notifyAll方法怎么正確使用

本篇內容介紹了“java的wait/notify/notifyAll方法怎么正確使用”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

韓城網(wǎng)站建設公司創(chuàng)新互聯(lián)公司,韓城網(wǎng)站設計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗。已為韓城近1000家提供企業(yè)網(wǎng)站建設服務。企業(yè)網(wǎng)站搭建\外貿網(wǎng)站建設要多少錢,請找那個售后服務好的韓城做網(wǎng)站的公司定做!

一:為什么 wait 必須在 synchronized 保護的同步代碼中使用?

源碼中對wait方法的介紹如下:

        /**
         * As in the one argument version, interrupts and spurious wakeups are
         * possible, and this method should always be used in a loop:
         * <pre>
         *     synchronized (obj) {
         *         while (&lt;condition does not hold&gt;)
         *             obj.wait();
         *         ... // Perform action appropriate to condition
         *     }
         * </pre>
         * This method should only be called by a thread that is the owner
         * of this object's monitor. See the {@code notify} method for a
         * description of the ways in which a thread can become the owner of
         * a monitor.
         *
         */
        public final void wait() throws InterruptedException {
            wait(0);
        }

意思是說,在使用 wait 方法時,必須把 wait 方法寫在 synchronized 保護的 while 代碼塊中,并始終判斷執(zhí)行條件是否滿足,如果滿足就往下繼續(xù)執(zhí)行,如果不滿足就執(zhí)行 wait 方法,而在執(zhí)行 wait 方法之前,必須先持有對象的 monitor 鎖,也就是通常所說的 synchronized 鎖

1.1 不這樣做會導致什么問題?

    class BlockingQueue{

        Queue<String> buffer = new LinkedList<>();
        public void give(String data){
            buffer.add(data);
            notify();
        }
        public String take() throws InterruptedException {
            while(buffer.isEmpty()){
                wait();
            }
            return buffer.remove();
        }
    }

在代碼中可以看到有兩個方法,give 方法負責往 buffer 中添加數(shù)據(jù),添加完之后執(zhí)行 notify 方法來喚醒之前等待的線程,而 take 方法負責檢查整個 buffer 是否為空,如果為空就進入等待,如果不為空就取出一個數(shù)據(jù),這是典型的生產者消費者的思想。

在如上所示的代碼中沒有正確使用wait()方法,那么可能出現(xiàn)什么異常呢?

  1. 首先,消費者線程調用 take 方法并判斷 buffer.isEmpty 方法是否返回 true,若為 true 代表buffer是空的,則線程希望進入等待,但是在線程調用 wait 方法之前(while(buffer.isEmpty())之后),就被調度器暫停了,所以此時還沒來得及執(zhí)行 wait 方法。

  2. 此時生產者開始運行,執(zhí)行了整個 give 方法,它往 buffer 中添加了數(shù)據(jù),并執(zhí)行了 notify 方法,但 notify 并沒有任何效果,因為消費者線程的 wait 方法沒來得及執(zhí)行,所以沒有線程在等待被喚醒。

  3. 此時,剛才被調度器暫停的消費者線程回來繼續(xù)執(zhí)行 wait 方法并進入了等待,這時消費者便有可能陷入無窮無盡的等待,因為它錯過了剛才 give 方法內的 notify 的喚醒。

ps:上面說的調度器暫停線程,因為在多線程下,CPU 的調度是以時間片為單位進行分配的,每個線程都可以得到一定量的時間片。但如果線程擁有的時間片耗盡,它將會被暫停執(zhí)行并讓出 CPU 資源給其他線程。而代碼中的“判斷-執(zhí)行”不是一個原子操作,它在中間有可能被打斷,是線程不安全的,所以說有可能在線程調用 wait 方法之前這個線程就被暫停了。

1.2 wait()方法正確使用方式

    class BlockingQueue{
        Queue<String> buffer = new LinkedList<>();
        public void give(String data){
            synchronized (this){
                buffer.add(data);
                notify();
            }
        }
        public String take() throws InterruptedException {
            synchronized (this){
                while(buffer.isEmpty()){
                    wait();
                }
                return buffer.remove();
            }
        }
    }

這樣就可以確保 notify 方法永遠不會在 buffer.isEmpty 和 wait 方法之間被調用,提升了程序的安全性。另外,wait 方法會釋放 monitor 鎖,這也要求我們必須首先進入到 synchronized 內持有這把鎖。

1.2.1 使用while結構判斷可以避免虛假喚醒問題

線程可能在既沒有被notify/notifyAll,也沒有被中斷或者超時的情況下被喚醒,這種喚醒是我們不希望看到的。然在實際生產中,虛假喚醒發(fā)生的概率很小,但是程序依然需要保證在發(fā)生虛假喚醒的時候的正確性,所以就需要采用while循環(huán)的結構。

while (condition does not hold)
    obj.wait();

這樣即便被虛假喚醒了,也會再次檢查while里面的條件,如果不滿足條件,就會繼續(xù)wait,也就消除了虛假喚醒的風險。

二:wait 和 sleep 方法的異同

2.1 相同點

  • 它們都可以讓線程阻塞

  • 它們都可以響應 interrupt 中斷:在等待的過程中如果收到中斷信號,都可以進行響應,并拋出 InterruptedException 異常。

2.2 不同點

  1. wait 方法必須在 synchronized 保護的代碼中使用,而 sleep 方法并沒有這個要求

  2. 在同步代碼中執(zhí)行 sleep 方法時,并不會釋放 monitor 鎖,但執(zhí)行 wait 方法時會主動釋放 monitor 鎖。

  3. sleep 方法中會要求必須定義一個時間,時間到期后會主動恢復,而對于沒有參數(shù)的 wait 方法而言,意味著永久等待,直到被中斷或被喚醒才能恢復,它并不會主動恢復。

  4. wait/notify/notifyAll 被定義在 Object 類中,而 sleep 定義在 Thread 類中。

2.2.1 為什么wait/notify/notifyAll 被定義在 Object 類中,而 sleep 定義在 Thread 類中?

首先因為 Java 中每個對象都有一把稱之為 monitor 監(jiān)視器的鎖,每個對象都可以上鎖,在對象頭中有一個用來保存鎖信息的位置。這個鎖是對象級別的,而非線程級別的,wait/notify/notifyAll 也都是鎖級別的操作,它們的鎖屬于對象,所以把它們定義在 Object 類中是最合適,因為 Object 類是所有對象的父類。

其次,一個線程可能持有多把鎖,以便實現(xiàn)相互配合的復雜邏輯,既然我們是讓當前線程去等待某個對象的鎖,自然應該通過操作對象來實現(xiàn),而不是操作線程。

“java的wait/notify/notifyAll方法怎么正確使用”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質量的實用文章!

標題名稱:java的wait/notify/notifyAll方法怎么正確使用
網(wǎng)頁路徑:http://aaarwkj.com/article14/ipcode.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站設計、虛擬主機、靜態(tài)網(wǎng)站、移動網(wǎng)站建設、響應式網(wǎng)站、品牌網(wǎng)站建設

廣告

聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

小程序開發(fā)
中文字幕中出亚洲精品| 欧美一日韩一级片免费看| 久久国内午夜福利直播| 国产日产精品久久婷婷色| 中文字幕日产乱码一二三区| 一区二区三区四区四虎| 国产精品传媒成人免费| 成人看片亚欧大片在线观看| 国产高清不卡一区二区| 韩国三级伦理中文字幕| 亚洲伦理在线一区二区| 激情毛片av在线免费看| 一区二区三区都市激情| 亚洲综合国产中文字幕| 99久久久精品国产免费| 精品乱码一区二区三区四区| 国产国产成人精品久久| 午夜激情在线观看国产| 国产在线拍揄自揄视频不卡99| 日韩精品一区二区三区高清 | 亚洲日本欧美在线一区| 日韩人妻中出中文字幕| 欧美精品黑人三级精品| 亚洲欧洲美洲中文天堂| 欧洲亚洲精品免费二区| 亚洲乱色熟女一区二区三区麻豆| 高清不卡一区二区在线观看| 亚洲国产欲色有一二欲色| 热久久这里只有精品网址| 中文字幕一区中出爽亚洲| 日日摸夜夜添添出白浆| 国产亚洲一区二区三区乱码| 日本在线免费成人高清| 日韩一二三区免费不卡视频| 国产成人精品无人区一区| 草逼免费在线观看视频| 91亚洲精品国产一区| 国产欧美日韩亚洲综合在线| 欧美国产一级二级三级| 一区二区三区人妻av| 亚洲国际天堂av在线|