<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官:線程順序執(zhí)行,這么多答案你都答不上來?

          共 17565字,需瀏覽 36分鐘

           ·

          2021-02-17 10:47

          點擊上方藍色“小哈學Java”,選擇“設為星標

          回復“資源”獲取獨家整理的學習資料!

          來源:https://cnblogs.com/wenjunwei/p/10573289.html

          一.前言

          本文使用了7中方法實現(xiàn)在多線程中讓線程按順序運行的方法,涉及到多線程中許多常用的方法,不止為了知道如何讓線程按順序運行,更是讓讀者對多線程的使用有更深刻的了解。使用的方法如下:

          • [1] 使用線程的join方法
          • [2] 使用主線程的join方法
          • [3] 使用線程的wait方法
          • [4] 使用線程的線程池方法
          • [5] 使用線程的Condition(條件變量)方法
          • [6] 使用線程的CountDownLatch(倒計數(shù))方法
          • [7] 使用線程的CyclicBarrier(回環(huán)柵欄)方法
          • [8] 使用線程的Semaphore(信號量)方法

          二.實現(xiàn)

          我們下面需要完成這樣一個應用場景:

          1.早上;2.測試人員、產(chǎn)品經(jīng)理、開發(fā)人員陸續(xù)的來公司上班;3.產(chǎn)品經(jīng)理規(guī)劃新需求;4.開發(fā)人員開發(fā)新需求功能;5.測試人員測試新功能。

          規(guī)劃需求,開發(fā)需求新功能,測試新功能是一個有順序的,我們把thread1看做產(chǎn)品經(jīng)理,thread2看做開發(fā)人員,thread3看做測試人員。

          1.使用線程的join方法

          join():是Theard的方法,作用是調(diào)用線程需等待該join()線程執(zhí)行完成后,才能繼續(xù)用下運行。

          應用場景:當一個線程必須等待另一個線程執(zhí)行完畢才能執(zhí)行時可以使用join方法。

          package?com.wwj.javabase.thread.order;

          /**
          ?*?@author?wwj
          ?*?通過子程序join使線程按順序執(zhí)行
          ?*/

          public?class?ThreadJoinDemo?{

          ????public?static?void?main(String[]?args)?{
          ????????final?Thread?thread1?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????System.out.println("產(chǎn)品經(jīng)理規(guī)劃新需求");
          ????????????}
          ????????});

          ????????final?Thread?thread2?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????try?{
          ????????????????????thread1.join();
          ????????????????????System.out.println("開發(fā)人員開發(fā)新需求功能");
          ????????????????}?catch?(InterruptedException?e)?{
          ????????????????????e.printStackTrace();
          ????????????????}
          ????????????}
          ????????});

          ????????Thread?thread3?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????try?{
          ????????????????????thread2.join();
          ????????????????????System.out.println("測試人員測試新功能");
          ????????????????}?catch?(InterruptedException?e)?{
          ????????????????????e.printStackTrace();
          ????????????????}
          ????????????}
          ????????});

          ????????System.out.println("早上:");
          ????????System.out.println("測試人員來上班了...");
          ????????thread3.start();
          ????????System.out.println("產(chǎn)品經(jīng)理來上班了...");
          ????????thread1.start();
          ????????System.out.println("開發(fā)人員來上班了...");
          ????????thread2.start();
          ????}
          }

          運行結果

          早上:
          測試人員來上班了...
          產(chǎn)品經(jīng)理來上班了...
          開發(fā)人員來上班了...
          產(chǎn)品經(jīng)理規(guī)劃新需求
          開發(fā)人員開發(fā)新需求功能
          測試人員測試新功能

          2.使用主線程的join方法

          這里是在主線程中使用join()來實現(xiàn)對線程的阻塞。

          package?com.wwj.javabase.thread.order;

          /**
          ?*?@author?wwj
          ?*?通過主程序join使線程按順序執(zhí)行
          ?*/

          public?class?ThreadMainJoinDemo?{

          ????public?static?void?main(String[]?args)?throws?Exception?{

          ????????final?Thread?thread1?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????System.out.println("產(chǎn)品經(jīng)理正在規(guī)劃新需求...");
          ????????????}
          ????????});

          ????????final?Thread?thread2?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????System.out.println("開發(fā)人員開發(fā)新需求功能");
          ????????????}
          ????????});

          ????????final?Thread?thread3?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????System.out.println("測試人員測試新功能");
          ????????????}
          ????????});

          ????????System.out.println("早上:");
          ????????System.out.println("產(chǎn)品經(jīng)理來上班了");
          ????????System.out.println("測試人員來上班了");
          ????????System.out.println("開發(fā)人員來上班了");
          ????????thread1.start();
          ????????//在父進程調(diào)用子進程的join()方法后,父進程需要等待子進程運行完再繼續(xù)運行。
          ????????System.out.println("開發(fā)人員和測試人員休息會...");
          ????????thread1.join();
          ????????System.out.println("產(chǎn)品經(jīng)理新需求規(guī)劃完成!");
          ????????thread2.start();
          ????????System.out.println("測試人員休息會...");
          ????????thread2.join();
          ????????thread3.start();
          ????}
          }

          運行結果

          產(chǎn)品經(jīng)理來上班了
          測試人員來上班了
          開發(fā)人員來上班了
          開發(fā)人員和測試人員休息會...
          產(chǎn)品經(jīng)理正在規(guī)劃新需求...
          產(chǎn)品經(jīng)理新需求規(guī)劃完成!
          測試人員休息會...
          開發(fā)人員開發(fā)新需求功能
          測試人員測試新功能

          3.使用線程的wait方法

          wait():是Object的方法,作用是讓當前線程進入等待狀態(tài),同時,wait()也會讓當前線程釋放它所持有的鎖?!爸钡狡渌€程調(diào)用此對象的 notify() 方法或 notifyAll() 方法”,當前線程被喚醒(進入“就緒狀態(tài)”)

          notify()和notifyAll():是Object的方法,作用則是喚醒當前對象上的等待線程;notify()是喚醒單個線程,而notifyAll()是喚醒所有的線程。

          wait(long timeout):讓當前線程處于“等待(阻塞)狀態(tài)”,“直到其他線程調(diào)用此對象的notify()方法或 notifyAll() 方法,或者超過指定的時間量”,當前線程被喚醒(進入“就緒狀態(tài)”)。

          應用場景:Java實現(xiàn)生產(chǎn)者消費者的方式。

          package?com.wwj.javabase.thread.order;

          /**
          ?*?@author?wwj
          ?*/

          public?class?ThreadWaitDemo?{

          ????private?static?Object?myLock1?=?new?Object();
          ????private?static?Object?myLock2?=?new?Object();

          ????/**
          ?????*?為什么要加這兩個標識狀態(tài)?
          ?????*?如果沒有狀態(tài)標識,當t1已經(jīng)運行完了t2才運行,t2在等待t1喚醒導致t2永遠處于等待狀態(tài)
          ?????*/

          ????private?static?Boolean?t1Run?=?false;
          ????private?static?Boolean?t2Run?=?false;
          ????public?static?void?main(String[]?args)?{

          ????????final?Thread?thread1?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????synchronized?(myLock1){
          ????????????????????System.out.println("產(chǎn)品經(jīng)理規(guī)劃新需求...");
          ????????????????????t1Run?=?true;
          ????????????????????myLock1.notify();
          ????????????????}
          ????????????}
          ????????});

          ????????final?Thread?thread2?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????synchronized?(myLock1){
          ????????????????????try?{
          ????????????????????????if(!t1Run){
          ????????????????????????????System.out.println("開發(fā)人員先休息會...");
          ????????????????????????????myLock1.wait();
          ????????????????????????}
          ????????????????????????synchronized?(myLock2){
          ????????????????????????????System.out.println("開發(fā)人員開發(fā)新需求功能");
          ????????????????????????????myLock2.notify();
          ????????????????????????}
          ????????????????????}?catch?(InterruptedException?e)?{
          ????????????????????????e.printStackTrace();
          ????????????????????}
          ????????????????}
          ????????????}
          ????????});

          ????????Thread?thread3?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????synchronized?(myLock2){
          ????????????????????try?{
          ????????????????????????if(!t2Run){
          ????????????????????????????System.out.println("測試人員先休息會...");
          ????????????????????????????myLock2.wait();
          ????????????????????????}
          ????????????????????????System.out.println("測試人員測試新功能");
          ????????????????????}?catch?(InterruptedException?e)?{
          ????????????????????????e.printStackTrace();
          ????????????????????}
          ????????????????}
          ????????????}
          ????????});

          ????????System.out.println("早上:");
          ????????System.out.println("測試人員來上班了...");
          ????????thread3.start();
          ????????System.out.println("產(chǎn)品經(jīng)理來上班了...");
          ????????thread1.start();
          ????????System.out.println("開發(fā)人員來上班了...");
          ????????thread2.start();
          ????}
          }

          運行結果:這里輸出會有很多種順序,主要是因為線程進入的順序,造成鎖住線程的順序不一致。

          早上:
          測試人員來上班了...
          產(chǎn)品經(jīng)理來上班了...
          開發(fā)人員來上班了...
          測試人員先休息會...
          產(chǎn)品經(jīng)理規(guī)劃新需求...
          開發(fā)人員開發(fā)新需求功能
          測試人員測試新功能

          4.使用線程的線程池方法

          JAVA通過Executors提供了四種線程池

          • 單線程化線程池(newSingleThreadExecutor);
          • 可控最大并發(fā)數(shù)線程池(newFixedThreadPool);
          • 可回收緩存線程池(newCachedThreadPool);
          • 支持定時與周期性任務的線程池(newScheduledThreadPool)。

          單線程化線程池(newSingleThreadExecutor):優(yōu)點,串行執(zhí)行所有任務。

          submit():提交任務。

          shutdown():方法用來關閉線程池,拒絕新任務。

          應用場景:串行執(zhí)行所有任務。如果這個唯一的線程因為異常結束,那么會有一個新的線程來替代它。此線程池保證所有任務的執(zhí)行順序按照任務的提交順序執(zhí)行。

          package?com.wwj.javabase.thread.order;

          import?java.util.concurrent.ExecutorService;
          import?java.util.concurrent.Executors;

          /**
          ?*?@author?wwj
          ?*?通過SingleThreadExecutor讓線程按順序執(zhí)行
          ?*/

          public?class?ThreadPoolDemo?{

          ????static?ExecutorService?executorService?=?Executors.newSingleThreadExecutor();

          ????public?static?void?main(String[]?args)?throws?Exception?{

          ????????final?Thread?thread1?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????System.out.println("產(chǎn)品經(jīng)理規(guī)劃新需求");
          ????????????}
          ????????});

          ????????final?Thread?thread2?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????System.out.println("開發(fā)人員開發(fā)新需求功能");
          ????????????}
          ????????});

          ????????Thread?thread3?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????System.out.println("測試人員測試新功能");
          ????????????}
          ????????});

          ????????System.out.println("早上:");
          ????????System.out.println("產(chǎn)品經(jīng)理來上班了");
          ????????System.out.println("測試人員來上班了");
          ????????System.out.println("開發(fā)人員來上班了");
          ????????System.out.println("領導吩咐:");
          ????????System.out.println("首先,產(chǎn)品經(jīng)理規(guī)劃新需求...");
          ????????executorService.submit(thread1);
          ????????System.out.println("然后,開發(fā)人員開發(fā)新需求功能...");
          ????????executorService.submit(thread2);
          ????????System.out.println("最后,測試人員測試新功能...");
          ????????executorService.submit(thread3);
          ????????executorService.shutdown();
          ????}
          }

          運行結果

          早上:
          產(chǎn)品經(jīng)理來上班了
          測試人員來上班了
          開發(fā)人員來上班了
          領導吩咐:
          首先,產(chǎn)品經(jīng)理規(guī)劃新需求...
          然后,開發(fā)人員開發(fā)新需求功能...
          最后,測試人員測試新功能...
          產(chǎn)品經(jīng)理規(guī)劃新需求
          開發(fā)人員開發(fā)新需求功能
          測試人員測試新功能

          5.使用線程的Condition(條件變量)方法

          Condition(條件變量):通常與一個鎖關聯(lián)。需要在多個Contidion中共享一個鎖時,可以傳遞一個Lock/RLock實例給構造方法,否則它將自己生成一個RLock實例。

          • Condition中**await()**方法類似于Object類中的wait()方法。
          • Condition中**await(long time,TimeUnit unit)**方法類似于Object類中的wait(long time)方法。
          • Condition中**signal()**方法類似于Object類中的notify()方法。
          • Condition中**signalAll()**方法類似于Object類中的notifyAll()方法。

          應用場景:Condition是一個多線程間協(xié)調(diào)通信的工具類,使得某個,或者某些線程一起等待某個條件(Condition),只有當該條件具備( signal 或者 signalAll方法被帶調(diào)用)時 ,這些等待線程才會被喚醒,從而重新爭奪鎖。

          package?com.wwj.javabase.thread.order;

          import?java.util.concurrent.locks.Condition;
          import?java.util.concurrent.locks.Lock;
          import?java.util.concurrent.locks.ReentrantLock;

          /**
          ?*?@author?wwj
          ?*?使用Condition(條件變量)實現(xiàn)線程按順序運行
          ?*/

          public?class?ThreadConditionDemo?{

          ????private?static?Lock?lock?=?new?ReentrantLock();
          ????private?static?Condition?condition1?=?lock.newCondition();
          ????private?static?Condition?condition2?=?lock.newCondition();

          ????/**
          ?????*?為什么要加這兩個標識狀態(tài)?
          ?????*?如果沒有狀態(tài)標識,當t1已經(jīng)運行完了t2才運行,t2在等待t1喚醒導致t2永遠處于等待狀態(tài)
          ?????*/

          ????private?static?Boolean?t1Run?=?false;
          ????private?static?Boolean?t2Run?=?false;

          ????public?static?void?main(String[]?args)?{

          ????????final?Thread?thread1?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????lock.lock();
          ????????????????System.out.println("產(chǎn)品經(jīng)理規(guī)劃新需求");
          ????????????????t1Run?=?true;
          ????????????????condition1.signal();
          ????????????????lock.unlock();
          ????????????}
          ????????});

          ????????final?Thread?thread2?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????lock.lock();
          ????????????????try?{
          ????????????????????if(!t1Run){
          ????????????????????????System.out.println("開發(fā)人員先休息會...");
          ????????????????????????condition1.await();
          ????????????????????}
          ????????????????????System.out.println("開發(fā)人員開發(fā)新需求功能");
          ????????????????????t2Run?=?true;
          ????????????????????condition2.signal();
          ????????????????}?catch?(InterruptedException?e)?{
          ????????????????????e.printStackTrace();
          ????????????????}
          ????????????????lock.unlock();
          ????????????}
          ????????});

          ????????Thread?thread3?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????lock.lock();
          ????????????????try?{
          ????????????????????if(!t2Run){
          ????????????????????????System.out.println("測試人員先休息會...");
          ????????????????????????condition2.await();
          ????????????????????}
          ????????????????????System.out.println("測試人員測試新功能");
          ????????????????????lock.unlock();
          ????????????????}?catch?(InterruptedException?e)?{
          ????????????????????e.printStackTrace();
          ????????????????}
          ????????????}
          ????????});

          ????????System.out.println("早上:");
          ????????System.out.println("測試人員來上班了...");
          ????????thread3.start();
          ????????System.out.println("產(chǎn)品經(jīng)理來上班了...");
          ????????thread1.start();
          ????????System.out.println("開發(fā)人員來上班了...");
          ????????thread2.start();
          ????}
          }

          運行結果:這里輸出會有很多種順序,主要是因為線程進入的順序,造成鎖住線程的順序不一致

          早上:
          測試人員來上班了...
          產(chǎn)品經(jīng)理來上班了...
          開發(fā)人員來上班了...
          測試人員先休息會...
          產(chǎn)品經(jīng)理規(guī)劃新需求
          開發(fā)人員開發(fā)新需求功能
          測試人員測試新功能

          6.使用線程的CountDownLatch(倒計數(shù))方法

          CountDownLatch:位于java.util.concurrent包下,利用它可以實現(xiàn)類似計數(shù)器的功能。

          應用場景:比如有一個任務C,它要等待其他任務A,B執(zhí)行完畢之后才能執(zhí)行,此時就可以利用CountDownLatch來實現(xiàn)這種功能了。

          package?com.wwj.javabase.thread.order;

          import?java.util.concurrent.CountDownLatch;

          /**
          ?*?@author?wwj
          ?*?通過CountDownLatch(倒計數(shù))使線程按順序執(zhí)行
          ?*/

          public?class?ThreadCountDownLatchDemo?{

          ????/**
          ?????*?用于判斷線程一是否執(zhí)行,倒計時設置為1,執(zhí)行后減1
          ?????*/

          ????private?static?CountDownLatch?c1?=?new?CountDownLatch(1);

          ????/**
          ?????*?用于判斷線程二是否執(zhí)行,倒計時設置為1,執(zhí)行后減1
          ?????*/

          ????private?static?CountDownLatch?c2?=?new?CountDownLatch(1);

          ????public?static?void?main(String[]?args)?{
          ????????final?Thread?thread1?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????System.out.println("產(chǎn)品經(jīng)理規(guī)劃新需求");
          ????????????????//對c1倒計時-1
          ????????????????c1.countDown();
          ????????????}
          ????????});

          ????????final?Thread?thread2?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????try?{
          ????????????????????//等待c1倒計時,計時為0則往下運行
          ????????????????????c1.await();
          ????????????????????System.out.println("開發(fā)人員開發(fā)新需求功能");
          ????????????????????//對c2倒計時-1
          ????????????????????c2.countDown();
          ????????????????}?catch?(InterruptedException?e)?{
          ????????????????????e.printStackTrace();
          ????????????????}
          ????????????}
          ????????});

          ????????Thread?thread3?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????try?{
          ????????????????????//等待c2倒計時,計時為0則往下運行
          ????????????????????c2.await();
          ????????????????????System.out.println("測試人員測試新功能");
          ????????????????}?catch?(InterruptedException?e)?{
          ????????????????????e.printStackTrace();
          ????????????????}
          ????????????}
          ????????});

          ????????System.out.println("早上:");
          ????????System.out.println("測試人員來上班了...");
          ????????thread3.start();
          ????????System.out.println("產(chǎn)品經(jīng)理來上班了...");
          ????????thread1.start();
          ????????System.out.println("開發(fā)人員來上班了...");
          ????????thread2.start();
          ????}
          }

          運行結果

          早上:
          測試人員來上班了...
          產(chǎn)品經(jīng)理來上班了...
          開發(fā)人員來上班了...
          產(chǎn)品經(jīng)理規(guī)劃新需求
          開發(fā)人員開發(fā)新需求功能
          測試人員測試新功能

          7.使用CyclicBarrier(回環(huán)柵欄)實現(xiàn)線程按順序運行

          CyclicBarrier(回環(huán)柵欄):通過它可以實現(xiàn)讓一組線程等待至某個狀態(tài)之后再全部同時執(zhí)行。叫做回環(huán)是因為當所有等待線程都被釋放以后,CyclicBarrier可以被重用。我們暫且把這個狀態(tài)就叫做barrier,當調(diào)用await()方法之后,線程就處于barrier了。

          應用場景:公司組織春游,等待所有的員工到達集合地點才能出發(fā),每個人到達后進入barrier狀態(tài)。都到達后,喚起大家一起出發(fā)去旅行。

          package?com.wwj.javabase.thread.order;

          import?java.util.concurrent.BrokenBarrierException;
          import?java.util.concurrent.CyclicBarrier;

          /**
          ?*?@author?wwj
          ?*?使用CyclicBarrier(回環(huán)柵欄)實現(xiàn)線程按順序運行
          ?*/

          public?class?CyclicBarrierDemo?{

          ????static?CyclicBarrier?barrier1?=?new?CyclicBarrier(2);
          ????static?CyclicBarrier?barrier2?=?new?CyclicBarrier(2);

          ????public?static?void?main(String[]?args)?{

          ????????final?Thread?thread1?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????try?{
          ????????????????????System.out.println("產(chǎn)品經(jīng)理規(guī)劃新需求");
          ????????????????????//放開柵欄1
          ????????????????????barrier1.await();
          ????????????????}?catch?(InterruptedException?e)?{
          ????????????????????e.printStackTrace();
          ????????????????}?catch?(BrokenBarrierException?e)?{
          ????????????????????e.printStackTrace();
          ????????????????}
          ????????????}
          ????????});

          ????????final?Thread?thread2?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????try?{
          ????????????????????//放開柵欄1
          ????????????????????barrier1.await();
          ????????????????????System.out.println("開發(fā)人員開發(fā)新需求功能");
          ????????????????????//放開柵欄2
          ????????????????????barrier2.await();
          ????????????????}?catch?(InterruptedException?e)?{
          ????????????????????e.printStackTrace();
          ????????????????}?catch?(BrokenBarrierException?e)?{
          ????????????????????e.printStackTrace();
          ????????????????}
          ????????????}
          ????????});

          ????????final?Thread?thread3?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????try?{
          ????????????????????//放開柵欄2
          ????????????????????barrier2.await();
          ????????????????????System.out.println("測試人員測試新功能");
          ????????????????}?catch?(InterruptedException?e)?{
          ????????????????????e.printStackTrace();
          ????????????????}?catch?(BrokenBarrierException?e)?{
          ????????????????????e.printStackTrace();
          ????????????????}
          ????????????}
          ????????});

          ????????System.out.println("早上:");
          ????????System.out.println("測試人員來上班了...");
          ????????thread3.start();
          ????????System.out.println("產(chǎn)品經(jīng)理來上班了...");
          ????????thread1.start();
          ????????System.out.println("開發(fā)人員來上班了...");
          ????????thread2.start();
          ????}
          }

          運行結果

          早上:
          測試人員來上班了...
          產(chǎn)品經(jīng)理來上班了...
          開發(fā)人員來上班了...
          產(chǎn)品經(jīng)理規(guī)劃新需求
          開發(fā)人員開發(fā)新需求功能
          測試人員測試新功能

          8.使用Sephmore(信號量)實現(xiàn)線程按順序運行

          Sephmore(信號量):Semaphore是一個計數(shù)信號量,從概念上將,Semaphore包含一組許可證,如果有需要的話,每個acquire()方法都會阻塞,直到獲取一個可用的許可證,每個release()方法都會釋放持有許可證的線程,并且歸還Semaphore一個可用的許可證。然而,實際上并沒有真實的許可證對象供線程使用,Semaphore只是對可用的數(shù)量進行管理維護。

          acquire():當前線程嘗試去阻塞的獲取1個許可證,此過程是阻塞的,當前線程獲取了1個可用的許可證,則會停止等待,繼續(xù)執(zhí)行。

          release():當前線程釋放1個可用的許可證。

          應用場景:Semaphore可以用來做流量分流,特別是對公共資源有限的場景,比如數(shù)據(jù)庫連接。假設有這個的需求,讀取幾萬個文件的數(shù)據(jù)到數(shù)據(jù)庫中,由于文件讀取是IO密集型任務,可以啟動幾十個線程并發(fā)讀取,但是數(shù)據(jù)庫連接數(shù)只有10個,這時就必須控制最多只有10個線程能夠拿到數(shù)據(jù)庫連接進行操作。這個時候,就可以使用Semaphore做流量控制。

          package?com.wwj.javabase.thread.order;

          import?java.util.concurrent.Semaphore;
          /**
          ?*?@author?wwj
          ?*?使用Sephmore(信號量)實現(xiàn)線程按順序運行
          ?*/

          public?class?SemaphoreDemo?{
          ????private?static?Semaphore?semaphore1?=?new?Semaphore(1);
          ????private?static?Semaphore?semaphore2?=?new?Semaphore(1);
          ????public?static?void?main(String[]?args)?{
          ????????final?Thread?thread1?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????System.out.println("產(chǎn)品經(jīng)理規(guī)劃新需求");
          ????????????????semaphore1.release();
          ????????????}
          ????????});

          ????????final?Thread?thread2?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????try?{
          ????????????????????semaphore1.acquire();
          ????????????????????System.out.println("開發(fā)人員開發(fā)新需求功能");
          ????????????????????semaphore2.release();
          ????????????????}?catch?(InterruptedException?e)?{
          ????????????????????e.printStackTrace();
          ????????????????}
          ????????????}
          ????????});

          ????????Thread?thread3?=?new?Thread(new?Runnable()?{
          ????????????@Override
          ????????????public?void?run()?{
          ????????????????try?{
          ????????????????????semaphore2.acquire();
          ????????????????????thread2.join();
          ????????????????????semaphore2.release();
          ????????????????????System.out.println("測試人員測試新功能");
          ????????????????}?catch?(InterruptedException?e)?{
          ????????????????????e.printStackTrace();
          ????????????????}
          ????????????}
          ????????});

          ????????System.out.println("早上:");
          ????????System.out.println("測試人員來上班了...");
          ????????thread3.start();
          ????????System.out.println("產(chǎn)品經(jīng)理來上班了...");
          ????????thread1.start();
          ????????System.out.println("開發(fā)人員來上班了...");
          ????????thread2.start();
          ????}
          }

          運行結果

          早上:
          測試人員來上班了...
          產(chǎn)品經(jīng)理來上班了...
          開發(fā)人員來上班了...
          產(chǎn)品經(jīng)理規(guī)劃新需求
          開發(fā)人員開發(fā)新需求功能
          測試人員測試新功能

          總結

          看完了這么多種方法,是不是對多線程有了更深入的了解呢?不妨自己試試吧(代碼拷貝均可運行)

          使用的場景還有很多,根據(jù)開發(fā)需求場景,選擇合適的方法,達到事半功倍的效果。

          END


          有熱門推薦??

          1.?一次線上商城系統(tǒng)高并發(fā)優(yōu)化,漲姿勢了~

          2.?Spring Boot 啟動擴展點超詳細總結,再也不怕面試官問了!

          3.?MySQL與PostgreSQL比較,哪個更好、我們該選用哪個?

          4.?Hutool Java 工具類庫導出 Excel,超級簡單!

          最近面試BAT,整理一份面試資料Java面試BATJ通關手冊,覆蓋了Java核心技術、JVM、Java并發(fā)、SSM、微服務、數(shù)據(jù)庫、數(shù)據(jù)結構等等。

          獲取方式:點“在看”,關注公眾號并回復?Java?領取,更多內(nèi)容陸續(xù)奉上。

          文章有幫助的話,在看,轉發(fā)吧。

          謝謝支持喲 (*^__^*)

          瀏覽 51
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美一级AAAAABBBBB | 成人网站在线观看视频 | www.黄色视频在线观看 | 强开小嫩苞一区二区三区图片 | 日韩在线小视频 |