一文弄懂Java中ThreadPoolExecutor
一、ThreadPoolExecutor類講解
1、線程池狀態(tài):
五種狀態(tài):
線程池 的狀態(tài) | 說明 |
RUNNING | 允許提交并處理任務(wù) |
SHUTDOWN | 不允許提交新的任務(wù),但是會(huì)處理完已提交的任務(wù) |
STOP | 不允許提交新的任務(wù),也不會(huì)處理阻塞隊(duì)列中未執(zhí)行的任務(wù), 并設(shè)置正在執(zhí)行的線程的中斷標(biāo)志位 |
TIDYING | 所有任務(wù)執(zhí)行完畢,池中工作的線程數(shù)為0,等待執(zhí)行terminated()勾子方法 |
TERMINATED | terminated()勾子方法執(zhí)行完畢 |
- 線程池的shutdown() 方法,將線程池由 RUNNING(運(yùn)行狀態(tài))轉(zhuǎn)換為 SHUTDOWN狀態(tài)
- 線程池的shutdownNow()方法,將線程池由RUNNING 或 SHUTDOWN 狀態(tài)轉(zhuǎn)換為 STOP 狀態(tài)。
注:SHUTDOWN 狀態(tài) 和 STOP 狀態(tài) 先會(huì)轉(zhuǎn)變?yōu)?TIDYING 狀態(tài),最終都會(huì)變?yōu)?TERMINATED
2、ThreadPoolExecutor構(gòu)造函數(shù):
ThreadPoolExecutor繼承自AbstractExecutorService,而AbstractExecutorService實(shí)現(xiàn)了ExecutorService接口。
接下來我們分別講解這些參數(shù)的含義。
2.1)線程池工作原理:
- corePoolSize :線程池中核心線程數(shù)的最大值
- maximumPoolSize :線程池中能擁有最多線程數(shù)
- workQueue:用于緩存任務(wù)的阻塞隊(duì)列
當(dāng)調(diào)用線程池execute() 方法添加一個(gè)任務(wù)時(shí),線程池會(huì)做如下判斷:
- 如果有空閑線程,則直接執(zhí)行該任務(wù);
- 如果沒有空閑線程,且當(dāng)前運(yùn)行的線程數(shù)少于corePoolSize,則創(chuàng)建新的線程執(zhí)行該任務(wù);
- 如果沒有空閑線程,且當(dāng)前的線程數(shù)等于corePoolSize,同時(shí)阻塞隊(duì)列未滿,則將任務(wù)入隊(duì)列,而不添加新的線程;
- 如果沒有空閑線程,且阻塞隊(duì)列已滿,同時(shí)池中的線程數(shù)小于maximumPoolSize ,則創(chuàng)建新的線程執(zhí)行任務(wù);
- 如果沒有空閑線程,且阻塞隊(duì)列已滿,同時(shí)池中的線程數(shù)等于maximumPoolSize ,則根據(jù)構(gòu)造函數(shù)中的 handler 指定的策略來拒絕新的任務(wù)。
2.2)KeepAliveTime:
- keepAliveTime :表示空閑線程的存活時(shí)間
- TimeUnit unit :表示keepAliveTime的單位
當(dāng)一個(gè)線程無事可做,超過一定的時(shí)間(keepAliveTime)時(shí),線程池會(huì)判斷,如果當(dāng)前運(yùn)行的線程數(shù)大于 corePoolSize,那么這個(gè)線程就被停掉。所以線程池的所有任務(wù)完成后,它最終會(huì)收縮到 corePoolSize 的大小。
注:如果線程池設(shè)置了allowCoreThreadTimeout參數(shù)為true(默認(rèn)false),那么當(dāng)空閑線程超過keepaliveTime后直接停掉。(不會(huì)判斷線程數(shù)是否大于corePoolSize)即:最終線程數(shù)會(huì)變?yōu)?。
2.3)workQueue 任務(wù)隊(duì)列:
- workQueue :它決定了緩存任務(wù)的排隊(duì)策略
ThreadPoolExecutor線程池推薦了三種等待隊(duì)列,它們是:SynchronousQueue 、LinkedBlockingQueue 和 ArrayBlockingQueue。
1)有界隊(duì)列:
- SynchronousQueue :一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列,每個(gè)插入操作必須等到另一個(gè)線程調(diào)用移除操作,否則插入操作一直處于 阻塞狀態(tài),吞吐量通常要高于LinkedBlockingQueue,靜態(tài)工廠方法 Executors.newCachedThreadPool 使用了這個(gè)隊(duì)列。
- ArrayBlockingQueue:一個(gè)由數(shù)組支持的有界阻塞隊(duì)列。此隊(duì)列按 FIFO(先進(jìn)先出)原則對(duì)元素進(jìn)行排序。一旦創(chuàng)建了這樣的緩存區(qū),就不能再增加其容量。試圖向已滿隊(duì)列中放入元素會(huì)導(dǎo)致操作受阻塞;試圖從空隊(duì)列中提取元素將導(dǎo)致類似阻塞。
2)無界隊(duì)列:
- LinkedBlockingQueue:基于鏈表結(jié)構(gòu)的無界阻塞隊(duì)列,它可以指定容量也可以不指定容量(實(shí)際上任何無限容量的隊(duì)列/棧都是有容量的,這個(gè)容量就是Integer.MAX_VALUE)
- PriorityBlockingQueue:是一個(gè)按照優(yōu)先級(jí)進(jìn)行內(nèi)部元素排序的無界阻塞隊(duì)列。隊(duì)列中的元素必須實(shí)現(xiàn) Comparable 接口,這樣才能通過實(shí)現(xiàn)compareTo()方法進(jìn)行排序。優(yōu)先級(jí)最高的元素將始終排在隊(duì)列的頭部;PriorityBlockingQueue 不會(huì)保證優(yōu)先級(jí)一樣的元素的排序。
注意:keepAliveTime和maximumPoolSize及BlockingQueue的類型均有關(guān)系。如果BlockingQueue是無界的,那么永遠(yuǎn)不會(huì)觸發(fā)maximumPoolSize,自然keepAliveTime也就沒有了意義。
2.4)threadFactory:
- threadFactory :指定創(chuàng)建線程的工廠。(可以不指定)
如果不指定線程工廠時(shí),ThreadPoolExecutor 會(huì)使用ThreadPoolExecutor.defaultThreadFactory 創(chuàng)建線程。默認(rèn)工廠創(chuàng)建的線程:同屬于相同的線程組,具有同為 Thread.NORM_PRIORITY 的優(yōu)先級(jí),以及名為 “pool-XXX-thread-” 的線程名(XXX為創(chuàng)建線程時(shí)順序序號(hào)),且創(chuàng)建的線程都是非守護(hù)進(jìn)程。
2.5)handler 拒絕策略:
- handler :表示當(dāng) workQueue 已滿,且池中的線程數(shù)達(dá)到 maximumPoolSize 時(shí),線程池拒絕添加新任務(wù)時(shí)采取的策略。(可以不指定)
策略 | BB |
ThreadPoolExecutor.AbortPolicy() | 拋出RejectedExecutionException異常。默認(rèn)策略 |
ThreadPoolExecutor.CallerRunsPolicy() | 由向線程池提交任務(wù)的線程來執(zhí)行該任務(wù) |
ThreadPoolExecutor.DiscardPolicy() | 拋棄當(dāng)前的任務(wù) |
ThreadPoolExecutor.DiscardOldestPolicy() | 拋棄最舊的任務(wù)(最先提交而沒有得到執(zhí)行的任務(wù)) |
最科學(xué)的的還是 AbortPolicy 提供的處理方式:拋出異常,由開發(fā)人員進(jìn)行處理。
3、常用方法:
除了在創(chuàng)建線程池時(shí)指定上述參數(shù)的值外,還可在線程池創(chuàng)建以后通過如下方法進(jìn)行設(shè)置。
此外,還有一些方法:
- getCorePoolSize():返回線程池的核心線程數(shù),這個(gè)值是一直不變的,返回在構(gòu)造函數(shù)中設(shè)置的coreSize大小;
- getMaximumPoolSize():返回線程池的最大線程數(shù),這個(gè)值是一直不變的,返回在構(gòu)造函數(shù)中設(shè)置的coreSize大?。?/li>
- getLargestPoolSize():記錄了曾經(jīng)出現(xiàn)的最大線程個(gè)數(shù)(水位線);
- getPoolSize():線程池中當(dāng)前線程的數(shù)量;
- getActiveCount():Returns the approximate(近似) number of threads that are actively executing tasks;
- prestartAllCoreThreads():會(huì)啟動(dòng)所有核心線程,無論是否有待執(zhí)行的任務(wù),線程池都會(huì)創(chuàng)建新的線程,直到池中線程數(shù)量達(dá)到 corePoolSize;
- prestartCoreThread():會(huì)啟動(dòng)一個(gè)核心線程(同上);
- allowCoreThreadTimeOut(true):允許核心線程在KeepAliveTime時(shí)間后,退出;
4、Executors類:
Executors類的底層實(shí)現(xiàn)便是ThreadPoolExecutor! Executors 工廠方法有:
- Executors.newCachedThreadPool():無界線程池,可以進(jìn)行自動(dòng)線程回收
- Executors.newFixedThreadPool(int):固定大小線程池
- Executors.newSingleThreadExecutor():單個(gè)后臺(tái)線程
它們均為大多數(shù)使用場(chǎng)景預(yù)定義了設(shè)置。不過在阿里java文檔中說明,盡量不要用該類創(chuàng)建線程池。
二、線程池相關(guān)接口介紹:
1、ExecutorService接口:
該接口是真正的線程池接口。上面的ThreadPoolExecutor以及下面的ScheduledThreadPoolExecutor都是該接口的實(shí)現(xiàn)類。改接口常用方法:
- Future<?> submit(Runnable task):提交Runnable任務(wù)到線程池,返回Future對(duì)象,由于Runnable沒有返回值,也就是說調(diào)用Future對(duì)象get()方法返回null;
- <T> Future<T> submit(Callable<T> task):提交Callable任務(wù)到線程池,返回Future對(duì)象,調(diào)用Future對(duì)象get()方法可以獲取Callable的返回值;
- <T> Future<T> submit(Runnable task,T result):提交Runnable任務(wù)到線程池,返回Future對(duì)象,調(diào)用Future對(duì)象get()方法可以獲取Runnable的參數(shù)值;
- invokeAll(collection of tasks)/invokeAll(collection of tasks, long timeout, TimeUnit unit):invokeAll會(huì)按照任務(wù)集合中的順序?qū)⑺械腇uture添加到返回的集合中,該方法是一個(gè)阻塞的方法。只有當(dāng)所有的任務(wù)都執(zhí)行完畢時(shí),或者調(diào)用線程被中斷,又或者超出指定時(shí)限時(shí),invokeAll方法才會(huì)返回。當(dāng)invokeAll返回之后每個(gè)任務(wù)要么返回,要么取消,此時(shí)客戶端可以調(diào)用get/isCancelled來判斷具體是什么情況。
- invokeAny(collection of tasks)/invokeAny(collection of tasks, long timeout, TimeUnit unit):阻塞的方法,不會(huì)返回 Future 對(duì)象,而是返回集合中某一個(gè)Callable 對(duì)象的結(jié)果,而且無法保證調(diào)用之后返回的結(jié)果是哪一個(gè) Callable,如果一個(gè)任務(wù)運(yùn)行完畢或者拋出異常,方法會(huì)取消其它的 Callable 的執(zhí)行。和invokeAll區(qū)別是只要有一個(gè)任務(wù)執(zhí)行完了,就把結(jié)果返回,并取消其他未執(zhí)行完的任務(wù);同樣,也帶有超時(shí)功能;
- shutdown():在完成已提交的任務(wù)后關(guān)閉服務(wù),不再接受新任;
- shutdownNow():停止所有正在執(zhí)行的任務(wù)并關(guān)閉服務(wù);
- isTerminated():測(cè)試是否所有任務(wù)都執(zhí)行完畢了;
- isShutdown():測(cè)試是否該ExecutorService已被關(guān)閉。
1.1)submit方法示例:
我們知道,線程池接口中有以下三個(gè)主要方法,接下來我們看一下具體示例:
1)Callable:
public static ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 50, 300, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(50), new ThreadFactory(){ public Thread newThread(Runnable r) { return new Thread(r, "schema_task_pool_" + r.hashCode()); }}, new ThreadPoolExecutor.DiscardOldestPolicy()); public static void callableTest() { int a = 1; //callable Future<Boolean> future = threadPool.submit(new Callable<Boolean>(){ @Override public Boolean call() throws Exception { int b = a + 100; System.out.println(b); return true; } }); try { System.out.println("feature.get"); Boolean boolean1 = future.get(); System.out.println(boolean1); } catch (InterruptedException e) { System.out.println("InterruptedException..."); e.printStackTrace(); } catch (ExecutionException e) { System.out.println("execute exception..."); e.printStackTrace(); } }
2)Runnable:
public static void runnableTest() { int a = 1; //runnable Future<?> future1 = threadPool.submit(new Runnable(){ @Override public void run() { int b = a + 100; System.out.println(b); } }); try { System.out.println("feature.get"); Object x = future1.get(900,TimeUnit.MILLISECONDS); System.out.println(x);//null } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { System.out.println("execute exception..."); e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } }
3)Runnable+result:
class RunnableTask implements Runnable { Person p; RunnableTask(Person p) { this.p = p; } @Override public void run() { p.setId(1); p.setName("Runnable Task..."); } } class Person { private Integer id; private String name; public Person(Integer id, String name) { super(); this.id = id; this.name = name; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + "]"; } } public static void runnableTest2() { //runnable + result Person p = new Person(0,"person"); Future<Person> future2 = threadPool.submit(new RunnableTask(p),p); try { System.out.println("feature.get"); Person person = future2.get(); System.out.println(person); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } }
1.2)線程池執(zhí)行時(shí),Callable的call方法(Runnable的run方法)拋出異常后,會(huì)出現(xiàn)什么?
在上面的例子中我們可以看到,線程池?zé)o論是執(zhí)行Callable還是Runnable,調(diào)用返回的Future對(duì)象get()方法時(shí)需要處理兩種異常(如果是調(diào)用get(timeout)方法,需要處理三種異常),如下:
//在線程池上運(yùn)行 Future<Object> future = threadPool.submit(callable); try { System.out.println("feature.get"); Object x = future.get(900,TimeUnit.MILLISECONDS); System.out.println(x); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { System.out.println("execute exception..."); e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); }
- 如果get方法被打斷,進(jìn)入InterruptedException異常;
- 如果線程執(zhí)行過程(call、run方法)中拋出異常,進(jìn)入ExecutionException異常;
- 如果get方法超時(shí),進(jìn)入TimeoutException異常;
1.3)submit()和execute()方法區(qū)別:
ExecutorService、ScheduledExecutorService接口的submit()和execute()方法都是把任務(wù)提交到線程池中,但二者的區(qū)別是
- 接收的參數(shù)不一樣,execute只能接收Runnable類型、submit可以接收Runnable和Callable兩種類型;
- submit有返回值,而execute沒有返回值;submit方便Exception處理;
1)submit方法內(nèi)部實(shí)現(xiàn):
其實(shí)submit方法也沒有什么神秘的,就是將我們的任務(wù)封裝成了RunnableFuture接口(繼承了Runnable、Future接口),再調(diào)用execute方法,我們看源碼:
public Future<?> submit(Runnable task) { if (task == null) throw new NullPointerException(); RunnableFuture<Void> ftask = newTaskFor(task, null); //轉(zhuǎn)成 RunnableFuture,傳的result是null execute(ftask); return ftask; } public <T> Future<T> submit(Runnable task, T result) { if (task == null) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task, result); execute(ftask); return ftask; } public <T> Future<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task); execute(ftask); return ftask; }
2)newTaskFor方法內(nèi)部實(shí)現(xiàn):
newTaskFor方法是new了一個(gè)FutureTask返回,所以三個(gè)方法其實(shí)都是把task轉(zhuǎn)成FutureTask,如果task是Callable,就直接賦值,如果是Runnable 就轉(zhuǎn)為Callable再賦值。
當(dāng)submit參數(shù)是Callable 時(shí):
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { return new FutureTask<T>(callable); } public FutureTask(Callable<V> callable) { if (callable == null) throw new NullPointerException(); this.callable = callable; this.state = NEW; }
當(dāng)submit參數(shù)是Runnable時(shí):
// 按順序看,層層調(diào)用 protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { return new FutureTask<T>(runnable, value); } public FutureTask(Runnable runnable, V result) { this.callable = Executors.callable(runnable, result); //轉(zhuǎn) runnable 為 callable this.state = NEW; } // 以下為Executors中的方法 public static <T> Callable<T> callable(Runnable task, T result) { if (task == null) throw new NullPointerException(); return new RunnableAdapter<T>(task, result); } static final class RunnableAdapter<T> implements Callable<T> { //適配器 final Runnable task; final T result; RunnableAdapter(Runnable task, T result) { this.task = task; this.result = result; } public T call() { task.run(); return result; } }
看了源碼就揭開了神秘面紗了,就是因?yàn)镕uture需要返回結(jié)果,所以內(nèi)部task必須是Callable,如果task是Runnable 就偷天換日,在Runnable 外面包個(gè)Callable馬甲,返回的結(jié)果在構(gòu)造時(shí)就寫好。
參考:搞懂Runnable、Callable、Future、FutureTask 及應(yīng)用_趕路人兒的博客-CSDN博客
1.4)ScheduledExecutorService接口:
繼承ExecutorService,并且提供了按時(shí)間安排執(zhí)行任務(wù)的功能,它提供的方法主要有:
- schedule(task, initDelay): 安排所提交的Callable或Runnable任務(wù)在initDelay指定的時(shí)間后執(zhí)行;
- scheduleAtFixedRate():安排所提交的Runnable任務(wù)按指定的間隔重復(fù)執(zhí)行;
- scheduleWithFixedDelay():安排所提交的Runnable任務(wù)在每次執(zhí)行完后,等待delay所指定的時(shí)間后重復(fù)執(zhí)行;
注:該接口的實(shí)現(xiàn)類是ScheduledThreadPoolExecutor。
2、Callable接口:
jdk1.5以后創(chuàng)建線程可以通過一下方式:
- 繼承Thread類,實(shí)現(xiàn)void run()方法;
- 實(shí)現(xiàn)Runnable接口,實(shí)現(xiàn)void run()方法;
- 實(shí)現(xiàn)Callable接口,實(shí)現(xiàn)V call() Throws Exception方法
1)Callable和Runnale接口區(qū)別:
- Callable可以拋出異常,和Future、FutureTask配合可以用來獲取異步執(zhí)行的結(jié)果;
- Runnable沒有返回結(jié)果,異常只能內(nèi)部消化;
2)執(zhí)行Callable的線程的方法可以通過以下兩種方式:
- 借助FutureTask,使用Thread的start方法來執(zhí)行;
- 加入到線程池中,使用線程池的execute或submit執(zhí)行;
注:Callable無法直接使用Thread來執(zhí)行;
我們都知道,Callable帶有返回值的,如果我們不需要返回值,卻又想用Callable該如何做?
jdk中有個(gè)Void類型(大寫V),但必須也要return null。
threadpool.submit(new Callable<Void>() { @Override public Void call() { //... return null; } });
3)通過Executors工具類可以把Runnable接口轉(zhuǎn)換成Callable接口:
Executors中的callable方法可以將Runnable轉(zhuǎn)成Callable,如下:
public static <T> Callable<T> callable(Runnable task, T result) { if (task == null) throw new NullPointerException(); return new RunnableAdapter<T>(task, result); }
RunnableAdapter類在上面已經(jīng)看過源碼,原理就是將返回值result作為成員變量,通過參數(shù)傳遞進(jìn)去,進(jìn)而實(shí)現(xiàn)了Runnable可以返回值。
示例:
public static void test5() { Person p = new Person(0,"person"); RunnableTask runnableTask = new RunnableTask(p);//創(chuàng)建runnable Callable<Person> callable = Executors.callable(runnableTask,p);//轉(zhuǎn)換 Future<Person> future1 = threadPool.submit(callable);//在線程池上執(zhí)行Callable try { Person person = future1.get(); System.out.println(person); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } Runnable runnable = new Runnable() {//創(chuàng)建Runnable @Override public void run() { } }; Callable<Object> callable2 = Executors.callable(runnable);//轉(zhuǎn)換 Future<Object> future2 = threadPool.submit(callable2);//在線程池上執(zhí)行Callable try { Object o = future2.get(); System.out.println(o); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } }
3、Future接口:
3.1)Future是用來獲取異步計(jì)算結(jié)果的接口,常用方法:
- boolean cancel(boolean mayInterruptIfRunning):試圖取消對(duì)此任務(wù)的執(zhí)行。如果任務(wù)已完成、或已取消,或者由于某些其他原因而無法取消,則此嘗試將失敗。當(dāng)調(diào)用 cancel 時(shí),如果調(diào)用成功,而此任務(wù)尚未啟動(dòng),則此任務(wù)將永不運(yùn)行。如果任務(wù)已經(jīng)啟動(dòng),則 mayInterruptIfRunning 參數(shù)確定是否應(yīng)該以試圖停止任務(wù)的方式來中斷執(zhí)行此任務(wù)的線程。此方法返回后,對(duì) isDone() 的后續(xù)調(diào)用將始終返回 true。如果此方法返回 true,則對(duì) isCancelled() 的后續(xù)調(diào)用將始終返回 true。
- boolean isCancelled():如果在任務(wù)正常完成前將其取消,則返回 true。
- boolean isDone():如果任務(wù)已完成,則返回 true,可能由于正常終止、異常或取消而完成,在所有這些情況中,此方法都將返回 true。
- V get()throws InterruptedException,ExecutionException:獲取異步結(jié)果,此方法會(huì)一直阻塞等到計(jì)算完成;
- V get(long timeout,TimeUnit unit) throws InterruptedException,ExecutionException,TimeoutException:獲取異步結(jié)果,此方法會(huì)在指定時(shí)間內(nèi)一直阻塞等到計(jì)算完成,超時(shí)后會(huì)拋出超時(shí)異常。
通過方法分析我們也知道實(shí)際上Future提供了3種功能:
- 能夠中斷執(zhí)行中的任務(wù);
- 判斷任務(wù)是否執(zhí)行完成;
- 獲取任務(wù)執(zhí)行完成后額結(jié)果。
但是Future只是一個(gè)接口,我們無法直接創(chuàng)建對(duì)象,因此就需要其實(shí)現(xiàn)類FutureTask登場(chǎng)啦。
3.2)FutureTask類:
1)FutureTask類的實(shí)現(xiàn):
public class FutureTask<V> implements RunnableFuture<V> { //... } public interface RunnableFuture<V> extends Runnable, Future<V> { /** * Sets this Future to the result of its computation * unless it has been cancelled. */ void run(); }
FutureTask實(shí)現(xiàn)了Runnable、Future兩個(gè)接口。由于FutureTask實(shí)現(xiàn)了Runnable,因此它既可以通過Thread包裝來直接執(zhí)行,也可以提交給ExecuteService來執(zhí)行。并且還可以直接通過get()函數(shù)獲取執(zhí)行結(jié)果,該函數(shù)會(huì)阻塞,直到結(jié)果返回。因此FutureTask既是Future、Runnable,又是包裝了Callable( 如果是Runnable最終也會(huì)被轉(zhuǎn)換為Callable ), 它是這兩者的合體。
2)FutureTask的構(gòu)造函數(shù):
public FutureTask(Callable<V> callable) { } public FutureTask(Runnable runnable, V result) { }
3.3)示例:(FutureTask兩種構(gòu)造函數(shù)、以及在Thread和線程池上運(yùn)行)
1)FutureTask包裝過的Callable在Thread、線程池上執(zhí)行:
public static void test3() { int a = 1,b = 2; Callable<Integer> callable = new Callable<Integer>() { @Override public Integer call() throws Exception { return a + b; } }; //通過futureTask來執(zhí)行Callable FutureTask<Integer> futureTask = new FutureTask<>(callable); //1.使用Thread執(zhí)行線程 new Thread(futureTask).start(); try { Integer integer = futureTask.get(); System.out.println(integer); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } //2.使用線程池執(zhí)行線程 Executors.newFixedThreadPool(1).submit(futureTask); threadPool.shutdown(); try { Integer integer = futureTask.get(); System.out.println(integer); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } }
2)FutureTask包裝過的Runnable在Thread、線程池上執(zhí)行:
public static void test4() { Person p = new Person(0,"person"); RunnableTask runnableTask = new RunnableTask(p); //創(chuàng)建futureTask來執(zhí)行Runnable FutureTask<Person> futureTask = new FutureTask<>(runnableTask,p); //1.使用Thread執(zhí)行線程 new Thread(futureTask).start(); try { Person x = futureTask.get(); System.out.println(x); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } //2.使用線程池執(zhí)行線程 threadPool.submit(futureTask); threadPool.shutdown(); try { Person y = futureTask.get(); System.out.println(y); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } }
Person、RunnableTask類同上面的示例中。
到此這篇關(guān)于一文弄懂Java中ThreadPoolExecutor的文章就介紹到這了,更多相關(guān)Java ThreadPoolExecut內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java線程池?ThreadPoolExecutor?詳解
- Java多線程ThreadPoolExecutor詳解
- Java線程池ThreadPoolExecutor源碼深入分析
- java高并發(fā)ThreadPoolExecutor類解析線程池執(zhí)行流程
- java高并發(fā)ScheduledThreadPoolExecutor與Timer區(qū)別
- 徹底搞懂java并發(fā)ThreadPoolExecutor使用
- Java多線程編程基石ThreadPoolExecutor示例詳解
- 源碼分析Java中ThreadPoolExecutor的底層原理
- 一文搞懂Java的ThreadPoolExecutor原理
相關(guān)文章
Spring整合TimerTask實(shí)現(xiàn)定時(shí)任務(wù)調(diào)度
這篇文章主要介紹了Spring整合TimerTask實(shí)現(xiàn)定時(shí)任務(wù)調(diào)度的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12Java中反射reflect的基礎(chǔ)知識(shí)講解
這篇文章主要介紹了Java中反射reflect的基礎(chǔ)知識(shí)講解,Java中的反射,它算是Java當(dāng)中非常底層的一個(gè)技術(shù),平時(shí)我們我們用得不多,實(shí)際上它也的確非常復(fù)雜同時(shí)也難以理解,但是涉及到底層的東西Java都給我們封裝好了,我們直接拿來調(diào)用即可,需要的朋友可以參考下2023-10-10SpringBoot整合WebSocket實(shí)現(xiàn)后端向前端發(fā)送消息的實(shí)例代碼
WebSocket使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,允許服務(wù)端主動(dòng)向客戶端推送數(shù)據(jù),下面這篇文章主要給大家介紹了關(guān)于SpringBoot整合WebSocket實(shí)現(xiàn)后端向前端發(fā)送消息的相關(guān)資料,需要的朋友可以參考下2023-03-03Spring Boot實(shí)現(xiàn)圖片上傳/加水印一把梭操作實(shí)例代碼
這篇文章主要給大家介紹了關(guān)于Spring Boot實(shí)現(xiàn)圖片上傳/加水印一把梭操作的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-11-11Spring定時(shí)任務(wù)中@PostConstruct被多次執(zhí)行異常的分析與解決
這篇文章主要給大家介紹了關(guān)于Spring定時(shí)任務(wù)中@PostConstruct被多次執(zhí)行異常的分析與解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-10-10