国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【從零開始學(xué)習(xí)JAVA | 三十九篇】深入多線程

這篇具有很好參考價(jià)值的文章主要介紹了【從零開始學(xué)習(xí)JAVA | 三十九篇】深入多線程。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

目錄

前言:? ? ? ??

?1.線程的壽命周期?

2.線程的安全問題

3.鎖

同步代碼塊:

同步方法:

死鎖:

4.生產(chǎn)者和消費(fèi)者模式(等待喚醒機(jī)制)

總結(jié):


前言:? ? ? ??

????????當(dāng)今軟件開發(fā)領(lǐng)域中,多線程編程已成為一項(xiàng)至關(guān)重要的技能。然而,要編寫出高效、可靠的多線程程序并不容易。多線程編程面臨著許多挑戰(zhàn),如線程安全性、資源共享、死鎖等問題。因此,對(duì)于初學(xué)者來說,深入理解Java多線程的工作原理和機(jī)制是至關(guān)重要的。只有通過掌握多線程的核心概念、了解常見問題和解決方案,我們才能寫出健壯且高性能的多線程應(yīng)用。

????????本文將為大家逐步深入介紹Java多線程的重要概念和機(jī)制。我們將從線程的創(chuàng)建和啟動(dòng)開始,討論如何使用線程池管理線程,并探討線程間的通信和同步技術(shù)。我們還將介紹一些常用的多線程設(shè)計(jì)模式和最佳實(shí)踐,幫助讀者更好地應(yīng)用多線程技術(shù)解決實(shí)際問題。

【從零開始學(xué)習(xí)JAVA | 三十九篇】深入多線程,【從零開始學(xué)習(xí)JAVA】,學(xué)習(xí),java,開發(fā)語言

1.線程的壽命周期

線程的生命周期描述了一個(gè)線程從創(chuàng)建到終止的整個(gè)過程,一般包含以下幾個(gè)階段:

  1. 新建狀態(tài)(New):

    • 當(dāng)線程對(duì)象被創(chuàng)建后,它處于新建狀態(tài)。
    • 此時(shí),線程還未被啟動(dòng),即尚未調(diào)用start()方法。
  2. 可運(yùn)行狀態(tài)(Runnable):

    • 當(dāng)線程調(diào)用start()方法后,進(jìn)入可運(yùn)行狀態(tài)。
    • 線程處于此狀態(tài)時(shí),可能正在執(zhí)行,也可能正在等待系統(tǒng)資源。
  3. 運(yùn)行狀態(tài)(Running):

    • 可運(yùn)行狀態(tài)中的線程被系統(tǒng)調(diào)度執(zhí)行,處于運(yùn)行狀態(tài)。
    • 線程執(zhí)行run()方法中的任務(wù)代碼。
  4. 阻塞狀態(tài)(Blocked):

    • 阻塞狀態(tài)指線程因?yàn)槟承┰驎簳r(shí)停止執(zhí)行,例如等待某個(gè)資源、等待鎖的釋放等。
    • 當(dāng)滿足特定條件時(shí),線程會(huì)進(jìn)入阻塞狀態(tài),等待條件滿足后被喚醒。
  5. 無限期等待狀態(tài)(Waiting):

    • 線程在某些條件下調(diào)用無參數(shù)的wait()方法,會(huì)進(jìn)入無限期等待狀態(tài)。
    • 只有當(dāng)其他線程顯式地調(diào)用notify()或notifyAll()方法,或者被中斷,才能解除該狀態(tài)。
  6. 限期等待狀態(tài)(Timed Waiting):

    • 線程在某些條件下調(diào)用具有超時(shí)參數(shù)的wait()、sleep()、join()或LockSupport.parkNanos()等方法,會(huì)進(jìn)入限期等待狀態(tài)。
    • 時(shí)間一過,或者收到特定事件的通知,該線程將會(huì)被喚醒。
  7. 終止?fàn)顟B(tài)(Terminated):

    • 線程執(zhí)行完run()方法中的任務(wù)代碼,或者線程發(fā)生異常而提前結(jié)束,都會(huì)進(jìn)入終止?fàn)顟B(tài)。
    • 一旦線程進(jìn)入終止?fàn)顟B(tài),就不能再切換到其他狀態(tài)。

需要注意的是,線程的狀態(tài)可以相互切換,具體的轉(zhuǎn)換由Java的線程調(diào)度器和操作系統(tǒng)決定。線程的生命周期和狀態(tài)的轉(zhuǎn)換對(duì)于多線程編程非常重要,合理地管理線程的狀態(tài)可以提高程序的性能和并發(fā)能力。

2.線程的安全問題

我們用一個(gè)案例來說明:

現(xiàn)在我們要開設(shè)三個(gè)窗口來買票,一共有100張票,請(qǐng)你利用多線程的知識(shí)完成。


class MyThread extends Thread {
    static int  tick=0;
    public void run() {
        // 定義線程要執(zhí)行的任務(wù)

        while(true)
       {
           if(tick<100)
           {

               try {
                   Thread.sleep(100);
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
               tick++;
               System.out.println(getName()+"正在賣第"+tick+"張票");
           }
           else
           {
               break;
           }
       }
    }
}

public class test05 {
    public static void main(String[] args) {
        MyThread  t1 = new MyThread();
        MyThread  t2 = new MyThread();
        MyThread  t3 = new MyThread();

        t1.start();
        t2.start();
        t3.start();
    }
}

很多同學(xué)在第一時(shí)間就會(huì)寫出這樣一個(gè)簡單的多線程,但是當(dāng)我們運(yùn)行之后,就會(huì)有一個(gè)明顯的問題:出現(xiàn)了一張票賣了兩次這種情況 ,也會(huì)出現(xiàn)了賣超了的這種現(xiàn)象。

【從零開始學(xué)習(xí)JAVA | 三十九篇】深入多線程,【從零開始學(xué)習(xí)JAVA】,學(xué)習(xí),java,開發(fā)語言

?我們來詳細(xì)解釋一下為什么

【從零開始學(xué)習(xí)JAVA | 三十九篇】深入多線程,【從零開始學(xué)習(xí)JAVA】,學(xué)習(xí),java,開發(fā)語言

線程1和線程2和線程3都在搶奪cpu調(diào)度,假設(shè)線程1搶到之后,那么他先進(jìn)入if語句,但if語句中有一個(gè)sleep,執(zhí)行到這里后,線程1就會(huì)被阻塞睡眠,此時(shí)線程2和線程3重新?lián)寠Zcpu調(diào)度,線程2搶到資源之后進(jìn)入if語句也會(huì)睡眠,然后就是線程3進(jìn)入資源,也會(huì)睡眠。隨著這三個(gè)的睡眠周期結(jié)束,就又會(huì)執(zhí)行if中的代碼。當(dāng)tick還沒來得及打印的時(shí)候,線程2醒來又會(huì)搶奪cpu資源,如果搶到了,就又會(huì)執(zhí)行一次tick++,接下來又是線程3.如此這樣循環(huán),就會(huì)造成賣出兩張票并且可能賣超的結(jié)果。

通過這個(gè)案例我們可以看出多線程在執(zhí)行的時(shí)候,有一個(gè)重要的隱患:

?線程的執(zhí)行具有隨機(jī)性

那么我們最簡單的思路就是:

設(shè)計(jì)一種方法,這個(gè)方法使得? 如果一個(gè)線程正在執(zhí)行代碼,那么其他的線程必須等待,只有當(dāng)這個(gè)線程執(zhí)行完之后,其他的線程才可以搶占CPU資源。這就是我們下面要介紹的東西

3.鎖

同步代碼塊:

把代碼塊用鎖鎖起來

synchronized(鎖)
{
    操作共享數(shù)據(jù)的代碼
}

特點(diǎn):

  • ????????鎖是默認(rèn)打開的,如果有一個(gè)進(jìn)程進(jìn)去了,鎖就會(huì)自動(dòng)關(guān)閉。
  • ? ? ? ? 里面的代碼全部執(zhí)行完畢,線程出來,鎖自動(dòng)打開

因此我們嘗試一下用鎖來改進(jìn)一下


class MyThread extends Thread {
    static int  tick=0;
    static Object oj = new Object();
    public void run() {
        // 定義線程要執(zhí)行的任務(wù)

        while(true)
        {

           try {
            Thread.sleep(10);
        } 
         catch (InterruptedException e)
        {
            throw new RuntimeException(e);
        }
             synchronized (oj)
          {

              if(tick<10000)
              {

                  tick++;
                  System.out.println(getName()+"正在賣第"+tick+"張票");
              }
              else
              {
                  break;
              }
          }
      }
    }
}

鎖的注意點(diǎn):

  1. 鎖的粒度:要在保證線程安全的前提下,盡量減小鎖的范圍。過大的鎖粒度可能導(dǎo)致不必要的線程阻塞,影響性能??梢钥紤]使用細(xì)粒度鎖或者使用并發(fā)集合類來提高并發(fā)性能。

  2. 鎖的公平性:鎖可以是公平的或非公平的。公平鎖會(huì)按照線程請(qǐng)求鎖的順序依次獲取鎖,而非公平鎖則不保證線程獲取鎖的先后順序。在選擇鎖時(shí),根據(jù)具體情況選擇公平或非公平鎖。

  3. 死鎖情況:死鎖是指兩個(gè)或多個(gè)線程相互等待對(duì)方釋放持有的鎖,從而導(dǎo)致所有線程無法繼續(xù)執(zhí)行的情況。為避免死鎖,需要謹(jǐn)慎設(shè)計(jì)鎖的獲取順序,并盡量避免嵌套鎖的情況。

  4. 鎖的釋放:在使用鎖時(shí),需要保證鎖的正確釋放,以免出現(xiàn)資源泄漏或線程饑餓等問題。一般可以使用try-finally塊來確保在發(fā)生異常時(shí)仍能正確釋放鎖。

  5. 鎖的性能:鎖的競爭會(huì)帶來一定的性能開銷,過多的鎖競爭可能會(huì)影響應(yīng)用的并發(fā)性能??梢钥紤]使用讀寫鎖、無鎖數(shù)據(jù)結(jié)構(gòu)或并發(fā)集合類等替代方案,來降低鎖競爭帶來的性能開銷。

  6. 死鎖檢測和避免:一旦發(fā)生死鎖,所有線程都將無法繼續(xù)執(zhí)行。為了避免死鎖,可以使用工具進(jìn)行死鎖檢測,并合理設(shè)計(jì)鎖的獲取和釋放順序,避免潛在的死鎖情況。

同步方法:

把方法用? 鎖? 鎖起來

修飾符   synchronized  返回值類型  方法名  (方法參數(shù)){...}

特點(diǎn):

  • 同步方法是鎖住方法里面的所有代碼
  • 鎖對(duì)象不能自己指定

非靜態(tài):this

靜態(tài):當(dāng)前類的字節(jié)碼文件

?則我們可把前面的改寫為:

class MyThread   extends Thread  {
    static int  tick=0;
    static final Object oj = new Object();
    public synchronized void run() {
        // 定義線程要執(zhí)行的任務(wù)

        while(true)
        {
                if (tick < 100) {

                    tick++;
                    System.out.println(getName() + "正在賣第" + tick + "張票");
                } else {

                    break;
                }

            }
      }
    }

死鎖:

死鎖是指在多線程編程中,兩個(gè)或多個(gè)線程互相持有對(duì)方需要的資源,導(dǎo)致它們都無法繼續(xù)執(zhí)行,稱為死鎖現(xiàn)象。

死鎖的發(fā)生通常需要滿足以下四個(gè)條件,也稱為死鎖的必要條件:

  1. 互斥條件:至少有一個(gè)資源同時(shí)只能被一個(gè)線程持有。
  2. 請(qǐng)求與保持條件:一個(gè)線程在持有某個(gè)資源的同時(shí),又請(qǐng)求獲取其他線程持有的資源。
  3. 不可剝奪條件:已經(jīng)分配給一個(gè)線程的資源不能被強(qiáng)制性地剝奪,只能由持有該資源的線程顯式釋放。
  4. 循環(huán)等待條件:多個(gè)線程之間形成循環(huán)等待一系列資源,而每個(gè)線程都在等待下一個(gè)線程所持有的資源。

當(dāng)以上四個(gè)條件都滿足時(shí),就可能出現(xiàn)死鎖。在死鎖發(fā)生時(shí),這些線程將無法繼續(xù)執(zhí)行下去,需要通過一些策略進(jìn)行解決,如避免死鎖的產(chǎn)生、檢測死鎖、解除死鎖等。

解決死鎖的方法一般有以下幾種:

  1. 避免死鎖:通過破壞死鎖的必要條件之一,如避免循環(huán)等待,確保資源分配的順序性。
  2. 檢測與恢復(fù):通過資源分配圖、銀行家算法等方法檢測死鎖的發(fā)生,然后采取相應(yīng)的策略進(jìn)行恢復(fù),如終止某些線程、回收資源等。
  3. 預(yù)防死鎖:通過一些算法和策略在設(shè)計(jì)階段預(yù)防死鎖的發(fā)生,如資源有序分配法、資源剝奪等。
  4. 忽略死鎖:對(duì)于一些系統(tǒng)來說,死鎖的發(fā)生概率較低且解決代價(jià)較高,可以選擇忽略死鎖。當(dāng)發(fā)生死鎖時(shí),通過系統(tǒng)重啟或人工介入恢復(fù)正常。
public class DeadlockExample {
    public static void main(String[] args) {
        final Object resource1 = new Object();
        final Object resource2 = new Object();

        Thread thread1 = new Thread(() -> {
            synchronized (resource1) {
                System.out.println("Thread 1 acquired lock on resource1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (resource2) {
                    System.out.println("Thread 1 acquired lock on resource2");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (resource2) {
                System.out.println("Thread 2 acquired lock on resource2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (resource1) {
                    System.out.println("Thread 2 acquired lock on resource1");
                }
            }
        });

        thread1.start();
        thread2.start();

        // 等待兩個(gè)線程執(zhí)行完畢
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Execution completed");
    }
}

在上述代碼中,兩個(gè)線程?thread1?和?thread2?分別嘗試獲取?resource1?和?resource2?的鎖。但是它們獲取鎖的順序是相反的,即?thread1?先獲取?resource1?的鎖,再獲取?resource2?的鎖;而?thread2?先獲取?resource2?的鎖,再獲取?resource1?的鎖。

這種情況下,如果兩個(gè)線程同時(shí)啟動(dòng),則?thread1?獲取了?resource1?的鎖并等待?resource2?的鎖釋放,而?thread2?獲取了?resource2?的鎖并等待?resource1?的鎖釋放。由于兩個(gè)線程相互等待對(duì)方所持有的鎖,它們將處于死鎖狀態(tài),無法繼續(xù)執(zhí)行下去。

4.生產(chǎn)者和消費(fèi)者模式(等待喚醒機(jī)制)

在Java中,生產(chǎn)者-消費(fèi)者模式是一種常見的多線程協(xié)作模式,用于解決生產(chǎn)者消費(fèi)者之間的數(shù)據(jù)交換和同步問題。

我們?cè)谝郧暗亩嗑€程中,會(huì)發(fā)現(xiàn)每條線程是都執(zhí)行都是隨機(jī)的,可能會(huì)是

A A A A B B A A B A?

而等待喚醒機(jī)制可以是線程的交替變得有規(guī)律,變?yōu)?/p>

A B A B A B A B A B A

生產(chǎn)者是生成數(shù)據(jù)的線程,而消費(fèi)者是消耗數(shù)據(jù)的線程。下面是對(duì)Java中生產(chǎn)者和消費(fèi)者的詳細(xì)介紹:【從零開始學(xué)習(xí)JAVA | 三十九篇】深入多線程,【從零開始學(xué)習(xí)JAVA】,學(xué)習(xí),java,開發(fā)語言

  1. 生產(chǎn)者:

    • 生產(chǎn)者負(fù)責(zé)生產(chǎn)數(shù)據(jù),并將其放入共享的緩沖區(qū)或隊(duì)列中,以供消費(fèi)者使用。
    • 生產(chǎn)者線程通常會(huì)循環(huán)執(zhí)行,生成數(shù)據(jù)并將其添加到緩沖區(qū)中。
    • 當(dāng)緩沖區(qū)已滿時(shí),生產(chǎn)者會(huì)等待,直到有足夠的空間來存放新的數(shù)據(jù)。
  2. 消費(fèi)者:

    • 消費(fèi)者負(fù)責(zé)從緩沖區(qū)中獲取數(shù)據(jù),并進(jìn)行消費(fèi)或處理。
    • 消費(fèi)者線程通常會(huì)循環(huán)執(zhí)行,從緩沖區(qū)中取出數(shù)據(jù)并進(jìn)行相應(yīng)的處理操作。
    • 當(dāng)緩沖區(qū)為空時(shí),消費(fèi)者會(huì)等待,直到有新的數(shù)據(jù)可供消費(fèi)。
  3. 共享緩沖區(qū):

    • 生產(chǎn)者和消費(fèi)者之間的數(shù)據(jù)交換通常通過共享的緩沖區(qū)或隊(duì)列來進(jìn)行。
    • 緩沖區(qū)可以是一個(gè)數(shù)組、一個(gè)隊(duì)列或其他數(shù)據(jù)結(jié)構(gòu),用來存放生產(chǎn)者生成的數(shù)據(jù),供消費(fèi)者取出。
    • 緩沖區(qū)的大小是有限的,當(dāng)緩沖區(qū)已滿時(shí),生產(chǎn)者必須等待;當(dāng)緩沖區(qū)為空時(shí),消費(fèi)者必須等待。
    • 生產(chǎn)者將數(shù)據(jù)添加到緩沖區(qū)的末尾,而消費(fèi)者從緩沖區(qū)的前端消費(fèi)數(shù)據(jù)。

為了實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者模式,可以使用以下方法之一:

  1. wait() 和 notify():

    • 使用對(duì)象的 wait() 和 notify() 方法來實(shí)現(xiàn)線程的等待和喚醒操作。
    • 生產(chǎn)者在緩沖區(qū)已滿時(shí)調(diào)用 wait() 方法進(jìn)行等待,并在生產(chǎn)數(shù)據(jù)后調(diào)用 notify() 方法喚醒消費(fèi)者。
    • 消費(fèi)者在緩沖區(qū)為空時(shí)調(diào)用 wait() 方法進(jìn)行等待,并在消費(fèi)數(shù)據(jù)后調(diào)用 notify() 方法喚醒生產(chǎn)者。
  2. Condition 和 Lock:

    • 使用?java.util.concurrent.locks.Condition?和?java.util.concurrent.locks.Lock?接口來實(shí)現(xiàn)線程的等待和喚醒操作。
    • 生產(chǎn)者和消費(fèi)者分別使用不同的條件變量來等待和喚醒。
    • 使用Lock對(duì)象來保護(hù)共享數(shù)據(jù)的訪問,通過條件變量的?await()?和?signal()?方法進(jìn)行線程的等待和喚醒操作。

生產(chǎn)者-消費(fèi)者模式可以幫助解決多線程并發(fā)情況下的數(shù)據(jù)同步和數(shù)據(jù)交換問題,確保生產(chǎn)者和消費(fèi)者之間的協(xié)調(diào)運(yùn)行。這種模式在許多并發(fā)編程場景中都有應(yīng)用,如線程池、消息隊(duì)列、生產(chǎn)者-消費(fèi)者問題等。

生產(chǎn)者與消費(fèi)者模式的意義:

  1. 解耦生產(chǎn)者和消費(fèi)者:

    • 生產(chǎn)者-消費(fèi)者模式將數(shù)據(jù)的生產(chǎn)和消費(fèi)過程解耦,使得生產(chǎn)者和消費(fèi)者可以獨(dú)立進(jìn)行操作。
    • 生產(chǎn)者只需關(guān)注生成數(shù)據(jù)并將其放入緩沖區(qū),而不需要關(guān)心數(shù)據(jù)如何被消費(fèi)。
    • 消費(fèi)者只需關(guān)注從緩沖區(qū)中獲取數(shù)據(jù)并進(jìn)行相應(yīng)處理,而不需要關(guān)心數(shù)據(jù)的生成過程。
  2. 提高系統(tǒng)的并發(fā)性和吞吐量:

    • 生產(chǎn)者和消費(fèi)者可以并行地執(zhí)行,從而提高系統(tǒng)的并發(fā)性能。
    • 生產(chǎn)者不必等待消費(fèi)者完成對(duì)數(shù)據(jù)的處理,而可以繼續(xù)生產(chǎn)新的數(shù)據(jù)。
    • 消費(fèi)者不必等待生產(chǎn)者生成新的數(shù)據(jù),而可以并行地處理已有的數(shù)據(jù)。
  3. 緩沖區(qū)平衡生產(chǎn)和消費(fèi)速度:

    • 生產(chǎn)者和消費(fèi)者之間通過共享的緩沖區(qū)進(jìn)行數(shù)據(jù)交換和同步。
    • 緩沖區(qū)充當(dāng)了生產(chǎn)者和消費(fèi)者之間的中介,平衡了它們之間的生產(chǎn)和消費(fèi)速度。
    • 當(dāng)生產(chǎn)者速度快于消費(fèi)者時(shí),數(shù)據(jù)會(huì)被存儲(chǔ)在緩沖區(qū)中,以供消費(fèi)者使用。
    • 當(dāng)消費(fèi)者速度快于生產(chǎn)者時(shí),消費(fèi)者可以從緩沖區(qū)中獲取數(shù)據(jù),而不必等待生產(chǎn)者生成。
  4. 實(shí)現(xiàn)線程間的通信和同步:

    • 生產(chǎn)者-消費(fèi)者模式為線程間的通信和同步提供了一種有效的方式。
    • 生產(chǎn)者和消費(fèi)者可以利用等待和喚醒機(jī)制來實(shí)現(xiàn)線程的同步和協(xié)作。
    • 生產(chǎn)者在緩沖區(qū)已滿時(shí)等待,直到有可用空間;消費(fèi)者在緩沖區(qū)為空時(shí)等待,直到有可供消費(fèi)的數(shù)據(jù)。
    • 當(dāng)生產(chǎn)者生成新的數(shù)據(jù)或消費(fèi)者消耗了數(shù)據(jù)時(shí),它們可以相互通知和喚醒對(duì)方。

綜上所述,生產(chǎn)者-消費(fèi)者模式是一種重要的多線程編程模式,它能夠提高系統(tǒng)的并發(fā)性、吞吐量和效率,實(shí)現(xiàn)生產(chǎn)者和消費(fèi)者之間的解耦和協(xié)作,確保數(shù)據(jù)交換和同步的正確性和可靠性。在并發(fā)編程和異步系統(tǒng)中廣泛應(yīng)用。

import java.util.LinkedList;

class Producer implements Runnable {
    private LinkedList<Integer> buffer;
    private int maxSize;
    
    public Producer(LinkedList<Integer> buffer, int maxSize) {
        this.buffer = buffer;
        this.maxSize = maxSize;
    }
    
    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            try {
                produce(i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    private void produce(int value) throws InterruptedException {
        synchronized (buffer) {
            while (buffer.size() == maxSize) {
                System.out.println("緩沖區(qū)已滿,生產(chǎn)者等待...");
                buffer.wait();
            }
            
            buffer.add(value);
            System.out.println("生產(chǎn)者生產(chǎn): " + value);
            
            buffer.notifyAll();
        }
    }
}

class Consumer implements Runnable {
    private LinkedList<Integer> buffer;
    
    public Consumer(LinkedList<Integer> buffer) {
        this.buffer = buffer;
    }
    
    @Override
    public void run() {
        while (true) {
            try {
                consume();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    private void consume() throws InterruptedException {
        synchronized (buffer) {
            while (buffer.size() == 0) {
                System.out.println("緩沖區(qū)為空,消費(fèi)者等待...");
                buffer.wait();
            }
            
            int value = buffer.removeFirst();
            System.out.println("消費(fèi)者消費(fèi): " + value);
            
            buffer.notifyAll();
        }
    }
}

public class ProducerConsumerExample {
    public static void main(String[] args) {
        LinkedList<Integer> buffer = new LinkedList<>();
        int maxSize = 5;
        
        Producer producer = new Producer(buffer, maxSize);
        Consumer consumer = new Consumer(buffer);
        
        Thread producerThread = new Thread(producer);
        Thread consumerThread = new Thread(consumer);
        
        producerThread.start();
        consumerThread.start();
    }
}

這個(gè)示例中,生產(chǎn)者線程通過?produce()?方法在?buffer?中生產(chǎn)數(shù)據(jù),而消費(fèi)者線程通過?consume()?方法從?buffer?中消費(fèi)數(shù)據(jù)。其中,buffer?是一個(gè)共享的緩沖區(qū),采用了等待和喚醒機(jī)制來實(shí)現(xiàn)線程的同步。

注意,在示例中使用了?LinkedList?作為緩沖區(qū),但這只是一種示例使用的數(shù)據(jù)結(jié)構(gòu),實(shí)際上可以使用其他線程安全的數(shù)據(jù)結(jié)構(gòu),如?ArrayBlockingQueue?或?LinkedBlockingQueue?來實(shí)現(xiàn)更高效的生產(chǎn)者-消費(fèi)者模式。

運(yùn)行代碼示例后,你可以觀察到生產(chǎn)者逐個(gè)生成數(shù)據(jù)并放入緩沖區(qū),而消費(fèi)者逐個(gè)從緩沖區(qū)中取出數(shù)據(jù)消費(fèi),它們之間的執(zhí)行是交替進(jìn)行的。當(dāng)緩沖區(qū)已滿時(shí),生產(chǎn)者線程會(huì)等待;當(dāng)緩沖區(qū)為空時(shí),消費(fèi)者線程會(huì)等待。這樣,生產(chǎn)者和消費(fèi)者之間的數(shù)據(jù)交換和同步就實(shí)現(xiàn)了。

總結(jié):

? ? ? ? 今天我們學(xué)習(xí)了多線程中必要有意思的壽命周期,鎖以及一個(gè)多線程的經(jīng)典模式:生產(chǎn)者和消費(fèi)者模式。多線程作為一項(xiàng)處理高并發(fā)和高吞吐量的重要技術(shù),其各項(xiàng)知識(shí)點(diǎn)我們都應(yīng)該擁有較好的掌握程度,這樣才可以熟練的使用多線程。

如果我的內(nèi)容對(duì)你有幫助,請(qǐng)點(diǎn)贊,評(píng)論,收藏。創(chuàng)作不易,大家的支持就是我堅(jiān)持下去的動(dòng)力!

【從零開始學(xué)習(xí)JAVA | 三十九篇】深入多線程,【從零開始學(xué)習(xí)JAVA】,學(xué)習(xí),java,開發(fā)語言文章來源地址http://www.zghlxwxcb.cn/news/detail-641203.html

到了這里,關(guān)于【從零開始學(xué)習(xí)JAVA | 三十九篇】深入多線程的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 從零開始學(xué)習(xí) Java:簡單易懂的入門指南之線程池(三十六)

    從零開始學(xué)習(xí) Java:簡單易懂的入門指南之線程池(三十六)

    當(dāng)線程被創(chuàng)建并啟動(dòng)以后,它既不是一啟動(dòng)就進(jìn)入了執(zhí)行狀態(tài),也不是一直處于執(zhí)行狀態(tài)。線程對(duì)象在不同的時(shí)期有不同的狀態(tài)。那么Java中的線程存在哪幾種狀態(tài)呢?Java中的線程 狀態(tài)被定義在了java.lang.Thread.State枚舉類中,State枚舉類的源碼如下: 通過源碼我們可以看到Ja

    2024年02月08日
    瀏覽(90)
  • 從零開始學(xué)習(xí) Java:簡單易懂的入門指南之線程同步(三十五)

    從零開始學(xué)習(xí) Java:簡單易懂的入門指南之線程同步(三十五)

    1.1賣票【應(yīng)用】 案例需求 某電影院目前正在上映國產(chǎn)大片,共有100張票,而它有3個(gè)窗口賣票,請(qǐng)?jiān)O(shè)計(jì)一個(gè)程序模擬該電影院賣票 實(shí)現(xiàn)步驟 定義一個(gè)類SellTicket實(shí)現(xiàn)Runnable接口,里面定義一個(gè)成員變量:private int tickets = 100; 在SellTicket類中重寫run()方法實(shí)現(xiàn)賣票,代碼步驟如下

    2024年02月08日
    瀏覽(91)
  • 從零開始學(xué)習(xí) Java:簡單易懂的入門指南之多線程(三十四)

    從零開始學(xué)習(xí) Java:簡單易懂的入門指南之多線程(三十四)

    1.1簡單了解多線程 是指從軟件或者硬件上實(shí)現(xiàn)多個(gè)線程并發(fā)執(zhí)行的技術(shù)。 具有多線程能力的計(jì)算機(jī)因有硬件支持而能夠在同一時(shí)間執(zhí)行多個(gè)線程,提升性能。 1.2并發(fā)和并行 并行:在同一時(shí)刻,有多個(gè)指令在多個(gè)CPU上同時(shí)執(zhí)行。 并發(fā):在同一時(shí)刻,有多個(gè)指令在單個(gè)CPU上交

    2024年02月08日
    瀏覽(156)
  • 【從零開始學(xué)習(xí)JAVA | 第三十篇】方法引用

    【從零開始學(xué)習(xí)JAVA | 第三十篇】方法引用

    目錄 前言: 方法引用: 方法引用基本概念: 方法可以被引用的條件: 方法引用的種類: 方法引用的優(yōu)點(diǎn): 總結(jié): 方法引用作為一個(gè)重要的知識(shí)點(diǎn),雖然他使用起來很復(fù)雜,而且會(huì)降低代碼的可讀性,但是如果用好了方法引用,我們也會(huì)獲得不錯(cuò)的效率,因此我們?cè)诮裉?/p>

    2024年02月15日
    瀏覽(92)
  • 【從零開始學(xué)習(xí)JAVA | 三十四篇】IO流

    【從零開始學(xué)習(xí)JAVA | 三十四篇】IO流

    目錄 前言: IO流介紹: IO流的常見方法: 1.字節(jié)流類: 2.字符流類: 總結(jié): ? ? ? ? ? ? ? ? IO流就是存入和讀取數(shù)據(jù)的解決方案,并且他是一個(gè)知識(shí)點(diǎn)很多的章節(jié),因此我們關(guān)于IO流的介紹會(huì)分為多篇來進(jìn)行詳解,而掌握好IO流可以大大提高我們的效率,簡化我們的代碼執(zhí)

    2024年02月13日
    瀏覽(503)
  • 【從零開始學(xué)習(xí)JAVA | 第三十一篇】異常體系介紹

    【從零開始學(xué)習(xí)JAVA | 第三十一篇】異常體系介紹

    ? ? ? ? 本文我們將為大家介紹一下異常的整個(gè)體系,而我們學(xué)習(xí)異常,不是為了敲代碼的時(shí)候不出異常,而是為了能夠熟練的處理異常,如何解決代碼中的異常。 ?我們就以這張圖作為線索來詳細(xì)介紹一下Java中的異常: 在Java中, Exception(異常)是一種表示非致命錯(cuò)誤或異

    2024年02月15日
    瀏覽(90)
  • 【從零開始學(xué)習(xí)JAVA | 第三十三篇】File類

    【從零開始學(xué)習(xí)JAVA | 第三十三篇】File類

    目錄 前言: File類: 構(gòu)造方法: 常見成員方法: 總結(jié): ? ? ? ? 本文我們將為大家介紹JAVA中一個(gè)比較使用的類:File類,他為我們提供了存儲(chǔ)數(shù)據(jù)的功能,使得程序的數(shù)據(jù)不至于在運(yùn)行結(jié)束之后就丟失,是一個(gè)很好的類。 ????????File類是Java標(biāo)準(zhǔn)庫中用于操作文件和目錄

    2024年02月15日
    瀏覽(96)
  • 從零開始學(xué)習(xí) Java:簡單易懂的入門指南之包裝類(十九)

    Java提供了兩個(gè)類型系統(tǒng),基本類型與引用類型,使用基本類型在于效率,然而很多情況,會(huì)創(chuàng)建對(duì)象使用,因?yàn)閷?duì)象可以做更多的功能,如果想要我們的基本類型像對(duì)象一樣操作,就可以使用基本類型對(duì)應(yīng)的包裝類,如下: 基本類型 對(duì)應(yīng)的包裝類(位于java.lang包中) byte

    2024年02月11日
    瀏覽(100)
  • 【從零開始學(xué)習(xí)JAVA | 第三十二篇】 異常(下)新手必學(xué)!

    【從零開始學(xué)習(xí)JAVA | 第三十二篇】 異常(下)新手必學(xué)!

    目錄 前言: ?Exceptions(異常): 異常的兩大作用: 異常的處理方式: 1.JVM默認(rèn)處理 ?2.自己捕獲異常 3.拋出處理 自定義異常: 異常的優(yōu)點(diǎn): 總結(jié): ? ? ? ? 前文我們?cè)敿?xì)的為大家介紹了整個(gè)異常體系的框架,本篇我們將為大家介紹 Exceptions 異常,我們會(huì)講解他的作用以及

    2024年02月15日
    瀏覽(123)
  • 【從零開始學(xué)習(xí)JAVA | 第三十五篇】IO流綜合練習(xí)

    【從零開始學(xué)習(xí)JAVA | 第三十五篇】IO流綜合練習(xí)

    目錄 前言: 1.拷貝文件(含子文件) 思路: 2.文件加密 思路: 3.修改文件中的數(shù)據(jù): 思路: 總結(jié): ? ? ? ? 在前面我們?yōu)榇蠹医榻B了FILE類和IO類。這篇文章我們來練習(xí)一些綜合使用的例子以此來鞏固我們自己的所學(xué)知識(shí)。 建立一個(gè)讀文件的流來讀取文件,一個(gè)寫文件的流

    2024年02月14日
    瀏覽(86)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包