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

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

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

1.線程同步

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)賣票,代碼步驟如下

    • 判斷票數(shù)大于0,就賣票,并告知是哪個(gè)窗口賣的

    • 賣了票之后,總票數(shù)要減1

    • 票賣沒了,線程停止

    • 定義一個(gè)測試類SellTicketDemo,里面有main方法,代碼步驟如下

    • 創(chuàng)建SellTicket類的對(duì)象

    • 創(chuàng)建三個(gè)Thread類的對(duì)象,把SellTicket對(duì)象作為構(gòu)造方法的參數(shù),并給出對(duì)應(yīng)的窗口名稱

    • 啟動(dòng)線程

  • 代碼實(shí)現(xiàn)

    public class SellTicket implements Runnable {
        private int tickets = 100;
        //在SellTicket類中重寫run()方法實(shí)現(xiàn)賣票,代碼步驟如下
        @Override
        public void run() {
            while (true) {
                if(ticket <= 0){
                        //賣完了
                        break;
                    }else{
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        ticket--;
                        System.out.println(Thread.currentThread().getName() + "在賣票,還剩下" + ticket + "張票");
                    }
            }
        }
    }
    public class SellTicketDemo {
        public static void main(String[] args) {
            //創(chuàng)建SellTicket類的對(duì)象
            SellTicket st = new SellTicket();
    
            //創(chuàng)建三個(gè)Thread類的對(duì)象,把SellTicket對(duì)象作為構(gòu)造方法的參數(shù),并給出對(duì)應(yīng)的窗口名稱
            Thread t1 = new Thread(st,"窗口1");
            Thread t2 = new Thread(st,"窗口2");
            Thread t3 = new Thread(st,"窗口3");
    
            //啟動(dòng)線程
            t1.start();
            t2.start();
            t3.start();
        }
    }
    

1.2賣票案例的問題

  • 賣票出現(xiàn)了問題

    • 相同的票出現(xiàn)了多次

    • 出現(xiàn)了負(fù)數(shù)的票

  • 問題產(chǎn)生原因

    線程執(zhí)行的隨機(jī)性導(dǎo)致的,可能在賣票過程中丟失cpu的執(zhí)行權(quán),導(dǎo)致出現(xiàn)問題

1.3同步代碼塊解決數(shù)據(jù)安全問題【應(yīng)用】

  • 安全問題出現(xiàn)的條件

    • 是多線程環(huán)境

    • 有共享數(shù)據(jù)

    • 有多條語句操作共享數(shù)據(jù)

  • 如何解決多線程安全問題呢?

    • 基本思想:讓程序沒有安全問題的環(huán)境
  • 怎么實(shí)現(xiàn)呢?

    • 把多條語句操作共享數(shù)據(jù)的代碼給鎖起來,讓任意時(shí)刻只能有一個(gè)線程執(zhí)行即可

    • Java提供了同步代碼塊的方式來解決

  • 同步代碼塊格式:

    synchronized(任意對(duì)象) { 
    	多條語句操作共享數(shù)據(jù)的代碼 
    }
    

    synchronized(任意對(duì)象):就相當(dāng)于給代碼加鎖了,任意對(duì)象就可以看成是一把鎖

  • 同步的好處和弊端

    • 好處:解決了多線程的數(shù)據(jù)安全問題

    • 弊端:當(dāng)線程很多時(shí),因?yàn)槊總€(gè)線程都會(huì)去判斷同步上的鎖,這是很耗費(fèi)資源的,無形中會(huì)降低程序的運(yùn)行效率

  • 代碼演示

    public class SellTicket implements Runnable {
        private int tickets = 100;
        private Object obj = new Object();
    
        @Override
        public void run() {
            while (true) {
                synchronized (obj) { // 對(duì)可能有安全問題的代碼加鎖,多個(gè)線程必須使用同一把鎖
                    //t1進(jìn)來后,就會(huì)把這段代碼給鎖起來
                    if (tickets > 0) {
                        try {
                            Thread.sleep(100);
                            //t1休息100毫秒
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //窗口1正在出售第100張票
                        System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "張票");
                        tickets--; //tickets = 99;
                    }
                }
                //t1出來了,這段代碼的鎖就被釋放了
            }
        }
    }
    
    public class SellTicketDemo {
        public static void main(String[] args) {
            SellTicket st = new SellTicket();
    
            Thread t1 = new Thread(st, "窗口1");
            Thread t2 = new Thread(st, "窗口2");
            Thread t3 = new Thread(st, "窗口3");
    
            t1.start();
            t2.start();
            t3.start();
        }
    }
    

1.4同步方法解決數(shù)據(jù)安全問題【應(yīng)用】

  • 同步方法的格式

    同步方法:就是把synchronized關(guān)鍵字加到方法上

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

    同步方法的鎖對(duì)象是什么呢?

    ? this

  • 靜態(tài)同步方法

    同步靜態(tài)方法:就是把synchronized關(guān)鍵字加到靜態(tài)方法上

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

    同步靜態(tài)方法的鎖對(duì)象是什么呢?

    ? 類名.class

  • 代碼演示

    public class MyRunnable implements Runnable {
        private static int ticketCount = 100;
    
        @Override
        public void run() {
            while(true){
                if("窗口一".equals(Thread.currentThread().getName())){
                    //同步方法
                    boolean result = synchronizedMthod();
                    if(result){
                        break;
                    }
                }
    
                if("窗口二".equals(Thread.currentThread().getName())){
                    //同步代碼塊
                    synchronized (MyRunnable.class){
                        if(ticketCount == 0){
                           break;
                        }else{
                            try {
                                Thread.sleep(10);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            ticketCount--;
                            System.out.println(Thread.currentThread().getName() + "在賣票,還剩下" + ticketCount + "張票");
                        }
                    }
                }
    
            }
        }
    
        private static synchronized boolean synchronizedMthod() {
            if(ticketCount == 0){
                return true;
            }else{
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                ticketCount--;
                System.out.println(Thread.currentThread().getName() + "在賣票,還剩下" + ticketCount + "張票");
                return false;
            }
        }
    }
    
  public class Demo {
      public static void main(String[] args) {
          MyRunnable mr = new MyRunnable();

          Thread t1 = new Thread(mr);
          Thread t2 = new Thread(mr);
    
          t1.setName("窗口一");
          t2.setName("窗口二");
    
          t1.start();
          t2.start();
      }

  }

1.5Lock鎖【應(yīng)用】

雖然我們可以理解同步代碼塊和同步方法的鎖對(duì)象問題,但是我們并沒有直接看到在哪里加上了鎖,在哪里釋放了鎖,為了更清晰的表達(dá)如何加鎖和釋放鎖,JDK5以后提供了一個(gè)新的鎖對(duì)象Lock

Lock是接口不能直接實(shí)例化,這里采用它的實(shí)現(xiàn)類ReentrantLock來實(shí)例化

  • ReentrantLock構(gòu)造方法

    方法名 說明
    ReentrantLock() 創(chuàng)建一個(gè)ReentrantLock的實(shí)例
  • 加鎖解鎖方法

    方法名 說明
    void lock() 獲得鎖
    void unlock() 釋放鎖
  • 代碼演示

    public class Ticket implements Runnable {
        //票的數(shù)量
        private int ticket = 100;
        private Object obj = new Object();
        private ReentrantLock lock = new ReentrantLock();
    
        @Override
        public void run() {
            while (true) {
                //synchronized (obj){//多個(gè)線程必須使用同一把鎖.
                try {
                    lock.lock();
                    if (ticket <= 0) {
                        //賣完了
                        break;
                    } else {
                        Thread.sleep(100);
                        ticket--;
                        System.out.println(Thread.currentThread().getName() + "在賣票,還剩下" + ticket + "張票");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
                // }
            }
        }
    }
    
    public class Demo {
        public static void main(String[] args) {
            Ticket ticket = new Ticket();
    
            Thread t1 = new Thread(ticket);
            Thread t2 = new Thread(ticket);
            Thread t3 = new Thread(ticket);
    
            t1.setName("窗口一");
            t2.setName("窗口二");
            t3.setName("窗口三");
    
            t1.start();
            t2.start();
            t3.start();
        }
    }
    

1.6死鎖

  • 概述

    線程死鎖是指由于兩個(gè)或者多個(gè)線程互相持有對(duì)方所需要的資源,導(dǎo)致這些線程處于等待狀態(tài),無法前往執(zhí)行

  • 什么情況下會(huì)產(chǎn)生死鎖

    1. 資源有限
    2. 同步嵌套
  • 代碼演示

    public class Demo {
        public static void main(String[] args) {
            Object objA = new Object();
            Object objB = new Object();
    
            new Thread(()->{
                while(true){
                    synchronized (objA){
                        //線程一
                        synchronized (objB){
                            System.out.println("小康同學(xué)正在走路");
                        }
                    }
                }
            }).start();
    
            new Thread(()->{
                while(true){
                    synchronized (objB){
                        //線程二
                        synchronized (objA){
                            System.out.println("小薇同學(xué)正在走路");
                        }
                    }
                }
            }).start();
        }
    }
    

2.生產(chǎn)者消費(fèi)者

2.1生產(chǎn)者和消費(fèi)者模式概述【應(yīng)用】

  • 概述

    生產(chǎn)者消費(fèi)者模式是一個(gè)十分經(jīng)典的多線程協(xié)作的模式,弄懂生產(chǎn)者消費(fèi)者問題能夠讓我們對(duì)多線程編程的理解更加深刻。

    所謂生產(chǎn)者消費(fèi)者問題,實(shí)際上主要是包含了兩類線程:

    ? 一類是生產(chǎn)者線程用于生產(chǎn)數(shù)據(jù)

    ? 一類是消費(fèi)者線程用于消費(fèi)數(shù)據(jù)

    為了解耦生產(chǎn)者和消費(fèi)者的關(guān)系,通常會(huì)采用共享的數(shù)據(jù)區(qū)域,就像是一個(gè)倉庫

    生產(chǎn)者生產(chǎn)數(shù)據(jù)之后直接放置在共享數(shù)據(jù)區(qū)中,并不需要關(guān)心消費(fèi)者的行為

    消費(fèi)者只需要從共享數(shù)據(jù)區(qū)中去獲取數(shù)據(jù),并不需要關(guān)心生產(chǎn)者的行為

  • Object類的等待和喚醒方法

    方法名 說明
    void wait() 導(dǎo)致當(dāng)前線程等待,直到另一個(gè)線程調(diào)用該對(duì)象的 notify()方法或 notifyAll()方法
    void notify() 喚醒正在等待對(duì)象監(jiān)視器的單個(gè)線程
    void notifyAll() 喚醒正在等待對(duì)象監(jiān)視器的所有線程

2.2生產(chǎn)者和消費(fèi)者案例【應(yīng)用】

  • 案例需求

    • 桌子類(Desk):定義表示包子數(shù)量的變量,定義鎖對(duì)象變量,定義標(biāo)記桌子上有無包子的變量

    • 生產(chǎn)者類(Cooker):實(shí)現(xiàn)Runnable接口,重寫run()方法,設(shè)置線程任務(wù)

      1.判斷是否有包子,決定當(dāng)前線程是否執(zhí)行

      2.如果有包子,就進(jìn)入等待狀態(tài),如果沒有包子,繼續(xù)執(zhí)行,生產(chǎn)包子

      3.生產(chǎn)包子之后,更新桌子上包子狀態(tài),喚醒消費(fèi)者消費(fèi)包子

    • 消費(fèi)者類(Foodie):實(shí)現(xiàn)Runnable接口,重寫run()方法,設(shè)置線程任務(wù)

      1.判斷是否有包子,決定當(dāng)前線程是否執(zhí)行

      2.如果沒有包子,就進(jìn)入等待狀態(tài),如果有包子,就消費(fèi)包子

      3.消費(fèi)包子后,更新桌子上包子狀態(tài),喚醒生產(chǎn)者生產(chǎn)包子

    • 測試類(Demo):里面有main方法,main方法中的代碼步驟如下

      創(chuàng)建生產(chǎn)者線程和消費(fèi)者線程對(duì)象

      分別開啟兩個(gè)線程

  • 代碼實(shí)現(xiàn)

    public class Desk {
    
        //定義一個(gè)標(biāo)記
        //true 就表示桌子上有漢堡包的,此時(shí)允許吃貨執(zhí)行
        //false 就表示桌子上沒有漢堡包的,此時(shí)允許廚師執(zhí)行
        public static boolean flag = false;
    
        //漢堡包的總數(shù)量
        public static int count = 10;
    
        //鎖對(duì)象
        public static final Object lock = new Object();
    }
    
    public class Cooker extends Thread {
    //    生產(chǎn)者步驟:
    //            1,判斷桌子上是否有漢堡包
    //    如果有就等待,如果沒有才生產(chǎn)。
    //            2,把漢堡包放在桌子上。
    //            3,叫醒等待的消費(fèi)者開吃。
        @Override
        public void run() {
            while(true){
                synchronized (Desk.lock){
                    if(Desk.count == 0){
                        break;
                    }else{
                        if(!Desk.flag){
                            //生產(chǎn)
                            System.out.println("廚師正在生產(chǎn)漢堡包");
                            Desk.flag = true;
                            Desk.lock.notifyAll();
                        }else{
                            try {
                                Desk.lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
    }
    
    public class Foodie extends Thread {
        @Override
        public void run() {
    //        1,判斷桌子上是否有漢堡包。
    //        2,如果沒有就等待。
    //        3,如果有就開吃
    //        4,吃完之后,桌子上的漢堡包就沒有了
    //                叫醒等待的生產(chǎn)者繼續(xù)生產(chǎn)
    //        漢堡包的總數(shù)量減一
    
            //套路:
                //1. while(true)死循環(huán)
                //2. synchronized 鎖,鎖對(duì)象要唯一
                //3. 判斷,共享數(shù)據(jù)是否結(jié)束. 結(jié)束
                //4. 判斷,共享數(shù)據(jù)是否結(jié)束. 沒有結(jié)束
            while(true){
                synchronized (Desk.lock){
                    if(Desk.count == 0){
                        break;
                    }else{
                        if(Desk.flag){
                            //有
                            System.out.println("吃貨在吃漢堡包");
                            Desk.flag = false;
                            Desk.lock.notifyAll();
                            Desk.count--;
                        }else{
                            //沒有就等待
                            //使用什么對(duì)象當(dāng)做鎖,那么就必須用這個(gè)對(duì)象去調(diào)用等待和喚醒的方法.
                            try {
                                Desk.lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
    
        }
    }
    
    public class Demo {
        public static void main(String[] args) {
            /*消費(fèi)者步驟:
            1,判斷桌子上是否有漢堡包。
            2,如果沒有就等待。
            3,如果有就開吃
            4,吃完之后,桌子上的漢堡包就沒有了
                    叫醒等待的生產(chǎn)者繼續(xù)生產(chǎn)
            漢堡包的總數(shù)量減一*/
    
            /*生產(chǎn)者步驟:
            1,判斷桌子上是否有漢堡包
            如果有就等待,如果沒有才生產(chǎn)。
            2,把漢堡包放在桌子上。
            3,叫醒等待的消費(fèi)者開吃。*/
    
            Foodie f = new Foodie();
            Cooker c = new Cooker();
    
            f.start();
            c.start();
    
        }
    }
    

2.3生產(chǎn)者和消費(fèi)者案例優(yōu)化【應(yīng)用】

  • 需求

    • 將Desk類中的變量,采用面向?qū)ο蟮姆绞椒庋b起來
    • 生產(chǎn)者和消費(fèi)者類中構(gòu)造方法接收Desk類對(duì)象,之后在run方法中進(jìn)行使用
    • 創(chuàng)建生產(chǎn)者和消費(fèi)者線程對(duì)象,構(gòu)造方法中傳入Desk類對(duì)象
    • 開啟兩個(gè)線程
  • 代碼實(shí)現(xiàn)

    public class Desk {
    
        //定義一個(gè)標(biāo)記
        //true 就表示桌子上有漢堡包的,此時(shí)允許吃貨執(zhí)行
        //false 就表示桌子上沒有漢堡包的,此時(shí)允許廚師執(zhí)行
        //public static boolean flag = false;
        private boolean flag;
    
        //漢堡包的總數(shù)量
        //public static int count = 10;
        //以后我們?cè)谑褂眠@種必須有默認(rèn)值的變量
       // private int count = 10;
        private int count;
    
        //鎖對(duì)象
        //public static final Object lock = new Object();
        private final Object lock = new Object();
    
        public Desk() {
            this(false,10); // 在空參內(nèi)部調(diào)用帶參,對(duì)成員變量進(jìn)行賦值,之后就可以直接使用成員變量了
        }
    
        public Desk(boolean flag, int count) {
            this.flag = flag;
            this.count = count;
        }
    
        public boolean isFlag() {
            return flag;
        }
    
        public void setFlag(boolean flag) {
            this.flag = flag;
        }
    
        public int getCount() {
            return count;
        }
    
        public void setCount(int count) {
            this.count = count;
        }
    
        public Object getLock() {
            return lock;
        }
    
        @Override
        public String toString() {
            return "Desk{" +
                    "flag=" + flag +
                    ", count=" + count +
                    ", lock=" + lock +
                    '}';
        }
    }
    
    public class Cooker extends Thread {
    
        private Desk desk;
    
        public Cooker(Desk desk) {
            this.desk = desk;
        }
    //    生產(chǎn)者步驟:
    //            1,判斷桌子上是否有漢堡包
    //    如果有就等待,如果沒有才生產(chǎn)。
    //            2,把漢堡包放在桌子上。
    //            3,叫醒等待的消費(fèi)者開吃。
    
        @Override
        public void run() {
            while(true){
                synchronized (desk.getLock()){
                    if(desk.getCount() == 0){
                        break;
                    }else{
                        //System.out.println("驗(yàn)證一下是否執(zhí)行了");
                        if(!desk.isFlag()){
                            //生產(chǎn)
                            System.out.println("廚師正在生產(chǎn)漢堡包");
                            desk.setFlag(true);
                            desk.getLock().notifyAll();
                        }else{
                            try {
                                desk.getLock().wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
    }
    
    public class Foodie extends Thread {
        private Desk desk;
    
        public Foodie(Desk desk) {
            this.desk = desk;
        }
    
        @Override
        public void run() {
    //        1,判斷桌子上是否有漢堡包。
    //        2,如果沒有就等待。
    //        3,如果有就開吃
    //        4,吃完之后,桌子上的漢堡包就沒有了
    //                叫醒等待的生產(chǎn)者繼續(xù)生產(chǎn)
    //        漢堡包的總數(shù)量減一
    
            //套路:
                //1. while(true)死循環(huán)
                //2. synchronized 鎖,鎖對(duì)象要唯一
                //3. 判斷,共享數(shù)據(jù)是否結(jié)束. 結(jié)束
                //4. 判斷,共享數(shù)據(jù)是否結(jié)束. 沒有結(jié)束
            while(true){
                synchronized (desk.getLock()){
                    if(desk.getCount() == 0){
                        break;
                    }else{
                        //System.out.println("驗(yàn)證一下是否執(zhí)行了");
                        if(desk.isFlag()){
                            //有
                            System.out.println("吃貨在吃漢堡包");
                            desk.setFlag(false);
                            desk.getLock().notifyAll();
                            desk.setCount(desk.getCount() - 1);
                        }else{
                            //沒有就等待
                            //使用什么對(duì)象當(dāng)做鎖,那么就必須用這個(gè)對(duì)象去調(diào)用等待和喚醒的方法.
                            try {
                                desk.getLock().wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
    
        }
    }
    
    public class Demo {
        public static void main(String[] args) {
            /*消費(fèi)者步驟:
            1,判斷桌子上是否有漢堡包。
            2,如果沒有就等待。
            3,如果有就開吃
            4,吃完之后,桌子上的漢堡包就沒有了
                    叫醒等待的生產(chǎn)者繼續(xù)生產(chǎn)
            漢堡包的總數(shù)量減一*/
    
            /*生產(chǎn)者步驟:
            1,判斷桌子上是否有漢堡包
            如果有就等待,如果沒有才生產(chǎn)。
            2,把漢堡包放在桌子上。
            3,叫醒等待的消費(fèi)者開吃。*/
    
            Desk desk = new Desk();
    
            Foodie f = new Foodie(desk);
            Cooker c = new Cooker(desk);
    
            f.start();
            c.start();
    
        }
    }
    

2.4阻塞隊(duì)列基本使用

  • 阻塞隊(duì)列繼承結(jié)構(gòu)

從零開始學(xué)習(xí) Java:簡單易懂的入門指南之線程同步(三十五),java基礎(chǔ),學(xué)習(xí),java,python,開發(fā)語言

  • 常見BlockingQueue:

    ArrayBlockingQueue: 底層是數(shù)組,有界

    LinkedBlockingQueue: 底層是鏈表,無界.但不是真正的無界,最大為int的最大值

  • BlockingQueue的核心方法:

    put(anObject): 將參數(shù)放入隊(duì)列,如果放不進(jìn)去會(huì)阻塞

    take(): 取出第一個(gè)數(shù)據(jù),取不到會(huì)阻塞

  • 代碼示例

    public class Demo02 {
        public static void main(String[] args) throws Exception {
            // 創(chuàng)建阻塞隊(duì)列的對(duì)象,容量為 1
            ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(1);
    
            // 存儲(chǔ)元素
            arrayBlockingQueue.put("漢堡包");
    
            // 取元素
            System.out.println(arrayBlockingQueue.take());
            System.out.println(arrayBlockingQueue.take()); // 取不到會(huì)阻塞
    
            System.out.println("程序結(jié)束了");
        }
    }
    

2.5阻塞隊(duì)列實(shí)現(xiàn)等待喚醒機(jī)制

  • 案例需求

    • 生產(chǎn)者類(Cooker):實(shí)現(xiàn)Runnable接口,重寫run()方法,設(shè)置線程任務(wù)

      1.構(gòu)造方法中接收一個(gè)阻塞隊(duì)列對(duì)象

      2.在run方法中循環(huán)向阻塞隊(duì)列中添加包子

      3.打印添加結(jié)果

    • 消費(fèi)者類(Foodie):實(shí)現(xiàn)Runnable接口,重寫run()方法,設(shè)置線程任務(wù)

      1.構(gòu)造方法中接收一個(gè)阻塞隊(duì)列對(duì)象

      2.在run方法中循環(huán)獲取阻塞隊(duì)列中的包子

      3.打印獲取結(jié)果

    • 測試類(Demo):里面有main方法,main方法中的代碼步驟如下

      創(chuàng)建阻塞隊(duì)列對(duì)象

      創(chuàng)建生產(chǎn)者線程和消費(fèi)者線程對(duì)象,構(gòu)造方法中傳入阻塞隊(duì)列對(duì)象

      分別開啟兩個(gè)線程

  • 代碼實(shí)現(xiàn)

    public class Cooker extends Thread {
    
        private ArrayBlockingQueue<String> bd;
    
        public Cooker(ArrayBlockingQueue<String> bd) {
            this.bd = bd;
        }
    //    生產(chǎn)者步驟:
    //            1,判斷桌子上是否有漢堡包
    //    如果有就等待,如果沒有才生產(chǎn)。
    //            2,把漢堡包放在桌子上。
    //            3,叫醒等待的消費(fèi)者開吃。
    
        @Override
        public void run() {
            while (true) {
                try {
                    bd.put("漢堡包");
                    System.out.println("廚師放入一個(gè)漢堡包");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    public class Foodie extends Thread {
        private ArrayBlockingQueue<String> bd;
    
        public Foodie(ArrayBlockingQueue<String> bd) {
            this.bd = bd;
        }
    
        @Override
        public void run() {
    //        1,判斷桌子上是否有漢堡包。
    //        2,如果沒有就等待。
    //        3,如果有就開吃
    //        4,吃完之后,桌子上的漢堡包就沒有了
    //                叫醒等待的生產(chǎn)者繼續(xù)生產(chǎn)
    //        漢堡包的總數(shù)量減一
    
            //套路:
            //1. while(true)死循環(huán)
            //2. synchronized 鎖,鎖對(duì)象要唯一
            //3. 判斷,共享數(shù)據(jù)是否結(jié)束. 結(jié)束
            //4. 判斷,共享數(shù)據(jù)是否結(jié)束. 沒有結(jié)束
            while (true) {
                try {
                    String take = bd.take();
                    System.out.println("吃貨將" + take + "拿出來吃了");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
        }
    }
    
    public class Demo {
        public static void main(String[] args) {
            ArrayBlockingQueue<String> bd = new ArrayBlockingQueue<>(1);
    
            Foodie f = new Foodie(bd);
            Cooker c = new Cooker(bd);
    
            f.start();
            c.start();
        }
    }
    

后記
????????美好的一天,到此結(jié)束,下次繼續(xù)努力!欲知后續(xù),請(qǐng)看下回分解,寫作不易,感謝大家的支持??! ??????
文章來源地址http://www.zghlxwxcb.cn/news/detail-713756.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)文章

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包