最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中notify和notifyAll的區(qū)別及何時使用

 更新時間:2021年09月07日 15:33:16   作者:angerYang  
本文主要介紹了Java中notify和notifyAll的區(qū)別及何時使用,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下

提幾個問題,從問題中去了解去學習:

  • 他們之間有啥區(qū)別?
  • 如果我使用notify(),將通知哪個線程?
  • 我怎么知道有多少線程在等待,所以我可以使用notifyAll()?
  • 如何調(diào)用notify()?
  • 什么是這些線程等待被通知等?

我給點建議:建議使用jdk8里的lock包

  • java.util.concurrent.locks下的Condition 他可以支持喚醒指定的線程。
  • 他只是一個接口 具體實現(xiàn)類是在AbstractQueuedSynchronizer 也就是AQS框架里的 你可以自己繼承他 或者使用 ReentrantLock里的newConditon()方法來獲取

解決下問題:

Java中notify和notifyAll的區(qū)別

Java提供了兩個方法notify和notifyAll來喚醒在某些條件下等待的線程,你可以使用它們中的任何一個,但是Java中的notify和notifyAll之間存在細微差別,這使得它成為Java中流行的多線程面試問題之一。當你調(diào)用notify時,只有一個等待線程會被喚醒而且它不能保證哪個線程會被喚醒,這取決于線程調(diào)度器。雖然如果你調(diào)用notifyAll方法,那么等待該鎖的所有線程都會被喚醒,但是在執(zhí)行剩余的代碼之前,所有被喚醒的線程都將爭奪鎖定,這就是為什么在循環(huán)上調(diào)用wait,因為如果多個線程被喚醒,那么線程是將獲得鎖定將首先執(zhí)行,它可能會重置等待條件,這將迫使后續(xù)線程等待。因此,notify和notifyAll之間的關鍵區(qū)別在于notify()只會喚醒一個線程,而notifyAll方法將喚醒所有線程。

何時在Java中使用notify和notifyAll

  • 如果所有線程都在等待相同的條件,并且一次只有一個線程可以從條件變?yōu)閠rue,則可以使用notify over notifyAll。
  • 在這種情況下,notify是優(yōu)于notifyAll 因為喚醒所有這些因為我們知道只有一個線程會受益而所有其他線程將再次等待,所以調(diào)用notifyAll方法只是浪費CPU。
  • 雖然這看起來很合理,但仍有一個警告,即無意中的接收者吞下了關鍵通知。通過使用notifyAll,我們確保所有收件人都會收到通知

Java中通知和notifyAll方法的示例(后序demo示例代碼 )

  • 我已經(jīng)匯總了一個示例來說明當我們在Java中調(diào)用notifyAll方法時如何通知所有線程,并且當我們在Java中調(diào)用notify方法時,只有一個Thread會被喚醒。
  • 在這個例子中,如果boolean變量go為false,則三個線程將等待,記住boolean go是一個volatile變量,以便所有線程都能看到它的更新值。
  • 最初三個線程WT1,WT2,WT3將等待,因為變量go為假,而一個線程NT1將變?yōu)檎?,并通過調(diào)用notifyAll方法通知所有線程,或通過調(diào)用notify()方法通知一個線程。在notify()調(diào)用的情況下,無法保證哪個線程會被喚醒,您可以通過多次運行此Java程序來查看它。
  • 在notifyAll的情況下,所有線程都將被喚醒,但是它們將競爭監(jiān)視器或鎖定,并且將首先獲得鎖定的線程將完成其執(zhí)行并且重置為false將迫使其他兩個線程仍在等待。在該程序結(jié)束時,將有兩個線程在等待,兩個線程包括通知線程完成。程序不會終止,因為其他兩個線程仍在等待,并且它們不是守護程序線程。
  • 實例代碼如下:以下是如何在Java中使用notify和notifyAll方法的完整代碼示例。在解釋了何時使用notify vs notifyAll方法,這個例子將闡明在Java中調(diào)用notify和notifyAll方法的效果。go!
import java.util.logging.Level;
import java.util.logging.Logger;
 
/**
 * Java程序演示如何在Java和Java中使用notify和notifyAll方法
  *如何通知和notifyAll方法通知線程,哪個線程被喚醒等。
 */
public class NotificationTest {
 
    private volatile boolean go = false;
 
    public static void main(String args[]) throws InterruptedException {
        final NotificationTest test = new NotificationTest();
      
        Runnable waitTask = new Runnable(){
      
            @Override
            public void run(){
                try {
                    test.shouldGo();
                } catch (InterruptedException ex) {
                    Logger.getLogger(NotificationTest.class.getName()).
                           log(Level.SEVERE, null, ex);
                }
                System.out.println(Thread.currentThread() + " finished Execution");
            }
        };
      
        Runnable notifyTask = new Runnable(){
      
            @Override
            public void run(){
                test.go();
                System.out.println(Thread.currentThread() + " finished Execution");
            }
        };
      
        Thread t1 = new Thread(waitTask, "WT1"); //will wait
        Thread t2 = new Thread(waitTask, "WT2"); //will wait
        Thread t3 = new Thread(waitTask, "WT3"); //will wait
        Thread t4 = new Thread(notifyTask,"NT1"); //will notify
      
        //starting all waiting thread
        t1.start();
        t2.start();
        t3.start();
      
        //pause to ensure all waiting thread started successfully
        Thread.sleep(200);
      
        //starting notifying thread
        t4.start();
      
    }
    /*
     * wait and notify can only be called from synchronized method or bock
     */
    private synchronized void shouldGo() throws InterruptedException {
        while(go != true){
            System.out.println(Thread.currentThread()
                         + " is going to wait on this object");
            wait(); //release lock and reacquires on wakeup
            System.out.println(Thread.currentThread() + " is woken up");
        }
        go = false; //resetting condition
    }
  
    /*
     * both shouldGo() and go() are locked on current object referenced by "this" keyword
     */
    private synchronized void go() {
        while (go == false){
            System.out.println(Thread.currentThread()
            + " is going to notify all or one thread waiting on this object");
 
            go = true; //making condition true for waiting thread
            //notify(); // only one out of three waiting thread WT1, WT2,WT3 will woke up
            notifyAll(); // all waiting thread  WT1, WT2,WT3 will woke up
        }
      
    }
}

使用notify時的輸出
Thread[WT1,5,main] is going to wait on this object
Thread[WT3,5,main] is going to wait on this object
Thread[WT2,5,main] is going to wait on this object
Thread[NT1,5,main] is going to notify all or one thread waiting on this object
Thread[WT1,5,main] is woken up
Thread[NT1,5,main] finished Execution
Thread[WT1,5,main] finished Execution

使用notifyAll時的輸出
Thread[WT1,5,main] is going to wait on this object
Thread[WT3,5,main] is going to wait on this object
Thread[WT2,5,main] is going to wait on this object
Thread[NT1,5,main] is going to notify all or one thread waiting on this object
Thread[WT2,5,main] is woken up
Thread[NT1,5,main] finished Execution
Thread[WT3,5,main] is woken up
Thread[WT3,5,main] is going to wait on this object
Thread[WT2,5,main] finished Execution
Thread[WT1,5,main] is woken up
Thread[WT1,5,main] is going to wait on this object

強烈建議運行這個Java程序并理解它產(chǎn)生的輸出并嘗試理解它。除了死鎖,競爭條件和線程安全之外,線程間通信是Java中并發(fā)編程的基礎之一。

總結(jié):

1)如果我使用notify(),將通知哪個線程?
無法保證,ThreadScheduler將從等待該監(jiān)視器上的線程的池中選擇一個隨機線程。保證只有一個線程會被通知:(隨機性)

2) 我怎么知道有多少線程在等待,所以我可以使用notifyAll()?
它取決于程序邏輯,在編碼時需要考慮一段代碼是否可以由多個線程運行。理解線程間通信的一個很好的例子是在Java中實現(xiàn)生產(chǎn)者 - 消費者模式。

3) 如何調(diào)用notify()?
Wait()和notify()方法只能從synchronized方法或塊中調(diào)用,需要在其他線程正在等待的對象上調(diào)用notify方法。

4) 什么是這些線程等待被通知等?
線程等待某些條件,例如在生產(chǎn)者 - 消費者問題中,如果共享隊列已滿,則生產(chǎn)者線程等待,如果共享隊列為空,則生成者線程等待。由于多個線程正在使用共享資源,因此它們使用wait和notify方法相互通信。

這就是Java中的notify和notifyAll方法之間的區(qū)別以及何時在Java中使用notify vs notifyAll?,F(xiàn)在,應該能夠理解并使用notify和notifyAll方法在Java程序中進行線程間通信。

補充下建議里的:lock包下的condition (demo里 是典型的生產(chǎn)者消費者模式》》》 使用的是condition來實現(xiàn))

   final Lock lock = new ReentrantLock();
   //定義2組condition 對應生產(chǎn)者消費者
   final Condition notFull  = lock.newCondition(); 
  
   final Condition notEmpty = lock.newCondition(); 
 
   final Object[] items = new Object[100];
   int putptr, takeptr, count;
    //在put的時候 當數(shù)組已經(jīng)滿了的情況下 我讓線程等待 不在容納數(shù)據(jù) 當消費者已經(jīng)消費了 觸發(fā)了、、
 
//notfull.signal() 這時候通知生產(chǎn)者 我這變已經(jīng)消費了 你那邊可以試試了哈。 
   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length)
         notFull.await();
       items[putptr] = x;
       if (++putptr == items.length) putptr = 0;
       ++count;
       notEmpty.signal();
     } finally {
       lock.unlock();
     }
   }
//同上 相反的理解就是了。。。
   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0)
         notEmpty.await();
       Object x = items[takeptr];
       if (++takeptr == items.length) takeptr = 0;
       --count;
       notFull.signal();
       return x;
     } finally {
       lock.unlock();
     }
   }

 Condition因素出Object監(jiān)視器方法(waitnotify notifyAll)為不同的對象,以得到具有多個等待集的每個對象,通過將它們與使用任意的相結(jié)合的效果Lock的實施方式。如果Lock替換synchronized方法和語句Condition的使用,則替換Object監(jiān)視方法的使用。

條件(也稱為條件隊列或 條件變量)為一個線程提供暫停執(zhí)行(“等待”)的手段,直到另一個線程通知某個狀態(tài)條件現(xiàn)在可能為真。由于對此共享狀態(tài)信息的訪問發(fā)生在不同的線程中,因此必須對其進行保護,因此某種形式的鎖定與該條件相關聯(lián)。等待條件提供的關鍵屬性是它以原子方式釋放關聯(lián)的鎖并掛起當前線程,就像它一樣Object.wait。

一個Condition實例本質(zhì)上綁定到一個鎖。要獲取Condition特定Lock 實例的實例,請使用其newCondition()方法。

舉個例子,假設我們有一個支持put和take方法的有界緩沖區(qū) 。如果take在空緩沖區(qū)上嘗試a ,則線程將阻塞直到某個項可用; 如果put在完整緩沖區(qū)上嘗試a,則線程將阻塞,直到空間可用。我們希望 在單獨的等待集中保持等待put線程和take線程,以便我們可以使用僅在緩沖區(qū)中的項或空間可用時通知單個線程的優(yōu)化。

也就是說 可以創(chuàng)建多個condition 每組condition 對應你的具體的線程操作 當你

notFull.signalAll();的時候 你喚醒的也只是你這組condition里的等待線程 對于不在這組里的notEmpty是沒有任何影響的
現(xiàn)在 你是不是可以隨心所欲的喚醒你想喚醒的線程了?

補充:關于notify() 和notifyAll() 一個需要注意的地方

notify() 和 notifyAll()都是喚醒其他正在等待同一個對象鎖的線程。

下面是我遇到的一個問題,記下來,免得忘了。

直接上代碼,有錯誤的代碼:

代碼描述:有一個Caculate類,類中又一個成員變量 j,現(xiàn)在有多個線程對這個變量進行操作。一個增加操作、一個減少操作。增加操作:當 j = 0 時,j++ 。減少操作:當 j = 1 時,j-- 。這兩個操作分別對應這 add()方法 和sub()方法,都使用synchronized關鍵字。

可以直接復制拿來運行一下

package com.zcd2;

public class ThreadTest1
{
    public static void main(String[] args)
    {
        Caculate caculate = new Caculate();
        
        //使用多個線程對實例caculate進行增加操作。
        for(int i = 0; i < 10; i++)
        {
            Thread1 t = new Thread1(caculate);
            t.start();
        }
        
        //使用多個線程對實例caculate進行減少操作。
        for(int i = 0; i < 2; i++)
        {
            Thread2 t = new Thread2(caculate);
            t.start();
        }
    }
}

//Thread1線程進行增加操作
class Thread1 extends Thread
{
    private Caculate caculate;
    
    public Thread1()
    {
        
    }    
    
    public Thread1(Caculate caculate)
    {
        this.caculate = caculate;
    }
    
    @Override
    public void run()
    {
        int i = 0;

        //死循環(huán),手動停止
        while(true)
        {
            try
            {
                caculate.add();
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            i++;
            System.out.println("加線程執(zhí)行第 " + i + " 次");
        }
    }    
}

//Thread2進行減少操作。
class Thread2 extends Thread
{    
    private Caculate caculate;
    
    public Thread2()
    {
    }

    public Thread2(Caculate caculate)
    {
        this.caculate = caculate;
    }

    @Override
    public void run()
    {    
        int i = 0;
        
        //死循環(huán),手動停止
        while(true)
        {
            try
            {
                caculate.sub();
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            i++;
            System.out.println("減線程執(zhí)行第 " + i + " 次");
        }
    }    
}

//
class Caculate
{
    private int j = 0;    

    //增加操作
    public synchronized void add() throws InterruptedException
    {
     //當 j = 1 的時候說明不符合操作條件,要放棄對象鎖。
        while(j == 1)
        {
            wait();
            System.out.println();
        }    
        j++;
        System.out.println(j);
        notify();
    }

    //減少操作
    public synchronized void sub() throws InterruptedException
    {
     //當j = 0 的時候說明不符合操作條件,放棄對象鎖
        while(j == 0)
        {
            wait();
            System.out.println();
        }
        j--;
        System.out.println(j);
        notify();
    }
}

以上代碼并不能一直循環(huán)執(zhí)行,按道理說應該是一直循環(huán)執(zhí)行的。

為什么呢????????

這就涉及到了notify() 和 notifyAll()的其中一個區(qū)別了。

這個區(qū)別就是:調(diào)用 notify() 方法只能隨機喚醒一個線程,調(diào)用notifyAll() 方法的喚醒所有的等待的線程。

比如這里,當一個線程在正常執(zhí)行。。。假設這里正常執(zhí)行完一個增加操作的線程,然后調(diào)用 notify() 方法 那么它會隨機喚醒一個線程。

  ①、如果喚醒的是進行減少操作的線程,此時 j = 1,線程能夠正常執(zhí)行減少操作。

 ?、?、如果喚醒的是進行增加操作的線程,此時 j = 1,那么不符合增加操作的條件,他就會調(diào)用 wait() 方法。那么調(diào)用完wait()方法后程序就會發(fā)現(xiàn)已經(jīng)沒有被喚醒的線程了。唯一一個被喚醒的線程因不符合條件放棄了對象鎖,其他線程又沒有被喚醒。此時程序只能一直等到其他線程被喚醒,但是它等不到了。

解決:

把notify() 改成notifyAll() 這個問題就解決了。因為如果喚醒一個線程,但是這個線程因不符合執(zhí)行條件而放棄對象,還有很多喚醒的線程。

所以,當多個(兩個以上的)線程操作同一個對象的時候最好使用的notifyAll(),這樣就不會出現(xiàn)上述的問題了。

發(fā)現(xiàn)一個問題,既然使用notify()會出問題那為什么不在每個地方的使用notifyAll()呢??這二者還有其他我沒了解的區(qū)別嗎???難道使用notifyAll() 會使性能大大下降???有待解決。

到此這篇關于Java中notify和notifyAll的區(qū)別及何時使用的文章就介紹到這了,更多相關Java notify和notifyAll內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家! 

相關文章

  • svn 清理失敗 (cleanup 失敗) 的快速解決方法

    svn 清理失敗 (cleanup 失敗) 的快速解決方法

    下面小編就為大家?guī)硪黄猻vn 清理失敗 (cleanup 失敗) 的快速解決方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-10-10
  • Java的方法和this關鍵字如何理解與應用

    Java的方法和this關鍵字如何理解與應用

    Java語言中的“方法”(Method)在其他語言當中也可能被稱為“函數(shù)”(Function)。對于一些復雜的代碼邏輯,如果希望重復使用這些代碼,并且做到“隨時任意使用”,那么就可以將這些代碼放在一個大括號{}當中,并且起一個名字。使用代碼的時候,直接找到名字調(diào)用即可
    2021-10-10
  • 學會Java字節(jié)碼指令,成為技術大佬

    學會Java字節(jié)碼指令,成為技術大佬

    Java 字節(jié)碼指令是 JVM 體系中非常難啃的一塊硬骨頭,我估計有些讀者會有這樣的疑惑,“Java 字節(jié)碼難學嗎?我能不能學會???”本文帶領大家一探究竟,幫助大家搞懂java底層代碼如何執(zhí)行
    2021-08-08
  • Java中BigDecimal精度和相等比較的坑

    Java中BigDecimal精度和相等比較的坑

    BigDecimal是一種精確的數(shù)字類,一般用于高精度的開發(fā)領域中,例如銀行。下面這篇文章主要給大家介紹了關于Java中BigDecimal精度和相等比較的坑的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2018-09-09
  • 淺析Java集合中的LinkedHashSet

    淺析Java集合中的LinkedHashSet

    這篇文章主要介紹了淺析Java集合中的LinkedHashSet,LinkedHashSet?是?Java?中的一個集合類,它是?HashSet?的子類,并實現(xiàn)了?Set?接口,與?HashSet?不同的是,LinkedHashSet?保留了元素插入的順序,并且具有?HashSet?的快速查找特性,需要的朋友可以參考下
    2023-09-09
  • Spring?Boot項目集成Knife4j接口文檔的實例代碼

    Spring?Boot項目集成Knife4j接口文檔的實例代碼

    Knife4j就相當于是swagger的升級版,對于我來說,它比swagger要好用得多<BR>,這篇文章主要介紹了Spring?Boot項目集成Knife4j接口文檔的示例代碼,需要的朋友可以參考下
    2021-12-12
  • 詳解java數(shù)據(jù)結(jié)構(gòu)與算法之雙鏈表設計與實現(xiàn)

    詳解java數(shù)據(jù)結(jié)構(gòu)與算法之雙鏈表設計與實現(xiàn)

    本篇文章主要介紹了詳解java數(shù)據(jù)結(jié)構(gòu)與算法之雙鏈表設計與實現(xiàn),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • springmvc 分頁查詢的簡單實現(xiàn)示例代碼

    springmvc 分頁查詢的簡單實現(xiàn)示例代碼

    我們在開發(fā)項目中很多項目都用到列表分頁功能,本篇介紹了springmvc 分頁查詢的簡單實現(xiàn)示例代碼,非常具有實用價值,需要的朋友可以參考下。
    2017-01-01
  • SpringCloud?Eureka應用全面介紹

    SpringCloud?Eureka應用全面介紹

    Eureka是Netflix開發(fā)的服務發(fā)現(xiàn)框架,本身是一個基于REST的服務,主要用于定位運行在AWS域中的中間層服務,以達到負載均衡和中間層服務故障轉(zhuǎn)移的目的
    2022-09-09
  • Spring中@Configuration注解的Full模式和Lite模式詳解

    Spring中@Configuration注解的Full模式和Lite模式詳解

    這篇文章主要介紹了Spring中@Configuration注解的Full模式和Lite模式詳解,準確來說,Full?模式和?Lite?模式其實?Spring?容器在處理?Bean?時的兩種不同行為,這兩種不同的模式在使用時候的表現(xiàn)完全不同,今天就來和各位小伙伴捋一捋這兩種模式,需要的朋友可以參考下
    2023-09-09

最新評論

阿拉善右旗| 治县。| 苏尼特左旗| 嘉善县| 安乡县| 集安市| 香格里拉县| 鹤山市| 五莲县| 霍山县| 河西区| 綦江县| 卢氏县| 米脂县| 余江县| 泗水县| 大城县| 昌图县| 锦屏县| 普洱| 汝阳县| 抚松县| 胶州市| 奉节县| 若尔盖县| 陵川县| 台湾省| 福州市| 孟州市| 肥西县| 安阳市| 巍山| 峨山| 达孜县| 许昌市| 衢州市| 青铜峡市| 如东县| 城固县| 安化县| 永春县|