www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 公眾號(hào)精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]多線程并發(fā)執(zhí)行?線程之間通信?這是我偶爾聽到我同事做面試官時(shí)問的一道題,感覺很有意思,發(fā)出來大家和大家討論下。

詳解一道京東面試題

多線程并發(fā)執(zhí)行?線程之間通信?這是我偶爾聽到我同事做面試官時(shí)問的一道題,感覺很有意思,發(fā)出來大家和大家討論下

面試題目描述

現(xiàn)在呢,我們有三個(gè)接口,就叫他A,B,C吧,這三個(gè)接口都是查詢某個(gè)人征信信息的,必須同時(shí)返回true,我們才認(rèn)為這個(gè)人的征信合格,如果其中某一個(gè)返回false的話,就表明這個(gè)人的征信不合格,如果是你,你會(huì)怎么設(shè)計(jì)怎么寫這個(gè)代碼呢?

第一次思考

首先,一定是并發(fā)執(zhí)行,假如說A接口執(zhí)行3秒,B接口執(zhí)行5秒,C接口執(zhí)行8秒的話

  • 串行執(zhí)行: 3+5+8 = 16秒
  • 并發(fā)執(zhí)行: 8=8秒 (時(shí)間最久的那個(gè)接口執(zhí)行的時(shí)間就是這三個(gè)接口的執(zhí)行總時(shí)間)

熟悉的感覺,多線程執(zhí)行任務(wù),我在第二章文章實(shí)戰(zhàn)!xhJaver竟然用線程池優(yōu)化了。。。有提過怎么寫,感興趣的讀者可以回去看一下,不過我在這里再寫一下,話不多說來看下代碼

并發(fā)代碼

建議用PC端查看,所有代碼都可直接復(fù)制運(yùn)行,代碼中重要的點(diǎn)都有詳細(xì)注釋

  1. 首先,我們先定義這三個(gè)接口
public class DoService { //設(shè)置A?B?C接口的返回值,b接口設(shè)置的是false private static Boolean?flagA?= true; private static Boolean?flagB?= false; private static Boolean?flagC?= true; public static boolean A(){ long start?=?System.currentTimeMillis(); try {
????????????Thread.sleep(3000L);
????????} catch (InterruptedException?e)?{
????????????System.out.println("a被打斷??耗時(shí)" +?(System.currentTimeMillis()?-?start));
???????????????e.printStackTrace();
????????}
????????System.out.println("a耗時(shí)??"+(System.currentTimeMillis()?-?start)); return flagA;
????} public static boolean B() { long start?=?System.currentTimeMillis(); try {
????????????Thread.sleep(5000L);
????????} catch (InterruptedException?e)?{
????????????System.out.println("b被打斷??耗時(shí)" +?(System.currentTimeMillis()?-?start));
????????????e.printStackTrace();
????????}
????????System.out.println("b耗時(shí)??"+(System.currentTimeMillis()?-?start)); return flagB;
????} public static boolean C() { long start?=?System.currentTimeMillis(); try {
????????????Thread.sleep(8000L);
????????} catch (InterruptedException?e)?{
????????????System.out.println("c被打斷??耗時(shí)" +?(System.currentTimeMillis()?-?start));
????????????e.printStackTrace();
????????}
????????System.out.println("c耗時(shí)??"+(System.currentTimeMillis()?-?start)); return flagC;
????}
}
  1. 其次 我們先創(chuàng)造一個(gè)Task 任務(wù)類
public class Task implements Callable<Boolean> { private String?taskName; private Integer?i; public Task(String?taskName,int i){ this.taskName?=taskName; this.i?=?i;
????} @Override public Boolean call() throws Exception { //?標(biāo)記?返回值,代表這個(gè)接口是否執(zhí)行成功 Boolean?flag?= false; //記錄接口名字 String?serviceName?= null; //根據(jù)i的值來判斷調(diào)用哪個(gè)接口 if (i==1){
????????????flag???=????DoService.A();
????????????serviceName="A";
????????} if (i==2){
????????????flag???=????DoService.B();
????????????serviceName="B";
????????} if (i==3){
????????????flag???=????DoService.C();
????????????serviceName="C";
????????}
????????System.out.println("當(dāng)前線程是:?"+Thread.currentThread().getName()+"正在處理的任務(wù)是:?"+this.taskName+"調(diào)用的接口是:?"+serviceName); return flag;
????}
}
  1. 最后,我們定義一個(gè)測(cè)試類
class Test { public static void main(String[]?args) throws ExecutionException,?InterruptedException { //創(chuàng)建一個(gè)包含三個(gè)線程的線程池 ExecutorService?executorService?=?Executors.newFixedThreadPool(3); //事先準(zhǔn)備好儲(chǔ)存結(jié)果的list集合 List< Future>?list?= new ArrayList<>(); //開始計(jì)時(shí) long start?=?System.currentTimeMillis(); for (int i=1;i<4;i++){
????????????Task?task?= new Task("任務(wù)"+i,i); //將每個(gè)任務(wù)提交到線程池中,并且得到這個(gè)線程的執(zhí)行結(jié)果 Futureresult?=?executorService.submit(task);
????????????list.add(result);
????????} //記得把線程池關(guān)閉 executorService.shutdown(); //定義一個(gè)變量?0 int count?= 0;
????????System.out.println("等待處理結(jié)果。。。"); for (int i=0;i//得到處理的結(jié)果?線程阻塞,如果線程沒有處理完就一直阻塞 Boolean?flag?=?result.get(); //如果這個(gè)接口返回true,那么count就++ if (flag){
????????????????count++;
????????????}
????????}
????????System.out.println("線程池+結(jié)果處理時(shí)間:"+?(System.currentTimeMillis()?-?start)); //如果count數(shù)量為3,那么三個(gè)就都為true,代表這個(gè)人征信沒問題 if (count==3){
????????????System.out.println("合格");
????????}else {//否則,就是有問題 System.out.println("不合格");
????????}
????}
}
  1. 我們看下輸出結(jié)果
等待處理結(jié)果。。。
a耗時(shí) 3000 當(dāng)前線程是:?pool-1-thread-1正在處理的任務(wù)是:?任務(wù)1調(diào)用的接口是:?A
b耗時(shí) 5000 當(dāng)前線程是:?pool-1-thread-2正在處理的任務(wù)是:?任務(wù)2調(diào)用的接口是:?B
c耗時(shí) 8000 當(dāng)前線程是:?pool-1-thread-3正在處理的任務(wù)是:?任務(wù)3調(diào)用的接口是:?C
線程池+結(jié)果處理時(shí)間:8008 不合格
  • 我們運(yùn)行的時(shí)候會(huì)發(fā)現(xiàn),它的輸出結(jié)果的順序如下 1 2 3 4 5 京東這道面試題你會(huì)嗎?我們圖中的2,3,4是再線程池內(nèi)開了三個(gè)線程執(zhí)行的,他們之間相隔一段時(shí)間才出現(xiàn)的,因?yàn)槊總€(gè)接口都有執(zhí)行時(shí)間

程序運(yùn)行后,“標(biāo)記2”是3秒后出現(xiàn),“標(biāo)記三”是5秒后出現(xiàn),“標(biāo)記4”是8秒后出現(xiàn)

其實(shí)4和5相差時(shí)間很短,幾乎是同時(shí)出現(xiàn)的,因?yàn)?執(zhí)行完了就是主線程繼續(xù)執(zhí)行了

線程池+結(jié)果處理的時(shí)間一共是8秒,而每個(gè)接口分別執(zhí)行的時(shí)間是3秒,5秒,8秒,達(dá)到了我們所說的,多線程處理多個(gè)接口,總共耗時(shí)時(shí)間是耗時(shí)最長(zhǎng)的接口的時(shí)間

和京東面試官探討

波哥說(我愛叫他波哥,東北人,說話則逗,幽默的人簡(jiǎn)直就是人間瑰寶,其實(shí)我也蠻有趣的,就是沒人發(fā)現(xiàn)),你這程序不行啊,有個(gè)缺點(diǎn),假如說,你這個(gè)A接口,耗時(shí)三秒,他返回了false,那么你另外兩個(gè)線程也不用執(zhí)行了,這個(gè)人的征信已經(jīng)不合格了,你需要判斷下,如果某一個(gè)線程執(zhí)行的任務(wù)返回了false,那么就及時(shí)中斷其他兩個(gè)線程

靈光乍現(xiàn)

上一次的代碼已經(jīng)實(shí)現(xiàn)了多線程執(zhí)行任務(wù),可是這線程間通信怎么辦呢?怎么才能根據(jù)一個(gè)線程的執(zhí)行結(jié)果而打斷其他線程呢?我想到了以下幾點(diǎn)

  1. 共享變量 public static volatile boolean end = true;

  • 這個(gè)共享變量就代表是否結(jié)束三個(gè)線程的執(zhí)行 如果為true的話,代表結(jié)束,false的話代表不結(jié)束線程執(zhí)行
  • 計(jì)數(shù)器 public static AtomicInteger count =new AtomicInteger(0);

    • 每當(dāng)每個(gè)線程執(zhí)行完的話,如果返回true,計(jì)數(shù)器就+1,當(dāng)計(jì)數(shù)器變?yōu)?的時(shí)候,就代表這個(gè)人征信沒問題
  • 中斷方法 interrupt()

    • 我們會(huì)單獨(dú)開個(gè)線程一直循環(huán)檢測(cè)這個(gè)變量,當(dāng)檢測(cè)到為true的時(shí)候,就會(huì)調(diào)用中斷方法中斷這三個(gè)線程
  • 阻塞線程 countDownLatch

    • 我們程序往下執(zhí)行需要獲取結(jié)果,獲取不到這個(gè)結(jié)果的話,就要一直等著。我們可以用這個(gè)線程阻塞的工具,一開始給他設(shè)置數(shù)量為1,當(dāng)滿足繼續(xù)向下執(zhí)行的條件時(shí),調(diào)用 countDownLatch.countDown();,在主線程那里 countDownLatch.await();一下這樣當(dāng)檢測(cè)到數(shù)量為0的時(shí)候,主線程那里就繼續(xù)往下執(zhí)行了,話不多說,來看代碼

    代碼優(yōu)化

    建議用PC端查看,所有代碼都可直接復(fù)制運(yùn)行,代碼中重要的點(diǎn)都有詳細(xì)注釋

    1. 首先,還是創(chuàng)建接口
    public class DoService { private static Boolean?flagA?= true; private static Boolean?flagB?= false; private static Boolean?flagC?= true; public static boolean A(){ long start?=?System.currentTimeMillis(); try {
    ????????????Thread.sleep(3000L);
    ????????} catch (InterruptedException?e)?{
    ????????????System.out.println("a被打斷??耗時(shí)" +?(System.currentTimeMillis()?-?start));
    ???????????????e.printStackTrace();
    ????????}
    ????????System.out.println("a耗時(shí)??"+(System.currentTimeMillis()?-?start)); return flagA;
    ????} public static boolean B() { long start?=?System.currentTimeMillis(); try {
    ????????????Thread.sleep(5000L);
    ????????} catch (InterruptedException?e)?{
    ????????????System.out.println("b被打斷??耗時(shí)" +?(System.currentTimeMillis()?-?start));
    ????????????e.printStackTrace();
    ????????}
    ????????System.out.println("b耗時(shí)??"+(System.currentTimeMillis()?-?start)); return flagB;
    ????} public static boolean C() { long start?=?System.currentTimeMillis(); try {
    ????????????Thread.sleep(8000L);
    ????????} catch (InterruptedException?e)?{
    ????????????System.out.println("c被打斷??耗時(shí)" +?(System.currentTimeMillis()?-?start));
    ????????????e.printStackTrace();
    ????????}
    ????????System.out.println("c耗時(shí)??"+(System.currentTimeMillis()?-?start)); return flagC;
    ????}
    }
    1. 創(chuàng)建任務(wù)
    public class Task implements Runnable { private String?name?; public Task(?String?name){ this.name?=?name;
    ????} @Override public void run() { boolean flag?= false;
    ????????String?serviceName?= null; if(this.name.equals("A")){
    ????????????serviceName?= "A";
    ?????????????flag?=?DoService.A();
    ????????} if(this.name.equals("B")){
    ????????????serviceName?= "B";
    ????????????flag?=?DoService.B();
    ????????} if(this.name.equals("C")){
    ???????????serviceName?= "C";
    ???????????flag?=?DoService.C();
    ???????} //如果有一個(gè)為false if (!flag){ //就把共享標(biāo)志位置為false Test.end?= false;
    ????????}else { //計(jì)數(shù)器加一,到三的話就是三個(gè)都為true Test.count.incrementAndGet();
    ???????}
    ????????System.out.println("當(dāng)前線程是:?"+Thread.currentThread().getName()+"正在處理的任務(wù)是:?"+this.name+"調(diào)用的接口是:?"+serviceName);
    ????}
    }
    1. 創(chuàng)建測(cè)試類
    class Test { //設(shè)置countDownLatch?里面計(jì)數(shù)為1, //?只調(diào)用一次countDownLatch.countDown就可以繼續(xù)執(zhí)行?countDownLatch.await(); //后面的代碼了,接觸阻塞 public static CountDownLatch?countDownLatch?= new CountDownLatch(1); //默認(rèn)都為true,有一個(gè)線程為false了,那么就變?yōu)閒alse public static volatile boolean end?= true; //計(jì)數(shù)器,數(shù)字變?yōu)?的時(shí)候代表三個(gè)接口都返回true,線程安全的原子類 public static AtomicInteger?count?=new AtomicInteger(0); public static void main(String[]?args) throws InterruptedException { long start?=?System.currentTimeMillis(); //創(chuàng)建三個(gè)任務(wù),分被調(diào)用A?B?C?接口 Task?taskA?= new Task("A");
    ????????Task?taskB?= new Task("B");
    ????????Task?taskC?= new Task("C"); //創(chuàng)建三個(gè)線程 Thread?tA?= new Thread(taskA);
    ????????Thread?tB?= new Thread(taskB);
    ????????Thread?tC?= new Thread(taskC); //開啟三個(gè)線程 tA.start();
    ????????tB.start();
    ????????tC.start(); //在開啟一個(gè)線程,這個(gè)線程就是單獨(dú)循環(huán)掃描這個(gè)共享變量的 new Thread(new Runnable()?{ @Override public void run() { //此線程一直循環(huán)判斷這個(gè)結(jié)束變量,如果為false的話,就代表有一個(gè)接口返回false,跳出,重點(diǎn)其他線程 while (true){ if (!end?){ //當(dāng)這個(gè)共享變量為false時(shí)i表示,其他線程可以中斷了,所以就打斷他們執(zhí)行 tA.interrupt();
    ????????????????????????tB.interrupt();
    ????????????????????????tC.interrupt(); //如果某個(gè)線程被打斷的話,就表明不合格 System.out.println("不合格"); //countDownLatch?計(jì)數(shù)器減一 countDownLatch.countDown(); break;
    ????????????????????} if (Test.count.get()==3){
    ????????????????????????System.out.println("合格"); //countDownLatch?計(jì)數(shù)器減一 countDownLatch.countDown(); break;
    ????????????????????}
    ????????????????}
    ????????????}
    ????????}).start();
    ????????System.out.println(Thread.currentThread().getName()+"主線程開始掛起"); //阻塞主線程繼續(xù)執(zhí)行,等待其他線程計(jì)算完結(jié)果在執(zhí)行下去,countDownLatch中的計(jì)數(shù)為0時(shí),就可以繼續(xù)執(zhí)行下去 countDownLatch.await();
    ????????System.out.println(Thread.currentThread().getName()+"?主線獲得結(jié)果后繼續(xù)執(zhí)行"+(System.currentTimeMillis()?-?start));
    ????}
    
    }
    1. 我們看下輸出結(jié)果
    main主線程開始掛起
    a耗時(shí) 3024 當(dāng)前線程是:?Thread-0正在處理的任務(wù)是:?A調(diào)用的接口是:?A
    b耗時(shí) 5000 當(dāng)前線程是:?Thread-1正在處理的任務(wù)是:?B調(diào)用的接口是:?B
    c被打斷??耗時(shí)5001 不合格
    java.lang.InterruptedException:?sleep?interrupted
    ?at?java.lang.Thread.sleep(Native?Method)
    ?at?com.xhj.concurrent.executor_05._02.DoService.C(DoService.java:41)
    ?at?com.xhj.concurrent.executor_05._02.Task.run(Task.java:30)
    ?at?java.lang.Thread.run(Thread.java:748)
    c耗時(shí) 5003 當(dāng)前線程是:?Thread-2正在處理的任務(wù)是:?C調(diào)用的接口是:?C
    main?主線獲得結(jié)果后繼續(xù)執(zhí)行5014 
    • 我們運(yùn)行的時(shí)候會(huì)發(fā)現(xiàn) 京東這道面試題你會(huì)嗎?

    由圖可見,我們首先就把主線程掛起,等待其他四個(gè)線程的處理結(jié)果,三個(gè)線程分別處理那三個(gè)接口,另外一個(gè)線程循環(huán)遍歷那個(gè)共享變量,當(dāng)檢測(cè)到為false時(shí),及時(shí)打斷其他線程,這樣的話,就解決了上面的那個(gè)問題。

    免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問題,請(qǐng)聯(lián)系我們,謝謝!

    本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
    換一批
    延伸閱讀

    9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

    關(guān)鍵字: 阿維塔 塞力斯 華為

    倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時(shí)1.5...

    關(guān)鍵字: 汽車 人工智能 智能驅(qū)動(dòng) BSP

    北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

    關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

    8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

    關(guān)鍵字: 騰訊 編碼器 CPU

    8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

    關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

    8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

    關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

    要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

    關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

    北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

    關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

    北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

    關(guān)鍵字: BSP 信息技術(shù)
    關(guān)閉
    關(guān)閉