Java如何實(shí)現(xiàn)多線程、線程同步

這篇文章主要介紹了Java如何實(shí)現(xiàn)多線程、線程同步的相關(guān)知識,內(nèi)容詳細(xì)易懂,操作簡單快捷,具有一定借鑒價(jià)值,相信大家閱讀完這篇Java如何實(shí)現(xiàn)多線程、線程同步文章都會有所收獲,下面我們一起來看看吧。

超過10多年行業(yè)經(jīng)驗(yàn),技術(shù)領(lǐng)先,服務(wù)至上的經(jīng)營模式,全靠網(wǎng)絡(luò)和口碑獲得客戶,為自己降低成本,也就是為客戶降低成本。到目前業(yè)務(wù)范圍包括了:成都網(wǎng)站制作、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè),成都網(wǎng)站推廣,成都網(wǎng)站優(yōu)化,整體網(wǎng)絡(luò)托管,小程序制作,微信開發(fā),成都App制作,同時(shí)也可以讓客戶的網(wǎng)站和網(wǎng)絡(luò)營銷和我們一樣獲得訂單和生意!

Java如何實(shí)現(xiàn)多線程、線程同步

1 多線程

1.1 進(jìn)程

  • 進(jìn)程:是正在運(yùn)行的程序

    • 是系統(tǒng)進(jìn)行資源分配和調(diào)用的獨(dú)立單位

    • 每一個(gè)進(jìn)行都有它自己的內(nèi)存空間和系統(tǒng)資源

  • 進(jìn)程的三個(gè)特征

    • 獨(dú)立性:進(jìn)程與進(jìn)程之間是相互獨(dú)立的,彼此有自己獨(dú)立內(nèi)存區(qū)域

    • 動態(tài)性:進(jìn)程是運(yùn)行中的程序,要動態(tài)的占用內(nèi)存,CPU和網(wǎng)絡(luò)等資源

    • 并發(fā)性:CPU會分時(shí)輪詢切換依次為每個(gè)進(jìn)程服務(wù),因?yàn)榍袚Q的速度非常快,給我們的感覺像是在同時(shí)執(zhí)行,這就是并發(fā)性(并發(fā):同一時(shí)刻同時(shí)有多個(gè)在執(zhí)行)

1.2 線程

  • 線程:是進(jìn)程中的單個(gè)順序控制流,是一條執(zhí)行路徑

    • 單線程:一個(gè)進(jìn)程只有一條執(zhí)行路徑

    • 多線程:一個(gè)進(jìn)程有多條執(zhí)行路徑

1.3 多線程的實(shí)現(xiàn)方式

1.3.1 方式1:繼承Tread類
  • 流程

    • 1、定義一個(gè)MyTread類繼承Tread類

    • 2、在MyTread類中重寫run()方法

    • 3、創(chuàng)建MyTread類的對象

    • 4、啟動線程:void start()

  • 為什么要重寫run()方法?

    • 因?yàn)閞un()是用來封裝被線程執(zhí)行的代碼

  • run()方法和start()方法的區(qū)別?

    • run():封裝線程執(zhí)行的代碼,直接調(diào)用,相當(dāng)于普通方法的的調(diào)用

    • start():啟動線程,然后由JVM調(diào)用此線程中的run()方法

  • 范例

  • MyTread類:

package test;//1、定義一類MyTread繼承Tread類public class MyThread extends Thread{
    2、在MyTread類中重寫run()方法
    @Override
    public void run() {
        for(int i=0;i<100;i++) {
            System.out.println(i);
        }
    }}
  • 測試類

package test;public class Demo {
    public static void main(String[] args) {
        //3、創(chuàng)建MyTread類的對象
        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();

        //4、啟動線程:void start():啟動線程,由Java虛擬機(jī)調(diào)用此線程的run()方法
        my1.start();
        my2.start();
    }}
1.3.2 方式2:實(shí)現(xiàn)Runnable接口
  • 流程

    • 1、定義一個(gè)MyRunnable類實(shí)現(xiàn)Runnable接口

    • 2、在MyRunnable類中重寫run()方法

    • 3、創(chuàng)建MyRunnable類的對象

    • 4、創(chuàng)建Tread類的對象,把MyRunnable對象作為構(gòu)造方法的參數(shù)

    • 5、啟動線程

  • 好處:

    • 避免了Java單繼承的局限性

    • 適合多個(gè)相同程序的代碼取處理同一個(gè)資源的情況,把線程和程序的代碼、數(shù)據(jù)有效分離,較好地體現(xiàn)了面向?qū)ο蟮脑O(shè)計(jì)理論

package test;public class Demo {
    public static void main(String[] args) {
        //3、創(chuàng)建MyRunnable類的對象
        MyRunnable mr = new MyRunnable();

        //4、創(chuàng)建Tread類的對象,把MyRunnable對象作為構(gòu)造方法的參數(shù)//        Thread t1 = new Thread(mr);//        Thread t2 = new Thread(mr);
        //Thread(Runnable target,String name)
        Thread t1 = new Thread(mr,"高鐵");
        Thread t2 = new Thread(mr,"飛機(jī)");

        //5、啟動線程
        t1.start();
        t2.start();
    }}
1.3.3 方式3:實(shí)現(xiàn)Callable接口

1.4 設(shè)置和獲取線程名稱

  • Thread類中設(shè)置和獲取線程名稱的方法

方法名說明
void setName(Stringname)將此線程的名稱更改為等于參數(shù)name
String getName()返回此線程的名稱
public Thread(String name)通過構(gòu)造方法也可以設(shè)置線程名稱
public static Thread currentThread()返回對當(dāng)前正在執(zhí)行的線程對象的引用(可以返回main()方法中線程)
public static void sleep(long time)讓當(dāng)前線程休眠多少毫秒再繼續(xù)執(zhí)行
  • MyThread類

package test;public class MyThread extends Thread{
    //構(gòu)造方法添加線程名稱
    public MyThread(){}
    public MyThread(String name) {
        super(name);
    }
    
    @Override
    public void run() {
        for(int i=0;i<100;i++) {
            //1,String getName() 	返回此線程的名稱
            System.out.println(getName()+":"+i);
        }
    }}
  • 測試類

package test;public class Demo {
    public static void main(String[] args) {
        /*        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();

        //2,void setName(Stringname) 	將此線程的名稱更改為等于參數(shù)name
        my1.setName("高鐵");
        my2.setName("飛機(jī)");*/
        
        //3,通過構(gòu)造方法設(shè)置線程名稱
        //需要自己定義的類中提供此帶參構(gòu)造方法,并通過super訪問父類帶參構(gòu)造方法
        /*MyThread my1 = new MyThread("高鐵");
        MyThread my2 = new MyThread("飛機(jī)"); 

        my1.start();
        my2.start();*/
        
        //4,public static Thread currentThread() 	返回對當(dāng)前正在執(zhí)行的線程對象的引用(可以返回main()方法中線程)
        System.out.println(Tread.currentThread().getName()); //main
    }}

1.5 線程調(diào)度

  • 線程有兩種調(diào)度模型

    • 分時(shí)調(diào)度模型:所有線程輪流使用CPU的使用權(quán),平均分配每個(gè)線程占用CPU的時(shí)間片

    • 搶占式調(diào)度模型:優(yōu)先讓優(yōu)先級高的線程使用CPU,如果線程的優(yōu)先級相同,那么會隨機(jī)選擇一個(gè),優(yōu)先級高的線程獲取的CPU時(shí)間片相對多一些

  • Java使用的是搶占式調(diào)度模型

  • 假如計(jì)算機(jī)只有一個(gè)CPU, 那么CPU在某一個(gè)時(shí)刻只能執(zhí)行條指令, 線程只有得到CPU時(shí)間片,也就是使用權(quán),才可以執(zhí)行指令。所以說多線程程序的執(zhí)行是有隨機(jī)性,因?yàn)檎l搶到CPU的使用權(quán)是不一定的

  • Thread類中設(shè)置和獲取線程優(yōu)先級的方法

方法名說明
public final int getPriority() [pra????r?ti]返回此線程的優(yōu)先級
public final void setPriority(int newPriority)更改此線程的優(yōu)先級
  • 線程默認(rèn)優(yōu)先級是5;線程優(yōu)先級范圍是:1-10

  • 線程優(yōu)先級高僅僅表示線程獲取的CPU時(shí)間的幾率高,但是要在次數(shù)比較多,或者多次運(yùn)行的時(shí)候才能看到你想要的效果

package test;public class Demo {
    public static void main(String[] args) {

        ThreadPriority tp1 = new ThreadPriority();
        ThreadPriority tp2 = new ThreadPriority();
        ThreadPriority tp3 = new ThreadPriority();


        tp1.setName("高鐵");
        tp2.setName("飛機(jī)");
        tp3.setName("汽車");

        //1,public final int getPriority() [pra????r?ti] 	返回此線程的優(yōu)先級//        System.out.println(tp1.getPriority()); //5//        System.out.println(tp2.getPriority()); //5//        System.out.println(tp3.getPriority()); //5

        //2,public final void setPriority(int newPriority) 	更改此線程的優(yōu)先級
        System.out.println(Thread.MAX_PRIORITY); //10
        System.out.println(Thread.MIN_PRIORITY); //1
        System.out.println(Thread.NORM_PRIORITY); //5

        //設(shè)置正確優(yōu)先級
        tp1.setPriority(5);
        tp2.setPriority(10);
        tp3.setPriority(1);

        tp1.start();
        tp2.start();
        tp3.start();
    }}

1.6 線程控制

方法名說明
static void sleep(long millis)使當(dāng)前正在執(zhí)行的線程停留(暫停執(zhí)行)指定的毫秒數(shù)
void join()等待這個(gè)線程死亡
void setDaemon(boolean on) [?di?m?n]將此線程標(biāo)記為守護(hù)線程,當(dāng)運(yùn)行的線程都是守護(hù)線程時(shí),Java虛擬機(jī)很快將退出 (并不是立刻退出)

案例:sleep()方法

  • 線程類

package test;public class ThreadSleep extends Thread{
    @Override
    public void run() {
        for(int i=0;i<10;i++) {
            System.out.println(getName()+":"+i);
            //1,static void sleep(long millis) 	使當(dāng)前正在執(zhí)行的線程停留(暫停執(zhí)行)指定的毫秒數(shù)
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }}
  • 測試類

package test;public class Demo {
    public static void main(String[] args) {

        ThreadSleep ts1 = new ThreadSleep();
        ThreadSleep ts2 = new ThreadSleep();
        ThreadSleep ts3 = new ThreadSleep();


        ts1.setName("曹操");
        ts2.setName("劉備");
        ts3.setName("孫權(quán)");


        ts1.start();
        ts2.start();
        ts3.start();//        曹操:0//        孫權(quán):0//        劉備:0//        孫權(quán):1//        曹操:1//        劉備:1//        ...
    }}

案例:join()方法

package test;public class Demo {
    public static void main(String[] args) {

        ThreadJoin tj1 = new ThreadJoin();
        ThreadJoin tj2 = new ThreadJoin();
        ThreadJoin tj3 = new ThreadJoin();

        tj1.setName("康熙");
        tj2.setName("四阿哥");
        tj3.setName("八阿哥");

        tj1.start();
        //2,void join() 	等待這個(gè)線程死亡
        try {
            tj1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        tj2.start();
        tj3.start();//        康熙:0//        康熙:1//        康熙:2//        四阿哥:0//        四阿哥:1//        八阿哥:0//        八阿哥:1//        八阿哥:2//        四阿哥:2//        ...
    }}

案例:setDaemon()方法

package test;public class Demo {
    public static void main(String[] args) {

        ThreadJoin tj1 = new ThreadJoin();
        ThreadJoin tj2 = new ThreadJoin();
        ThreadJoin tj3 = new ThreadJoin();

        tj2.setName("關(guān)羽");
        tj3.setName("張飛");
        //設(shè)置主線程為劉備
        Thread.currentThread().setName("劉備");

        //3,void setDaemon(boolean on) 	將此線程標(biāo)記為守護(hù)線程,當(dāng)運(yùn)行的線程都是守護(hù)線程時(shí),Java虛擬機(jī)將退出
        tj1.setDaemon(true);
        tj2.setDaemon(true);

        tj1.start();
        tj2.start();

        for(int i=0;i<2;i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
        //劉備執(zhí)行完后,關(guān)羽和張飛會很快結(jié)束
    }}

1.7 線程生命周期

Java如何實(shí)現(xiàn)多線程、線程同步

1.8 數(shù)據(jù)安全問題之案例:買票

Java如何實(shí)現(xiàn)多線程、線程同步
Java如何實(shí)現(xiàn)多線程、線程同步

  • 為什么出現(xiàn)問題?(這也是我們判斷多線程程序是否會有數(shù)據(jù)安全問題的標(biāo)準(zhǔn))

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

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

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

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

  • 基本思想:讓程序沒有安全問題的環(huán)境

  • 怎么實(shí)現(xiàn)呢?

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

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

1.9 線程同步_同步代碼塊

  • 鎖多條語句操作共享數(shù)據(jù),可以使用同步代碼塊實(shí)現(xiàn)

  • 格式

synchronized(任意對象) {
	多條語句操作共享數(shù)據(jù)的代碼}
  • 好處:讓多個(gè)線程實(shí)現(xiàn)先后依次訪問共享資源,解決了多線程的數(shù)據(jù)安全問題

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

  • sellTicket類

package test;//1,定義一個(gè)類SellTicket實(shí)現(xiàn)Runnable接口,里面定義一個(gè)成員變量: private int tickets= 100;public class SellTicket implements Runnable{
    private int tickets = 100;
    private Object obj = new Object();

    //2,在ellTicket類中重寫run0方法實(shí)現(xiàn)賣票, 代碼步驟如下
    @Override
    public void run() {
        while(true) {
            //tickes=100
            //t1,t2,t3
            //假設(shè)t1搶到CPU執(zhí)行器
            synchronized (obj){
                //t1進(jìn)來后把代碼鎖起來了
                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出來了,鎖就被釋放了
            }
        }
    }}
  • 測試類

package test;public class SellTicketDemo {
    public static void main(String[] args) {
        //創(chuàng)建SellTicket類的對象
        SellTicket st = new SellTicket();

        //創(chuàng)建三個(gè)Thread類的對象,把SellTicket對象作為構(gòu)造方法的參數(shù),并給出對應(yīng)的窗口名稱
        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.10 線程同步_同步方法

  • 作用:把出現(xiàn)線程安全問題的核心方法給鎖起來,每次只能一個(gè)線程進(jìn)入訪問,其他線程必須在方法外面等待

  • 同步方法:就是把synchronized關(guān)鍵字加到方法上;鎖對象為:this

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

  • 同步靜態(tài)方法:就是把synchronized關(guān)鍵字加到靜態(tài)方法上面;鎖對象為:類名.class

    • 格式:修飾符 static synchronized 返回值類型 方法名(方法參數(shù)) {}

package test;public class SellTicket implements Runnable{//1非靜態(tài)    private int tickets = 100;
    private static int tickets = 100;
    private Object obj = new Object();
    private int x = 0;

    @Override
    public void run() {
        while(true) {
            if(x%2==0) {//1非靜態(tài)                synchronized (this) {
                synchronized (SellTicket.class) {
                    if (tickets > 0) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "張票");
                        tickets--; //tickets=99
                    }
                }
            } else {//                synchronized (obj) {//                    if (tickets > 0) {//                        try {//                            Thread.sleep(100);//                        } catch (InterruptedException e) {//                            e.printStackTrace();//                        }//                        System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "張票");//                        tickets--; //tickets=99//                    }//                }
                sellTicket();
            }
            x++;
        }
    }//1非靜態(tài)//    private synchronized void sellTicket() {//        if (tickets > 0) {//            try {//                Thread.sleep(100);//            } catch (InterruptedException e) {//                e.printStackTrace();//            }//            System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "張票");//            tickets--; //tickets=99//        }//    }

    private static synchronized void sellTicket() {
        if (tickets > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "張票");
            tickets--; //tickets=99
        }
    }}

1.11 線程安全的類(了解)

源碼中方法都被synchronized修飾

StringBuffer

  • 線程安全, 可變的字符序列

  • 從版本JDK 5開始,被StringBuilder替代。通常應(yīng)該使用StringBuilder類, 因?yàn)樗С炙邢嗤牟僮?但它更快,因?yàn)樗粓?zhí)行同步

Vector

  • 從Java 2平臺v1.2開始,該類改進(jìn)了List接口, 使其成為Java Collections Framework的成員。 與新的集合實(shí)現(xiàn)不同,Vector被同步。 如果不需要線程安全的實(shí)現(xiàn),建議使用ArrayList代替Vector

Hashtable

  • 該類實(shí)現(xiàn)了一個(gè)哈希表,它將鍵映射到值。任何非null對象都可以用作鍵或者值

  • 從Java 2平臺v1.2開始,該類進(jìn)行了改進(jìn),實(shí)現(xiàn)了Map接口,使其成為Java Collections Framework的成員。與新的集合實(shí)現(xiàn)不同,Hashtable被同步。 如果不需要線程安全的實(shí)現(xiàn),建議使用HashMap代替Hashtable

Collections類中static <T> List<T> snchronizedList(List<T> list):返回由指定列表支持的同步(線程安全)的列表

package test;import java.util.ArrayList;import java.util.Collection;import java.util.Collections;public class Demo {
    public static void main(String[] args)  {
        //static <T> List<T> snchronizedList(List<T> list):返回由指定列表支持的同步(線程安全)的列表
        Collection<String> list = Collections.synchronizedList(new ArrayList<String>());

        /*源碼都是返回Synchronized
        public static <T> List<T> synchronizedList(List<T> list) {
            return (list instanceof RandomAccess ?
                    new Collections.SynchronizedRandomAccessList<>(list) :
                    new Collections.SynchronizedList<>(list));
        }*/

    }}

1.12 Lock鎖

  • Lock是接口不能直接實(shí)例化,采用實(shí)現(xiàn)類ReentrantLock來實(shí)例化(JDK5以后)

  • ReentrantLock構(gòu)造方法:

方法名說明
ReentrantLock()創(chuàng)建一個(gè)ReentrantLock的實(shí)例對象
  • Lock中獲得鎖和釋放鎖方法:

方法名說明
void lock()獲得鎖
void unlock()釋放鎖
  • 推薦使用try{} finall{}代碼塊來加鎖和釋放鎖

package test;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class SellTicket implements Runnable{
    private static int tickets = 100;
    private Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while(true) {
            try {
                lock.lock();
                if (tickets > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "張票");
                    tickets--;
                }
            }finally {
                lock.unlock();
            }
        }
    }}

1.13 線程通訊

  • 線程通信一定是多個(gè)線程在操作同一個(gè)資源才需要通信

方法名說明
public void wait()讓當(dāng)前線程進(jìn)入到等待狀態(tài),此方法必須鎖對象調(diào)用
public void notify()喚醒當(dāng)前鎖對象上等待狀態(tài)的某個(gè)線程,此方法必須鎖對象調(diào)用
public void notifyAll()喚醒當(dāng)前鎖對象上等待狀態(tài)的全部線程,此方法必須鎖對象調(diào)用

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

1.14.1 生產(chǎn)者消費(fèi)者概述

Java如何實(shí)現(xiàn)多線程、線程同步

  • 為了體現(xiàn)生產(chǎn)和消費(fèi)過程中的等待和喚醒,Java就提供了幾個(gè)方法供我們使用,這幾個(gè)方法在Object類中

  • Object類的等待和喚醒方法

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

Java如何實(shí)現(xiàn)多線程、線程同步

  • 奶箱類

package test;//1:定義奶箱類public class Box {
    //定義一個(gè)成員變量,表示第x瓶奶
    private int milk;
    //定義一個(gè)成員變量表示奶箱的狀態(tài)
    private boolean state = false;

    //提供存儲牛奶和獲取牛奶的操作
    public  synchronized void put(int milk) {
        //如果有牛奶等待消費(fèi)
        if(state) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //如果沒有牛奶,就生產(chǎn)牛奶
        this.milk = milk;
        System.out.println("送奶工將第" + this.milk + "瓶奶放入奶箱");

        //生產(chǎn)完畢后,修改奶箱狀態(tài)
        state = true;

        //喚醒其他等待線程
        notifyAll();
    }

    public  synchronized void get() {
        //如果沒有牛奶,就等到生產(chǎn)
        if(!state) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果有牛奶,就消費(fèi)牛奶
        System.out.println("用戶拿到第" + this.milk + "瓶奶");

        //消費(fèi)完畢后,修改奶箱狀態(tài)
        state = false;

        //喚醒其他等待線程
        notifyAll();
    }}
  • 生產(chǎn)者類

package test;//2:生產(chǎn)者類(Producer):實(shí)現(xiàn)Runnable接口public class Producer implements Runnable {
    private Box b;

    public Producer(Box b) {
        this.b = b;
    }

    //重寫run()方法,調(diào)用存儲牛奶的操作
    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            b.put(i);
        }
    }}
  • 消費(fèi)者類

package test;//3:消費(fèi)者類(Customer);實(shí)現(xiàn)Runnable接口public class Customer implements Runnable{
    private Box b;

    public Customer(Box b) {
        this.b = b;
    }

    //重寫run()方法,調(diào)用獲取牛奶的操作
    @Override
    public void run() {
        while(true) {
            b.get();
        }
    }}
  • 測試類

package test;public class BoxDemo {
    public static void main(String[] args) {
        //創(chuàng)建奶箱對象,這是共享數(shù)據(jù)區(qū)域
        Box b = new Box();

        //創(chuàng)建生產(chǎn)者對象,把奶箱對象作為構(gòu)造方法參數(shù)傳遞。因?yàn)樵谶@個(gè)類中要謂用存儲牛奶的操作
        Producer p = new Producer(b);

        //創(chuàng)建消費(fèi)者對象,把奶箱對象作為構(gòu)造方法參數(shù)傳遞,因?yàn)樵谶@個(gè)類中要調(diào)用獲取牛奶的操作
        Customer c  =new Customer(b);

        //創(chuàng)建2個(gè)線程對象,分別把生產(chǎn)者對象和消費(fèi)者對象作為構(gòu)造方法參數(shù)傳遞
        Thread t1 = new Thread(p);
        Thread t2 = new Thread(c);

        //啟動線程
        t1.start();
        t2.start();//        送奶工將第1瓶奶放入奶箱//                用戶拿到第1瓶奶//        送奶工將第2瓶奶放入奶箱//                用戶拿到第2瓶奶//        送奶工將第3瓶奶放入奶箱//                用戶拿到第3瓶奶//        送奶工將第4瓶奶放入奶箱//                用戶拿到第4瓶奶//        送奶工將第5瓶奶放入奶箱//                用戶拿到第5瓶奶
    }}

關(guān)于“Java如何實(shí)現(xiàn)多線程、線程同步”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“Java如何實(shí)現(xiàn)多線程、線程同步”知識都有一定的了解,大家如果還想學(xué)習(xí)更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

名稱欄目:Java如何實(shí)現(xiàn)多線程、線程同步
分享網(wǎng)址:http://muchs.cn/article4/joggie.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供域名注冊網(wǎng)站導(dǎo)航、網(wǎng)站維護(hù)、網(wǎng)站改版網(wǎng)站設(shè)計(jì)、Google

廣告

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

小程序開發(fā)