日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

通过java.util.concurrent写多线程程序

發(fā)布時間:2025/7/14 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 通过java.util.concurrent写多线程程序 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
在JDK 1.5之前,要實現(xiàn)多線程的功能,得用到Thread這個類,通過這個類設(shè)計多線程程序,需要考慮性能,死鎖,資源等很多因素,一句話,就是相當麻煩,而且很容易出問題。所幸的是,在JDK1.5之后,java.util.concurrent包出現(xiàn)了,這是一個設(shè)計良好的多線程工具類,本文就將介紹該類的基本使用方法。 按照本博的風格,依然是先扔上一段示例代碼,然后我們再慢慢講解 package com.giantray;import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;public class TestConcurrent {public static ExecutorService exec = Executors.newCachedThreadPool();public void startMutilThread(){int taskNum = 2;final CountDownLatch cd = new CountDownLatch(taskNum );//任務(wù)1exec.submit(new Runnable(){@Overridepublic void run(){System. out.println("1 start" );try {Thread. sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}cd.countDown();System. out.println("1 end" );}});//任務(wù)2exec.submit(new Runnable(){@Overridepublic void run(){System. out.println("2 start" );cd.countDown();System. out.println("2 end" );}});System. out.println("submit end" );try{cd.await();}catch (InterruptedException e){}System. out.print("end" );}public static void main(String[] args) {TestConcurrent testThread = new TestConcurrent();testThread.startMutilThread();} }
輸出 1 start submit end 2 start 2 end 1 end end

下面進行詳細介紹:

一、使用流程

1、ExecutorService exec = ?Executors.newCachedThreadPool();獲得一個線程池
2、final CountDownLatch cd = new CountDownLatch(taskNum ); 定義計數(shù)器,指定要并發(fā)執(zhí)行的任務(wù)數(shù)
3、 exec .submit( new Runnable(){};定義任務(wù)的執(zhí)行邏輯
4、cd.countDown();任務(wù)結(jié)束了,要讓計算器減1
5、cd.await();表示等待計數(shù)器小于等于0時,再繼續(xù)往下走其他邏輯

二、線程池的管理

除了示例中的newCachedThreadPool(),也有其他各種類型的線程池:
1、newFixedThreadPool(固定大小線程池)
線程數(shù)是固定的,例如線程數(shù)設(shè)為1,則需要等待任務(wù)1結(jié)束后,才執(zhí)行任務(wù)2;如設(shè)為2,則兩個任務(wù)能同時執(zhí)行
2、newCachedThreadPool(無限制大小的線程池)
線程數(shù)無固定大小,當前無可用線程,就回創(chuàng)建新線程。如果任務(wù)1沒結(jié)束,那么啟動任務(wù)2時,就會新建線程,這時線程池大小為2;但假如啟動任務(wù)2時,任務(wù)1已結(jié)束,則不會新建線程,會沿用任務(wù)1使用的線程
3、newSingleThreadExecutor(單線程)
使用單線程池時,就沒辦法同時執(zhí)行多個任務(wù),因此,本例中的任務(wù)1執(zhí)行完后,才會執(zhí)行任務(wù)2
4、newScheduledThreadPool(定時任務(wù)線程池)
支持定時任務(wù)的線程池,與Timer,Quartz一樣,常見于一些定時任務(wù)調(diào)度程序·

三、計數(shù)器CountDownLatch

1、示例講解

在示例中,我們通過多線程執(zhí)行了兩個任務(wù)。之后我們需要知道,兩個任務(wù)是否都執(zhí)行結(jié)束?都執(zhí)行結(jié)束了,我們才能繼續(xù)執(zhí)行接下來的其他邏輯。為了這個目的,需要引入CountDownLatch這個計數(shù)器。先聲明一個計算量為TaskNum(2)的計數(shù)器,接著,每個任務(wù)執(zhí)行結(jié)束時,要執(zhí)行countDown()方法,而最后的await()方法表示,如果CountDownLatch不為零,那么就在這里等待,下面的邏輯會被阻塞住,不會繼續(xù)執(zhí)行,等待兩個任務(wù)都執(zhí)行結(jié)束了--執(zhí)行兩次countDown()方法,計數(shù)器等于0,這時候程序才會繼續(xù)往下執(zhí)行System. out.print("end")這行代碼

2、它的兄弟CyclicBarrier

還有一個類似CountDownLatch的計數(shù)器,名為CyclicBarrier。這兩者的區(qū)別:CountDownLatch被減至0后,是不能重置的。而CyclicBarrier被減至0后,會自動恢復(fù)至初始值,因此它是一個循環(huán)的計數(shù)器,舉一個例子,運動員跑步,這是一個任務(wù),而這個任務(wù),又分為運動員準備,以及開跑兩個子任務(wù),所有的運動員,必須等待其他運動員都”準備“好后,才能起跑。為了實現(xiàn)這個邏輯,及可以用到CyclicBarrier,CyclicBarrier的計數(shù)初始值為運動員數(shù)量,運動員準備完畢時,讓計數(shù)器減1,這時候它不會進行”開跑“,等到計數(shù)器減為0時,所有運動員才同時“起跑”,并且會重新恢復(fù)至初始值,等到所有運動員都跑完時,計數(shù)器才又恢復(fù)為0,這時候,才能再繼續(xù)執(zhí)行其他任務(wù)。而如果使用CyclicBarrier,在線程執(zhí)行過程中,是不能等待其他線程的,不能等其他線程都“準備”好了,所有線程再一起“開跑”

四、并發(fā)執(zhí)行

多運行幾次示例程序,會發(fā)現(xiàn),有時候,"2 start"會早于"1 start"輸出,因此,不一定是先submit的任務(wù),就先“開始執(zhí)行”。這也告訴我們,不能想當然地以為,任務(wù)1先submit,就可以在任務(wù)1里做一些全局初始化的工作,然后在任務(wù)2里可以去拿任務(wù)1初始化的變量。

五、線程池的生命周期管理

1、三種基本狀態(tài)

線程池的聲明周期有三個狀態(tài),運行,關(guān)閉,終止。初始化線程時,處于運行狀態(tài),執(zhí)行shutdown()方法后,處于關(guān)閉狀態(tài),但這時候線程任務(wù)會繼續(xù)執(zhí)行,當所有任務(wù)都結(jié)束后,才會變成終止狀態(tài)。

2、shutdown()與shutdownNow()的區(qū)別

這兩個方法都用于關(guān)閉線程池
shutdown() 關(guān)閉線程池,但之前提交的任務(wù),會繼續(xù)執(zhí)行;如果新提交任務(wù),會拋異常
shutdownNow() 馬上關(guān)閉線程池,之前提交的任務(wù),如果還未執(zhí)行完,會被終止,且拋出異常

3、shutdown()的作用

  • ? 釋放線程池資源(其實不關(guān)閉線程池,會資源會有多大的消耗,筆者也不清楚)
  • ? 可以讓程序有序退出。這是什么意思呢?講一個例子,你就明白了。假如你的程序正在并發(fā)執(zhí)行任務(wù),而且還一直會提交新的任務(wù)。這時候,該如何設(shè)計程序的“退出”功能呢?首先,為了任務(wù)的原子性,希望能執(zhí)行完已提交的任務(wù),并且阻止新的任務(wù)提交。這時候,就得用到了shutdown()了。退出功能的代碼可以是這樣:
System.out.println("準備退出程序"); service.shutdown(); while (true) {try {System.out.println("等待“已提交任務(wù)”執(zhí)行結(jié)束");//awaitTerminationm,先等待5秒,再檢查任務(wù)是否結(jié)束if (service.awaitTermination(5, TimeUnit.SECONDS)) {break;}} catch (InterruptedException e) {} } System.out.println("”已提交任務(wù)“執(zhí)行完,程序可以安全退出");

六、獲取線程任務(wù)的執(zhí)行結(jié)果

如果想知道任務(wù)的執(zhí)行結(jié)果,就得使用Future和Callable。Future可以拿到結(jié)果,而Callable能返回值,用于產(chǎn)生結(jié)果
對示例代碼做下修改,其中,task1.get()將拿到call()方法的return值,也就是示例中的"false"
int taskNum = 1; final CountDownLatch cd = new CountDownLatch(taskNum);Future<Boolean> task1 = exec.submit(new Callable<Boolean>(){@Overridepublic Boolean call() throws Exception {System.out.println("1 start");cd.countDown();System.out.println("1 end");return false;}});try {cd.await();Boolean result = task1.get();System.out.println("result : " + result); } catch (InterruptedException e) {e.printStackTrace(); } catch (ExecutionException e) {e.printStackTrace(); } System.out.print("end");

?

總結(jié)

以上是生活随笔為你收集整理的通过java.util.concurrent写多线程程序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。