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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java中线程池的几种实现方式

發(fā)布時(shí)間:2023/12/10 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java中线程池的几种实现方式 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1、線程池簡(jiǎn)介:
??? 多線程技術(shù)主要解決處理器單元內(nèi)多個(gè)線程執(zhí)行的問(wèn)題,它可以顯著減少處理器單元的閑置時(shí)間,增加處理器單元的吞吐能力。????
??? 假設(shè)一個(gè)服務(wù)器完成一項(xiàng)任務(wù)所需時(shí)間為:T1 創(chuàng)建線程時(shí)間,T2 在線程中執(zhí)行任務(wù)的時(shí)間,T3 銷(xiāo)毀線程時(shí)間。

??? 如果:T1 + T3 遠(yuǎn)大于 T2,則可以采用線程池,以提高服務(wù)器性能。
??????????????? 一個(gè)線程池包括以下四個(gè)基本組成部分:
??????????????? 1、線程池管理器(ThreadPool):用于創(chuàng)建并管理線程池,包括 創(chuàng)建線程池,銷(xiāo)毀線程池,添加新任務(wù);
??????????????? 2、工作線程(PoolWorker):線程池中線程,在沒(méi)有任務(wù)時(shí)處于等待狀態(tài),可以循環(huán)的執(zhí)行任務(wù);
??????????????? 3、任務(wù)接口(Task):每個(gè)任務(wù)必須實(shí)現(xiàn)的接口,以供工作線程調(diào)度任務(wù)的執(zhí)行,它主要規(guī)定了任務(wù)的入口,任務(wù)執(zhí)行完后的收尾工作,任務(wù)的執(zhí)行狀態(tài)等;
??????????????? 4、任務(wù)隊(duì)列(taskQueue):用于存放沒(méi)有處理的任務(wù)。提供一種緩沖機(jī)制。
????????????????
??? 線程池技術(shù)正是關(guān)注如何縮短或調(diào)整T1,T3時(shí)間的技術(shù),從而提高服務(wù)器程序性能的。它把T1,T3分別安排在服務(wù)器程序的啟動(dòng)和結(jié)束的時(shí)間段或者一些空閑的時(shí)間段,這樣在服務(wù)器程序處理客戶請(qǐng)求時(shí),不會(huì)有T1,T3的開(kāi)銷(xiāo)了。
??? 線程池不僅調(diào)整T1,T3產(chǎn)生的時(shí)間段,而且它還顯著減少了創(chuàng)建線程的數(shù)目,看一個(gè)例子:
??? 假設(shè)一個(gè)服務(wù)器一天要處理50000個(gè)請(qǐng)求,并且每個(gè)請(qǐng)求需要一個(gè)單獨(dú)的線程完成。在線程池中,線程數(shù)一般是固定的,所以產(chǎn)生線程總數(shù)不會(huì)超過(guò)線程池中線程的數(shù)目,而如果服務(wù)器不利用線程池來(lái)處理這些請(qǐng)求則線程總數(shù)為50000。一般線程池大小是遠(yuǎn)小于50000。所以利用線程池的服務(wù)器程序不會(huì)為了創(chuàng)建50000而在處理請(qǐng)求時(shí)浪費(fèi)時(shí)間,從而提高效率。

??? 代碼實(shí)現(xiàn)中并沒(méi)有實(shí)現(xiàn)任務(wù)接口,而是把Runnable對(duì)象加入到線程池管理器(ThreadPool),然后剩下的事情就由線程池管理器(ThreadPool)來(lái)完成了

?

package mine.util.thread; import java.util.LinkedList; import java.util.List; /** * 線程池類(lèi),線程管理器:創(chuàng)建線程,執(zhí)行任務(wù),銷(xiāo)毀線程,獲取線程基本信息 */ public final class ThreadPool { // 線程池中默認(rèn)線程的個(gè)數(shù)為5 private static int worker_num = 5; // 工作線程 private WorkThread[] workThrads; // 未處理的任務(wù) private static volatile int finished_task = 0; // 任務(wù)隊(duì)列,作為一個(gè)緩沖,List線程不安全 private List<Runnable> taskQueue = new LinkedList<Runnable>(); private static ThreadPool threadPool; // 創(chuàng)建具有默認(rèn)線程個(gè)數(shù)的線程池 private ThreadPool() { this(5); } // 創(chuàng)建線程池,worker_num為線程池中工作線程的個(gè)數(shù) private ThreadPool(int worker_num) { ThreadPool.worker_num = worker_num; workThrads = new WorkThread[worker_num]; for (int i = 0; i < worker_num; i++) { workThrads[i] = new WorkThread(); workThrads[i].start();// 開(kāi)啟線程池中的線程 } } // 單態(tài)模式,獲得一個(gè)默認(rèn)線程個(gè)數(shù)的線程池 public static ThreadPool getThreadPool() { return getThreadPool(ThreadPool.worker_num); } // 單態(tài)模式,獲得一個(gè)指定線程個(gè)數(shù)的線程池,worker_num(>0)為線程池中工作線程的個(gè)數(shù) // worker_num<=0創(chuàng)建默認(rèn)的工作線程個(gè)數(shù) public static ThreadPool getThreadPool(int worker_num1) { if (worker_num1 <= 0) worker_num1 = ThreadPool.worker_num; if (threadPool == null) threadPool = new ThreadPool(worker_num1); return threadPool; } // 執(zhí)行任務(wù),其實(shí)只是把任務(wù)加入任務(wù)隊(duì)列,什么時(shí)候執(zhí)行有線程池管理器覺(jué)定 public void execute(Runnable task) { synchronized (taskQueue) { taskQueue.add(task); taskQueue.notify(); } } // 批量執(zhí)行任務(wù),其實(shí)只是把任務(wù)加入任務(wù)隊(duì)列,什么時(shí)候執(zhí)行有線程池管理器覺(jué)定 public void execute(Runnable[] task) { synchronized (taskQueue) { for (Runnable t : task) taskQueue.add(t); taskQueue.notify(); } } // 批量執(zhí)行任務(wù),其實(shí)只是把任務(wù)加入任務(wù)隊(duì)列,什么時(shí)候執(zhí)行有線程池管理器覺(jué)定 public void execute(List<Runnable> task) { synchronized (taskQueue) { for (Runnable t : task) taskQueue.add(t); taskQueue.notify(); } } // 銷(xiāo)毀線程池,該方法保證在所有任務(wù)都完成的情況下才銷(xiāo)毀所有線程,否則等待任務(wù)完成才銷(xiāo)毀 public void destroy() { while (!taskQueue.isEmpty()) {// 如果還有任務(wù)沒(méi)執(zhí)行完成,就先睡會(huì)吧 try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } // 工作線程停止工作,且置為null for (int i = 0; i < worker_num; i++) { workThrads[i].stopWorker(); workThrads[i] = null; } threadPool=null; taskQueue.clear();// 清空任務(wù)隊(duì)列 } // 返回工作線程的個(gè)數(shù) public int getWorkThreadNumber() { return worker_num; } // 返回已完成任務(wù)的個(gè)數(shù),這里的已完成是只出了任務(wù)隊(duì)列的任務(wù)個(gè)數(shù),可能該任務(wù)并沒(méi)有實(shí)際執(zhí)行完成 public int getFinishedTasknumber() { return finished_task; } // 返回任務(wù)隊(duì)列的長(zhǎng)度,即還沒(méi)處理的任務(wù)個(gè)數(shù) public int getWaitTasknumber() { return taskQueue.size(); } // 覆蓋toString方法,返回線程池信息:工作線程個(gè)數(shù)和已完成任務(wù)個(gè)數(shù) @Override public String toString() { return "WorkThread number:" + worker_num + " finished task number:" + finished_task + " wait task number:" + getWaitTasknumber(); } /** * 內(nèi)部類(lèi),工作線程 */ private class WorkThread extends Thread { // 該工作線程是否有效,用于結(jié)束該工作線程 private boolean isRunning = true; /* * 關(guān)鍵所在啊,如果任務(wù)隊(duì)列不空,則取出任務(wù)執(zhí)行,若任務(wù)隊(duì)列空,則等待 */ @Override public void run() { Runnable r = null; while (isRunning) {// 注意,若線程無(wú)效則自然結(jié)束run方法,該線程就沒(méi)用了 synchronized (taskQueue) { while (isRunning && taskQueue.isEmpty()) {// 隊(duì)列為空 try { taskQueue.wait(20); } catch (InterruptedException e) { e.printStackTrace(); } } if (!taskQueue.isEmpty()) r = taskQueue.remove(0);// 取出任務(wù) } if (r != null) { r.run();// 執(zhí)行任務(wù) } finished_task++; r = null; } } // 停止工作,讓該線程自然執(zhí)行完run方法,自然結(jié)束 public void stopWorker() { isRunning = false; } } }

注意!多線程安全,或者說(shuō)synchronize 一般是用在“增”,“刪”,“改”代碼段上;

測(cè)試代碼:

package mine.util.thread; //測(cè)試線程池 public class TestThreadPool { public static void main(String[] args) { // 創(chuàng)建3個(gè)線程的線程池 ThreadPool t = ThreadPool.getThreadPool(3); t.execute(new Runnable[] { new Task(), new Task(), new Task() }); t.execute(new Runnable[] { new Task(), new Task(), new Task() }); System.out.println(t); t.destroy();// 所有線程都執(zhí)行完成才destory System.out.println(t); } // 任務(wù)類(lèi) static class Task implements Runnable { private static volatile int i = 1; @Override public void run() {// 執(zhí)行任務(wù) System.out.println("任務(wù) " + (i++) + " 完成"); } } }

運(yùn)行結(jié)果:

WorkThread number:3? finished task number:0? wait task number:6
任務(wù) 1 完成
任務(wù) 2 完成
任務(wù) 3 完成
任務(wù) 4 完成
任務(wù) 5 完成
任務(wù) 6 完成
WorkThread number:3? finished task number:6? wait task number:0

分析:由于并沒(méi)有任務(wù)接口,傳入的可以是自定義的任何任務(wù),所以線程池并不能準(zhǔn)確的判斷該任務(wù)是否真正的已經(jīng)完成(真正完成該任務(wù)是這個(gè)任務(wù)的run方法執(zhí)行完畢),只能知道該任務(wù)已經(jīng)出了任務(wù)隊(duì)列,正在執(zhí)行或者已經(jīng)完成。

?

2、Java類(lèi)庫(kù)中提供的線程池簡(jiǎn)介:

???? java提供的線程池更加強(qiáng)大,相信理解線程池的工作原理,看類(lèi)庫(kù)中的線程池就不會(huì)感到陌生了。

在Java5之后,并 發(fā)線程這塊發(fā)生了根本的變化,最重要的莫過(guò)于新的啟動(dòng)、調(diào)度、管理線程的一大堆API了。在Java5以后,通過(guò)Executor來(lái)啟動(dòng)線程比用 Thread的start()更好。在新特征中,可以很容易控制線程的啟動(dòng)、執(zhí)行和關(guān)閉過(guò)程,還可以很容易使用線程池的特性。

參考:https://www.cnblogs.com/mokafamily/p/3558886.html

參考:https://www.cnblogs.com/zhujiabin/p/5404771.html

下面我們來(lái)詳細(xì)了解下這些線程池。

2、Java 線程池

Java通過(guò)Executors提供四種線程池,分別為:
newCachedThreadPool創(chuàng)建一個(gè)可緩存線程池,如果線程池長(zhǎng)度超過(guò)處理需要,可靈活回收空閑線程,若無(wú)可回收,則新建線程。
newFixedThreadPool 創(chuàng)建一個(gè)定長(zhǎng)線程池,可控制線程最大并發(fā)數(shù),超出的線程會(huì)在隊(duì)列中等待。
newScheduledThreadPool 創(chuàng)建一個(gè)定長(zhǎng)線程池,支持定時(shí)及周期性任務(wù)執(zhí)行。
newSingleThreadExecutor 創(chuàng)建一個(gè)單線程化的線程池,它只會(huì)用唯一的工作線程來(lái)執(zhí)行任務(wù),保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級(jí))執(zhí)行。

  當(dāng)你挑選完的線程池后就需要?jiǎng)?chuàng)建以及使用線程池:

    大概步驟為以下3步:

   ?(1)調(diào)用執(zhí)行器類(lèi)(Executors)的靜態(tài)方法來(lái)創(chuàng)建線程池

    (2)調(diào)用線程池的submit方法提交Runnable或Callable對(duì)象

    (3)當(dāng)不需要添加更多的任務(wù)時(shí),調(diào)用shutdown關(guān)閉入口

?

  下面通過(guò)代碼來(lái)逐步操作:

//創(chuàng)建線程池對(duì)象ExecutorService service = Executors.newCachedThreadPool();//創(chuàng)建一個(gè)用于遞增輸出i值的runnable對(duì)象Runnable runnable = new Runnable() {@Overridepublic void run() {for (int i = 0; i < 400; i++) {System.out.println(i);}}};//調(diào)用線程池的submit方法傳入runnable(傳入的runnable將會(huì)自動(dòng)執(zhí)行)service.submit(runnable);service.submit(runnable);//當(dāng)不需要傳入更多的任務(wù)時(shí)調(diào)用shutdown方法來(lái)關(guān)閉入口service.shutdown();

  需要注意的是如果希望直接停止線程池的一切任務(wù)是無(wú)法通過(guò)shutdown來(lái)操作的,因?yàn)閟hutdown僅僅是關(guān)閉了入口,但是已經(jīng)加入的任務(wù)還是會(huì)繼續(xù)執(zhí)行的,這時(shí)我們可以調(diào)用線程池的shutdownNow方法來(lái)操作,shutdownNow的作用是用來(lái)關(guān)閉線程池的入口并且會(huì)嘗試終止所有當(dāng)前線程池內(nèi)的任務(wù)。

//用來(lái)關(guān)閉線程池入口以及終止所有正在執(zhí)行的任務(wù)service.shutdownNow();

 service的submit方法會(huì)返回一個(gè)Future<?>類(lèi)型的對(duì)象,然而這是一個(gè)怎樣的類(lèi)型呢?讓我們來(lái)看一下api中的方法摘要:

?

?  

?

?  從方法摘要中可以看出該對(duì)象用于在加入線程池以后能夠?qū)Υ巳蝿?wù)進(jìn)行取消,查看狀態(tài)等操作,如果說(shuō)在加入線程池以后有可能會(huì)取消此任務(wù)的話就需要,在submit的時(shí)候就需要保存好Future對(duì)象。

?

//保存Future<?>Future<?> run2 = service.submit(runnable);//用于查看是否已經(jīng)執(zhí)行完畢,返回類(lèi)型為booleanSystem.out.println(run2.isDone());//取消任務(wù),如果需要中斷的話參數(shù)為truerun2.cancel(true);

3.線程池實(shí)例:

(1). newCachedThreadPool
創(chuàng)建一個(gè)可緩存線程池,如果線程池長(zhǎng)度超過(guò)處理需要,可靈活回收空閑線程,若無(wú)可回收,則新建線程。示例代碼如下:

ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { final int index = i; try { Thread.sleep(index * 1000); } catch (InterruptedException e) { e.printStackTrace(); }cachedThreadPool.execute(new Runnable() {@Override public void run() { System.out.println(index); } }); }

線程池為無(wú)限大,當(dāng)執(zhí)行第二個(gè)任務(wù)時(shí)第一個(gè)任務(wù)已經(jīng)完成,會(huì)復(fù)用執(zhí)行第一個(gè)任務(wù)的線程,而不用每次新建線程。

注意! executeService.submit() 有返回值 返回類(lèi)型為future ,exeuteService.execute() 沒(méi)有返回值

?(2). newFixedThreadPool
創(chuàng)建一個(gè)定長(zhǎng)線程池,可控制線程最大并發(fā)數(shù),超出的線程會(huì)在隊(duì)列中等待。示例代碼如下:

?

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3); for (int i = 0; i < 10; i++) { final int index = i; fixedThreadPool.execute(new Runnable() {@Override public void run() { try { System.out.println(index); Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); }

因?yàn)榫€程池大小為3,每個(gè)任務(wù)輸出index后sleep 2秒,所以每?jī)擅氪蛴?個(gè)數(shù)字。

定長(zhǎng)線程池的大小最好根據(jù)系統(tǒng)資源進(jìn)行設(shè)置。如Runtime.getRuntime().availableProcessors()。可參考PreloadDataCache。

?(3) newScheduledThreadPool
創(chuàng)建一個(gè)定長(zhǎng)線程池,支持定時(shí)及周期性任務(wù)執(zhí)行。延遲執(zhí)行示例代碼如下:

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); scheduledThreadPool.schedule(new Runnable() {@Override public void run() { System.out.println("delay 3 seconds"); } }, 3, TimeUnit.SECONDS);

表示延遲3秒執(zhí)行。

定期執(zhí)行示例代碼如下:

scheduledThreadPool.scheduleAtFixedRate(new Runnable() {@Override public void run() { System.out.println("delay 1 seconds, and excute every 3 seconds"); } }, 1, 3, TimeUnit.SECONDS);

表示延遲1秒后每3秒執(zhí)行一次。

ScheduledExecutorService比Timer更安全,功能更強(qiáng)大,后面會(huì)有一篇單獨(dú)進(jìn)行對(duì)比。

(4)、newSingleThreadExecutor
創(chuàng)建一個(gè)單線程化的線程池,它只會(huì)用唯一的工作線程來(lái)執(zhí)行任務(wù),保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級(jí))執(zhí)行。示例代碼如下:

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { final int index = i; singleThreadExecutor.execute(new Runnable() {@Override public void run() { try { System.out.println(index); Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }); }

?

線程池的作用:

線程池作用就是限制系統(tǒng)中執(zhí)行線程的數(shù)量。
???? 根 據(jù)系統(tǒng)的環(huán)境情況,可以自動(dòng)或手動(dòng)設(shè)置線程數(shù)量,達(dá)到運(yùn)行的最佳效果;少了浪費(fèi)了系統(tǒng)資源,多了造成系統(tǒng)擁擠效率不高。用線程池控制線程數(shù)量,其他線程排 隊(duì)等候。一個(gè)任務(wù)執(zhí)行完畢,再?gòu)年?duì)列的中取最前面的任務(wù)開(kāi)始執(zhí)行。若隊(duì)列中沒(méi)有等待進(jìn)程,線程池的這一資源處于等待。當(dāng)一個(gè)新任務(wù)需要運(yùn)行時(shí),如果線程池 中有等待的工作線程,就可以開(kāi)始運(yùn)行了;否則進(jìn)入等待隊(duì)列。

為什么要用線程池:

1.減少了創(chuàng)建和銷(xiāo)毀線程的次數(shù),每個(gè)工作線程都可以被重復(fù)利用,可執(zhí)行多個(gè)任務(wù)。

2.可以根據(jù)系統(tǒng)的承受能力,調(diào)整線程池中工作線線程的數(shù)目,防止因?yàn)橄倪^(guò)多的內(nèi)存,而把服務(wù)器累趴下(每個(gè)線程需要大約1MB內(nèi)存,線程開(kāi)的越多,消耗的內(nèi)存也就越大,最后死機(jī))。

Java里面線程池的頂級(jí)接口是Executor,但是嚴(yán)格意義上講Executor并不是一個(gè)線程池,而只是一個(gè)執(zhí)行線程的工具。真正的線程池接口是ExecutorService。

比較重要的幾個(gè)類(lèi):

ExecutorService

真正的線程池接口。

ScheduledExecutorService

能和Timer/TimerTask類(lèi)似,解決那些需要任務(wù)重復(fù)執(zhí)行的問(wèn)題。

ThreadPoolExecutor

ExecutorService的默認(rèn)實(shí)現(xiàn)。

ScheduledThreadPoolExecutor

繼承ThreadPoolExecutor的ScheduledExecutorService接口實(shí)現(xiàn),周期性任務(wù)調(diào)度的類(lèi)實(shí)現(xiàn)。

要配置一個(gè)線程池是比較復(fù)雜的,尤其是對(duì)于線程池的原理不是很清楚的情況下,很有可能配置的線程池不是較優(yōu)的,因此在Executors類(lèi)里面提供了一些靜態(tài)工廠,生成一些常用的線程池。

1. newSingleThreadExecutor

創(chuàng)建一個(gè)單線程的線程池。這個(gè)線程池只有一個(gè)線程在工作,也就是相當(dāng)于單線程串行執(zhí)行所有任務(wù)。如果這個(gè)唯一的線程因?yàn)楫惓=Y(jié)束,那么會(huì)有一個(gè)新的線程來(lái)替代它。此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行。

2.newFixedThreadPool

創(chuàng)建固定大小的線程池。每次提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線程,直到線程達(dá)到線程池的最大大小。線程池的大小一旦達(dá)到最大值就會(huì)保持不變,如果某個(gè)線程因?yàn)閳?zhí)行異常而結(jié)束,那么線程池會(huì)補(bǔ)充一個(gè)新線程。

3. newCachedThreadPool

創(chuàng)建一個(gè)可緩存的線程池。如果線程池的大小超過(guò)了處理任務(wù)所需要的線程,

那么就會(huì)回收部分空閑(60秒不執(zhí)行任務(wù))的線程,當(dāng)任務(wù)數(shù)增加時(shí),此線程池又可以智能的添加新線程來(lái)處理任務(wù)。此線程池不會(huì)對(duì)線程池大小做限制,線程池大小完全依賴(lài)于操作系統(tǒng)(或者說(shuō)JVM)能夠創(chuàng)建的最大線程大小。

4.newScheduledThreadPool

創(chuàng)建一個(gè)大小無(wú)限的線程池。此線程池支持定時(shí)以及周期性執(zhí)行任務(wù)的需求。

------------------------------------------------------------------------------------------------------

一、創(chuàng)建任務(wù)

  任務(wù)就是一個(gè)實(shí)現(xiàn)了Runnable接口的類(lèi)。

  創(chuàng)建的時(shí)候?qū)峳un方法即可。

  二、執(zhí)行任務(wù)

  通過(guò)java.util.concurrent.ExecutorService接口對(duì)象來(lái)執(zhí)行任務(wù),該接口對(duì)象通過(guò)工具類(lèi)java.util.concurrent.Executors的靜態(tài)方法來(lái)創(chuàng)建。

  Executors此包中所定義的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 類(lèi)的工廠和實(shí)用方法。

   ExecutorService提供了管理終止的方法,以及可為跟蹤一個(gè)或多個(gè)異步任務(wù)執(zhí)行狀況而生成 Future 的方法。 可以關(guān)閉 ExecutorService,這將導(dǎo)致其停止接受新任務(wù)。關(guān)閉后,執(zhí)行程序?qū)⒆詈蠼K止,這時(shí)沒(méi)有任務(wù)在執(zhí)行,也沒(méi)有任務(wù)在等待執(zhí)行,并且無(wú)法提交新任 務(wù)。

  executorService.execute(new TestRunnable());

  1、創(chuàng)建ExecutorService

  通過(guò)工具類(lèi)java.util.concurrent.Executors的靜態(tài)方法來(lái)創(chuàng)建。

  Executors此包中所定義的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 類(lèi)的工廠和實(shí)用方法。

  比如,創(chuàng)建一個(gè)ExecutorService的實(shí)例,ExecutorService實(shí)際上是一個(gè)線程池的管理工具:

  ExecutorService executorService = Executors.newCachedThreadPool();

  ExecutorService executorService = Executors.newFixedThreadPool(3);

  ExecutorService executorService = Executors.newSingleThreadExecutor();

  2、將任務(wù)添加到線程去執(zhí)行

  當(dāng)將一個(gè)任務(wù)添加到線程池中的時(shí)候,線程池會(huì)為每個(gè)任務(wù)創(chuàng)建一個(gè)線程,該線程會(huì)在之后的某個(gè)時(shí)刻自動(dòng)執(zhí)行。

  三、關(guān)閉執(zhí)行服務(wù)對(duì)象

  executorService.shutdown();

?

  四、綜合實(shí)例

package concurrent;import java.util.concurrent.ExecutorService;? import java.util.concurrent.Executors;public class TestCachedThreadPool {?public static void main(String[] args) {? //????????????????ExecutorService executorService = Executors.newCachedThreadPool();?ExecutorService executorService = Executors.newFixedThreadPool(5); //?????????ExecutorService executorService = Executors.newSingleThreadExecutor();for (int i = 0; i < 5; i++) {?executorService.execute(new TestRunnable());?System.out.println("************* a" + i + " *************");?}?executorService.shutdown();?}? }class TestRunnable implements Runnable {?public void run() {?System.out.println(Thread.currentThread().getName() + "線程被調(diào)用了。");?while (true) {?try {?Thread.sleep(5000);?System.out.println(Thread.currentThread().getName());?} catch (InterruptedException e) {?e.printStackTrace();?}?}?}? }運(yùn)行結(jié)果:************* a0 *************? ************* a1 *************? pool-1-thread-2線程被調(diào)用了。? ************* a2 *************? pool-1-thread-3線程被調(diào)用了。? pool-1-thread-1線程被調(diào)用了。? ************* a3 *************? ************* a4 *************? pool-1-thread-4線程被調(diào)用了。? pool-1-thread-5線程被調(diào)用了。? pool-1-thread-2? pool-1-thread-1? pool-1-thread-3? pool-1-thread-5? pool-1-thread-4? pool-1-thread-2? pool-1-thread-1? pool-1-thread-3? pool-1-thread-5? pool-1-thread-4?

?

 五、獲取任務(wù)的執(zhí)行的返回值

  在Java5之 后,任務(wù)分兩類(lèi):一類(lèi)是實(shí)現(xiàn)了Runnable接口的類(lèi),一類(lèi)是實(shí)現(xiàn)了Callable接口的類(lèi)。兩者都可以被ExecutorService執(zhí)行,但是 Runnable任務(wù)沒(méi)有返回值,而Callable任務(wù)有返回值。并且Callable的call()方法只能通過(guò)ExecutorService的 submit(Callable<T> task) 方法來(lái)執(zhí)行,并且返回一個(gè) <T> Future<T>,是表示任務(wù)等待完成的 Future.

  public interface Callable<V>返回結(jié)果并且可能拋出異常的任務(wù)。實(shí)現(xiàn)者定義了一個(gè)不帶任何參數(shù)的叫做 call 的方法。

  Callable 接口類(lèi)似于 Runnable,兩者都是為那些其實(shí)例可能被另一個(gè)線程執(zhí)行的類(lèi)設(shè)計(jì)的。但是 Runnable 不會(huì)返回結(jié)果,并且無(wú)法拋出經(jīng)過(guò)檢查的異常。

  Executors 類(lèi)包含一些從其他普通形式轉(zhuǎn)換成 Callable 類(lèi)的實(shí)用方法。

  Callable中的call()方法類(lèi)似Runnable的run()方法,就是前者有返回值,后者沒(méi)有。

  當(dāng)將一個(gè)Callable的對(duì)象傳遞給ExecutorService的submit方法,則該call方法自動(dòng)在一個(gè)線程上執(zhí)行,并且會(huì)返回執(zhí)行結(jié)果Future對(duì)象。

  同樣,將Runnable的對(duì)象傳遞給ExecutorService的submit方法,則該run方法自動(dòng)在一個(gè)線程上執(zhí)行,并且會(huì)返回執(zhí)行結(jié)果Future對(duì)象,但是在該Future對(duì)象上調(diào)用get方法,將返回null.

  遺憾的是,在Java API文檔中,這塊介紹的很糊涂,估計(jì)是翻譯人員還沒(méi)搞清楚的緣故吧。或者說(shuō)是注釋不到位。下面看個(gè)例子:

import java.util.ArrayList;? import java.util.List;? import java.util.concurrent.*;public class CallableDemo {?public static void main(String[] args) {?ExecutorService executorService = Executors.newCachedThreadPool();?List<Future<String>> resultList = new ArrayList<Future<String>>();//創(chuàng)建10個(gè)任務(wù)并執(zhí)行?for (int i = 0; i < 10; i++) {?//使用ExecutorService執(zhí)行Callable類(lèi)型的任務(wù),并將結(jié)果保存在future變量中?Future<String> future = executorService.submit(new TaskWithResult(i));?//將任務(wù)執(zhí)行結(jié)果存儲(chǔ)到List中?resultList.add(future);?}//遍歷任務(wù)的結(jié)果?for (Future<String> fs : resultList) {?try {?System.out.println(fs.get());?????//打印各個(gè)線程(任務(wù))執(zhí)行的結(jié)果?} catch (InterruptedException e) {?e.printStackTrace();?} catch (ExecutionException e) {?e.printStackTrace();?} finally {?//啟動(dòng)一次順序關(guān)閉,執(zhí)行以前提交的任務(wù),但不接受新任務(wù)。如果已經(jīng)關(guān)閉,則調(diào)用沒(méi)有其他作用。?executorService.shutdown();?}?}?}? }class TaskWithResult implements Callable<String> {?private int id;public TaskWithResult(int id) {?this.id = id;?}public String call() throws Exception {?System.out.println("call()方法被自動(dòng)調(diào)用,干活!!!?????????????" + Thread.currentThread().getName());?//一個(gè)模擬耗時(shí)的操作?for (int i = 999999; i > 0; i--) ;?return "call()方法被自動(dòng)調(diào)用,任務(wù)的結(jié)果是:" + id + "????" + Thread.currentThread().getName();?}? }運(yùn)行結(jié)果:call()方法被自動(dòng)調(diào)用,干活!!!?????????????pool-1-thread-1? call()方法被自動(dòng)調(diào)用,干活!!!?????????????pool-1-thread-3? call()方法被自動(dòng)調(diào)用,干活!!!?????????????pool-1-thread-4? call()方法被自動(dòng)調(diào)用,干活!!!?????????????pool-1-thread-6? call()方法被自動(dòng)調(diào)用,干活!!!?????????????pool-1-thread-2? call()方法被自動(dòng)調(diào)用,干活!!!?????????????pool-1-thread-5? call()方法被自動(dòng)調(diào)用,任務(wù)的結(jié)果是:0????pool-1-thread-1? call()方法被自動(dòng)調(diào)用,任務(wù)的結(jié)果是:1????pool-1-thread-2? call()方法被自動(dòng)調(diào)用,干活!!!?????????????pool-1-thread-2? call()方法被自動(dòng)調(diào)用,干活!!!?????????????pool-1-thread-6? call()方法被自動(dòng)調(diào)用,干活!!!?????????????pool-1-thread-4? call()方法被自動(dòng)調(diào)用,任務(wù)的結(jié)果是:2????pool-1-thread-3? call()方法被自動(dòng)調(diào)用,干活!!!?????????????pool-1-thread-3? call()方法被自動(dòng)調(diào)用,任務(wù)的結(jié)果是:3????pool-1-thread-4? call()方法被自動(dòng)調(diào)用,任務(wù)的結(jié)果是:4????pool-1-thread-5? call()方法被自動(dòng)調(diào)用,任務(wù)的結(jié)果是:5????pool-1-thread-6? call()方法被自動(dòng)調(diào)用,任務(wù)的結(jié)果是:6????pool-1-thread-2? call()方法被自動(dòng)調(diào)用,任務(wù)的結(jié)果是:7????pool-1-thread-6? call()方法被自動(dòng)調(diào)用,任務(wù)的結(jié)果是:8????pool-1-thread-4? call()方法被自動(dòng)調(diào)用,任務(wù)的結(jié)果是:9????pool-1-thread-3Process finished with exit code 0

一個(gè) ExecutorService,它使用可能的幾個(gè)池線程之一執(zhí)行每個(gè)提交的任務(wù),通常使用 Executors 工廠方法配置。

?

線程池可以解決兩個(gè)不 同問(wèn)題:由于減少了每個(gè)任務(wù)調(diào)用的開(kāi)銷(xiāo),它們通常可以在執(zhí)行大量異步任務(wù)時(shí)提供增強(qiáng)的性能,并且還可以提供綁定和管理資源(包括執(zhí)行集合任務(wù)時(shí)使用的線 程)的方法。每個(gè) ThreadPoolExecutor 還維護(hù)著一些基本的統(tǒng)計(jì)數(shù)據(jù),如完成的任務(wù)數(shù)。

?

為了便于跨大量上下文 使用,此類(lèi)提供了很多可調(diào)整的參數(shù)和擴(kuò)展掛鉤。但是,強(qiáng)烈建議程序員使用較為方便的 Executors 工廠方法Executors.newCachedThreadPool()(無(wú)界線程池,可以進(jìn)行自動(dòng)線程回收)、 Executors.newFixedThreadPool(int)(固定大小線程池)和 Executors.newSingleThreadExecutor()(單個(gè)后臺(tái)線程),它們均為大多數(shù)使用場(chǎng)景預(yù)定義了設(shè)置。

用法示例 下面給出了一個(gè)網(wǎng)絡(luò)服務(wù)的簡(jiǎn)單結(jié)構(gòu),這里線程池中的線程作為傳入的請(qǐng)求。它使用了預(yù)先配置的 Executors.newFixedThreadPool(int) 工廠方法:class NetworkService implements Runnable {private final ServerSocket serverSocket;private final ExecutorService pool;public NetworkService(int port, int poolSize)throws IOException {serverSocket = new ServerSocket(port);pool = Executors.newFixedThreadPool(poolSize);}public void run() { // run the servicetry {for (;;) {pool.execute(new Handler(serverSocket.accept()));}} catch (IOException ex) {pool.shutdown();}}}class Handler implements Runnable {private final Socket socket;Handler(Socket socket) { this.socket = socket; }public void run() {// read and service request on socket}} 下列方法分兩個(gè)階段關(guān)閉 ExecutorService。第一階段調(diào)用 shutdown 拒絕傳入任務(wù),然后調(diào)用 shutdownNow(如有必要)取消所有遺留的任務(wù):void shutdownAndAwaitTermination(ExecutorService pool) {pool.shutdown(); // Disable new tasks from being submittedtry {// Wait a while for existing tasks to terminateif (!pool.awaitTermination(60, TimeUnit.SECONDS)) {pool.shutdownNow(); // Cancel currently executing tasks// Wait a while for tasks to respond to being cancelledif (!pool.awaitTermination(60, TimeUnit.SECONDS))System.err.println("Pool did not terminate");}} catch (InterruptedException ie) {// (Re-)Cancel if current thread also interruptedpool.shutdownNow();// Preserve interrupt statusThread.currentThread().interrupt();}} 內(nèi)存一致性效果:線程中向 ExecutorService 提交 Runnable 或 Callable 任務(wù)之前的操作 happen-before 由該任務(wù)所提取的所有操作,后者依次 happen-before 通過(guò) Future.get() 獲取的結(jié)果。

轉(zhuǎn)發(fā):https://blog.csdn.net/w2393040183/article/details/52177572

總結(jié)

以上是生活随笔為你收集整理的java中线程池的几种实现方式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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