Java線(xiàn)程池實(shí)現(xiàn)原理與技術(shù),看這一篇就夠了
01.***制線(xiàn)程的缺點(diǎn)
多線(xiàn)程的軟件設(shè)計(jì)方法確實(shí)可以***限度地發(fā)揮多核處理器的計(jì)算能力,提高生產(chǎn)系統(tǒng)的吞吐量和性能。但是,若不加控制和管理的隨意使用線(xiàn)程,對(duì)系統(tǒng)的性能反而會(huì)產(chǎn)生不利的影響。
一種最為簡(jiǎn)單的線(xiàn)程創(chuàng)建和回收的方法類(lèi)似如下:
- new Thread(new Runnable() {
- @Override
- public void run() {
- //do sth
- }
- }).start();
以上代碼創(chuàng)建了一條線(xiàn)程,并在run()方法結(jié)束后,自動(dòng)回收該線(xiàn)程。在簡(jiǎn)單的應(yīng)用系統(tǒng)中,這段代碼并沒(méi)有太多問(wèn)題。但是在真實(shí)的生產(chǎn)環(huán)境中,系統(tǒng)由于真實(shí)環(huán)境的需要,可能會(huì)開(kāi)啟很多線(xiàn)程來(lái)支撐其應(yīng)用。而當(dāng)線(xiàn)程數(shù)量過(guò)大時(shí),反而會(huì)耗盡CPU和內(nèi)存資源。
首先,雖然與進(jìn)程相比,線(xiàn)程是一種輕量級(jí)的工具,但其創(chuàng)建和關(guān)閉依然需要花費(fèi)時(shí)間,如果為每一個(gè)小的任務(wù)都創(chuàng)建一個(gè)線(xiàn)程,很有可能出現(xiàn)創(chuàng)建和銷(xiāo)毀線(xiàn)程所占用的時(shí)間大于該線(xiàn)程真實(shí)工作所消耗的時(shí)間,反而會(huì)得不償失。
其次,線(xiàn)程本身也是要占用內(nèi)存空間的,大量的線(xiàn)程會(huì)搶占寶貴的內(nèi)部資源。
因此,在實(shí)際生產(chǎn)環(huán)境中,線(xiàn)程的數(shù)量必須得到控制。盲目地大量創(chuàng)建線(xiàn)程對(duì)系統(tǒng)性能是有傷害的。
02.簡(jiǎn)單的線(xiàn)程池實(shí)現(xiàn)
下面給出一個(gè)最簡(jiǎn)單的線(xiàn)程池,該線(xiàn)程池不是一個(gè)完善的線(xiàn)程池,但已經(jīng)實(shí)現(xiàn)了一個(gè)基本線(xiàn)程池的核心功能,有助于快速理解線(xiàn)程池的實(shí)現(xiàn)。
1.線(xiàn)程池的實(shí)現(xiàn)
- public class ThreadPool {
- private static ThreadPool instance = null;
- //空閑的線(xiàn)程隊(duì)列
- private List<PThread> idleThreads;
- //已有的線(xiàn)程總數(shù)
- private int threadCounter;
- private boolean isShutDown = false;
- private ThreadPool() {
- this.idleThreads = new Vector<>(5);
- threadCounter = 0;
- }
- public int getCreatedThreadCounter() {
- return threadCounter;
- }
- //取得線(xiàn)程池的實(shí)例
- public synchronized static ThreadPool getInstance() {
- if (instance == null) {
- instance = new ThreadPool();
- }
- return instance;
- }
- //將線(xiàn)程池放入池中
- protected synchronized void repool(PThread repoolingThread) {
- if (!isShutDown) {
- idleThreads.add(repoolingThread);
- } else {
- repoolingThread.shutDown();
- }
- }
- //停止池中所有線(xiàn)程
- public synchronized void shutDown() {
- isShutDown = true;
- for (int threadIndex = 0; threadIndex < idleThreads.size(); threadIndex++) {
- PThread pThread = idleThreads.get(threadIndex);
- pThread.shutDown();
- }
- }
- //執(zhí)行任務(wù)
- public synchronized void start(Runnable target) {
- PThread thread = null;
- //如果有空閑線(xiàn)程,則直接使用
- if (idleThreads.size() > 0) {
- int lastIndex = idleThreads.size() - 1;
- thread = idleThreads.get(lastIndex);
- idleThreads.remove(thread);
- //立即執(zhí)行這個(gè)任務(wù)
- thread.setTarget(target);
- }//沒(méi)有空閑線(xiàn)程,則創(chuàng)建線(xiàn)程
- else {
- threadCounter++;
- //創(chuàng)建新線(xiàn)程
- thread = new PThread(target, "PThread #" + threadCounter, this);
- //啟動(dòng)這個(gè)線(xiàn)程
- thread.start();
- }
- }
- }
2.要實(shí)現(xiàn)上面的線(xiàn)程池,就需要一個(gè)永不退出的線(xiàn)程與之配合。PThread就是一個(gè)這樣的線(xiàn)程。它的主體部分是一個(gè)***循環(huán),該線(xiàn)程在手動(dòng)關(guān)閉前永不結(jié)束,并一直等待新的任務(wù)到達(dá)。
- public class PThread extends Thread {
- //線(xiàn)程池
- private ThreadPool pool;
- //任務(wù)
- private Runnable target;
- private boolean isShutDown = false;
- private boolean isIdle = false; //是否閑置
- //構(gòu)造函數(shù)
- public PThread(Runnable target,String name, ThreadPool pool){
- super(name);
- this.pool = pool;
- this.target = target;
- }
- public Runnable getTarget(){
- return target;
- }
- public boolean isIdle() {
- return isIdle;
- }
- @Override
- public void run() {
- //只要沒(méi)有關(guān)閉,則一直不結(jié)束該線(xiàn)程
- while (!isShutDown){
- isIdle = false;
- if (target != null){
- //運(yùn)行任務(wù)
- target.run();
- }
- try {
- //任務(wù)結(jié)束了,到閑置狀態(tài)
- isIdle = true;
- pool.repool(this);
- synchronized (this){
- //線(xiàn)程空閑,等待新的任務(wù)到來(lái)
- wait();
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- isIdle = false;
- }
- }
- public synchronized void setTarget(Runnable newTarget){
- target = newTarget;
- //設(shè)置了任務(wù)之后,通知run方法,開(kāi)始執(zhí)行這個(gè)任務(wù)
- notifyAll();
- }
- //關(guān)閉線(xiàn)程
- public synchronized void shutDown(){
- isShutDown = true;
- notifyAll();
- }
- }
3.測(cè)試Main方法
- public static void main(String[] args) throws InterruptedException {
- for (int i = 0; i < 1000; i++) {
- ThreadPool.getInstance().start(new Runnable() {
- @Override
- public void run() {
- try {
- //休眠100ms
- Thread.sleep(100);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
- }
- }
03ThreadPoolExecutor
為了能夠更好地控制多線(xiàn)程,JDK提供了一套Executor框架,幫助開(kāi)發(fā)人員有效地進(jìn)行線(xiàn)程控制。Executor框架無(wú)論是newFixedThreadPool()方法、newSingleThreadExecutor()方法還是newCachedThreadPool()方法,其內(nèi)部實(shí)現(xiàn)均使用了 ThreadPoolExecutor:
- public static ExecutorService newCachedThreadPool() {
- return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
- 60L, TimeUnit.SECONDS,
- new SynchronousQueue<Runnable>());
- }
- public static ExecutorService newFixedThreadPool(int nThreads) {
- return new ThreadPoolExecutor(nThreads, nThreads,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue<Runnable>());
- }
- public static ExecutorService newSingleThreadExecutor() {
- return new FinalizableDelegatedExecutorService
- (new ThreadPoolExecutor(1, 1,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue<Runnable>()));
- }
由以上線(xiàn)程池的實(shí)現(xiàn)代碼可以知道,它們只是對(duì) ThreadPoolExecutor 類(lèi)的封裝。為何 ThreadPoolExecutor 類(lèi)有如此強(qiáng)大的功能?來(lái)看一下 ThreadPoolExecutor 最重要的構(gòu)造方法。
3.1 構(gòu)造方法
ThreadPoolExecutor最重要的構(gòu)造方法如下:
- public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
方法參數(shù)如下:
ThreadPoolExecutor的使用示例,通過(guò)execute()方法提交任務(wù)。
- public static void main(String[] args) {
- ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 5, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
- for (int i = 0; i < 10; i++) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- System.out.println(Thread.currentThread().getName());
- }
- });
- }
- executor.shutdown();
- }
或者通過(guò)submit()方法提交任務(wù)
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 5, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
- List<Future> futureList = new Vector<>();
- //在其它線(xiàn)程中執(zhí)行100次下列方法
- for (int i = 0; i < 100; i++) {
- futureList.add(executor.submit(new Callable<String>() {
- @Override
- public String call() throws Exception {
- return Thread.currentThread().getName();
- }
- }));
- }
- for (int i = 0;i<futureList.size();i++){
- Object o = futureList.get(i).get();
- System.out.println(o.toString());
- }
- executor.shutdown();
- }
運(yùn)行結(jié)果:
- ...
- pool-1-thread-4
- pool-1-thread-3
- pool-1-thread-2
下面主要講解ThreadPoolExecutor的構(gòu)造方法中workQueue和RejectedExecutionHandler參數(shù),其它參數(shù)都很簡(jiǎn)單。
3.2 workQueue任務(wù)隊(duì)列
用于保存等待執(zhí)行的任務(wù)的阻塞隊(duì)列??梢赃x擇以下幾個(gè)阻塞隊(duì)列。
- ArrayBlockingQueue: 是一個(gè)基于數(shù)組結(jié)構(gòu)的有界阻塞隊(duì)列,按FIFO原則進(jìn)行排序
- LinkedBlockingQueue: 一個(gè)基于鏈表結(jié)構(gòu)的阻塞隊(duì)列,吞吐量高于A(yíng)rrayBlockingQueue。靜態(tài)工廠(chǎng)方法Excutors.newFixedThreadPool()使用了這個(gè)隊(duì)列
- SynchronousQueue: 一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列。每個(gè)插入操作必須等到另一個(gè)線(xiàn)程調(diào)用移除操作,否則插入操作一直處于阻塞狀態(tài),吞吐量高于LinkedBlockingQueue,靜態(tài)工廠(chǎng)方法Excutors.newCachedThreadPool()使用了這個(gè)隊(duì)列
- PriorityBlockingQueue: 一個(gè)具有優(yōu)先級(jí)的***阻塞隊(duì)列。
3.3 RejectedExecutionHandler飽和策略
當(dāng)隊(duì)列和線(xiàn)程池都滿(mǎn)了,說(shuō)明線(xiàn)程池處于飽和狀態(tài),那么必須采取一種策略還處理新提交的任務(wù)。它可以有如下四個(gè)選項(xiàng):
- AbortPolicy : 直接拋出異常,默認(rèn)情況下采用這種策略
- CallerRunsPolicy : 只用調(diào)用者所在線(xiàn)程來(lái)運(yùn)行任務(wù)
- DiscardOldestPolicy : 丟棄隊(duì)列里最近的一個(gè)任務(wù),并執(zhí)行當(dāng)前任務(wù)
- DiscardPolicy : 不處理,丟棄掉
更多的時(shí)候,我們應(yīng)該通過(guò)實(shí)現(xiàn)RejectedExecutionHandler 接口來(lái)自定義策略,比如記錄日志或持久化存儲(chǔ)等。
3.4 submit()與execute()
可以使用execute和submit兩個(gè)方法向線(xiàn)程池提交任務(wù)。
execute方法用于提交不需要返回值的任務(wù),利用這種方式提交的任務(wù)無(wú)法得知是否正常執(zhí)行
submit方法用于提交一個(gè)任務(wù)并帶有返回值,這個(gè)方法將返回一個(gè)Future類(lèi)型對(duì)象。可以通過(guò)這個(gè)返回對(duì)象判斷任務(wù)是否執(zhí)行成功,并且可以通過(guò)future.get()方法來(lái)獲取返回值,get()方法會(huì)阻塞當(dāng)前線(xiàn)程直到任務(wù)完成。
3.5 shutdown()與shutdownNow()
可以通過(guò)調(diào)用 shutdown() 或 shutdownNow() 方法來(lái)關(guān)閉線(xiàn)程池。它們的原理是遍歷線(xiàn)程池中的工作線(xiàn)程,然后逐個(gè)調(diào)用線(xiàn)程的 interrupt 方法來(lái)中斷線(xiàn)程,所以無(wú)法響應(yīng)中斷的任務(wù)可能永遠(yuǎn)無(wú)法停止。
這倆方法的區(qū)別是,shutdownNow() 首先將線(xiàn)程池的狀態(tài)設(shè)置成STOP,然后嘗試停止所有的正在執(zhí)行或暫停任務(wù)的線(xiàn)程,并返回等待執(zhí)行任務(wù)的列表,而 shutdown() 只是將線(xiàn)程池的狀態(tài)設(shè)置成 SHUTDOWN 狀態(tài),然后中斷所有沒(méi)有正在執(zhí)行任務(wù)的線(xiàn)程。
只要調(diào)用了這兩個(gè)關(guān)閉方法的任意一個(gè),isShutdown 方法就會(huì)返回 true。當(dāng)所有的任務(wù)都已關(guān)閉了,才表示線(xiàn)程池關(guān)閉成功,這時(shí)調(diào)用 isTerminaced 方法會(huì)返回 true。
通常調(diào)用 shutdown() 方法來(lái)關(guān)閉線(xiàn)程池,如果任務(wù)不一定要執(zhí)行完,則可以調(diào)用 shutdownNow() 方法。
3.6 合理配置線(xiàn)程池
要想合理地配置線(xiàn)程池,首先要分析任務(wù)特性
- 任務(wù)的性質(zhì):CPU密集型任務(wù)、IO密集型任務(wù)和混合型任務(wù)。
- 任務(wù)的優(yōu)先級(jí):高、中和低。
- 任務(wù)的執(zhí)行時(shí)間:長(zhǎng)、中和短。
- 任務(wù)的依賴(lài)性:是否依賴(lài)其他系統(tǒng)資源,如數(shù)據(jù)庫(kù)連接。
性質(zhì)不同的任務(wù)可以用不同規(guī)模的線(xiàn)程池分開(kāi)處理。
CPU密集型任務(wù)應(yīng)該配置盡可能少的線(xiàn)程,如配置N+1個(gè)線(xiàn)程,N位CPU的個(gè)數(shù)。
而IO密集型任務(wù)線(xiàn)程并不是一直在執(zhí)行任務(wù),則應(yīng)配置盡可能多的線(xiàn)程,如2*N。
混合型任務(wù),如果可以拆分,將其拆分成一個(gè)CPU密集型任務(wù)和一個(gè)IO密集型任務(wù),只要這兩個(gè)任務(wù)執(zhí)行的時(shí)間相差不是太大,那么分解后執(zhí)行的吞吐量將高于串行執(zhí)行的吞吐量。如果這兩個(gè)任務(wù)執(zhí)行的時(shí)間相差很大,則沒(méi)有必要進(jìn)行分解。可以通過(guò)Runtime.getRuntime().availableProcessors()方法獲得當(dāng)前設(shè)備的CPU個(gè)數(shù)。
優(yōu)先級(jí)不同的任務(wù)可以使用優(yōu)先級(jí)隊(duì)列PriorityBlockingQueue來(lái)處理。它可以讓優(yōu)先級(jí)高的任務(wù)先執(zhí)行。
3.7 線(xiàn)程池的監(jiān)控
由于大量的使用線(xiàn)程池,所以很有必要對(duì)其進(jìn)行監(jiān)控。可以通過(guò)繼承線(xiàn)程池來(lái)自定義線(xiàn)程池,重寫(xiě)線(xiàn)程池的beforeExecute、afterExecute 和 terminated 方法,也可以在任務(wù)執(zhí)行前,執(zhí)行后和線(xiàn)程池關(guān)閉前執(zhí)行一些代碼來(lái)進(jìn)行監(jiān)控。在監(jiān)控線(xiàn)程池的時(shí)候可以使用一下屬性:
(1) taskCount:線(xiàn)程池需要執(zhí)行的任務(wù)數(shù)量
(2) completedTaskCount:線(xiàn)程池在運(yùn)行過(guò)程中已完成的任務(wù)數(shù)量,小于或等于taskCount
(3) largestPoolSize: 線(xiàn)程池里曾經(jīng)創(chuàng)建過(guò)***的線(xiàn)程數(shù)量。通過(guò)這個(gè)數(shù)據(jù)可以知道線(xiàn)程池是否曾經(jīng)滿(mǎn)過(guò)。如該數(shù)值等于線(xiàn)程池***大小,則表示線(xiàn)程池曾經(jīng)滿(mǎn)過(guò)。
(4) getPoolSize:線(xiàn)程池的線(xiàn)程數(shù)量。如果線(xiàn)程池不銷(xiāo)毀的話(huà),線(xiàn)程池里的線(xiàn)程不會(huì)自動(dòng)銷(xiāo)毀,所以這個(gè)大小只增不減。
(5) getActiveCount:獲取活動(dòng)的線(xiàn)程數(shù)
04Executor多線(xiàn)程框架
ThreadPoolExecutor 表示一個(gè)線(xiàn)程池,Executors 類(lèi)則扮演著線(xiàn)程池工廠(chǎng)的角色,通過(guò) Executors 可以取得一個(gè)特定功能的線(xiàn)程池。
使用 Executors 框架實(shí)現(xiàn)上節(jié)中的例子,其代碼如下:
- public static void main(String[] args) {
- //新建一個(gè)線(xiàn)程池
- ExecutorService executor = Executors.newCachedThreadPool();
- //在其它線(xiàn)程中執(zhí)行100次下列方法
- for (int i = 0; i < 100; i++) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- System.out.println(Thread.currentThread().getName());
- }
- });
- }
- //執(zhí)行完關(guān)閉
- executor.shutdown();
- }
4.1 Executors框架的結(jié)構(gòu)
1.任務(wù)
包括被執(zhí)行任務(wù)需要實(shí)現(xiàn)的接口:Runnable 接口或 Callable 接口。
2.任務(wù)的執(zhí)行
包括任務(wù)執(zhí)行機(jī)制的核心接口 Executor,以及繼承自 Executor 的ExecutorService 接口。Executor框架有兩個(gè)關(guān)鍵類(lèi)實(shí)現(xiàn)了 ExecutorService 接口(ThreadPoolExecutor 和 ScheduledThreadPoolExecutor)。
3.異步計(jì)算的結(jié)果
包括接口 Future 和實(shí)現(xiàn)Future接口的FutureTask類(lèi)。
4.2 Executors工廠(chǎng)方法
Executors工廠(chǎng)類(lèi)的主要方法:
- public static ExecutorService newFixedThreadPool(int nThreads)
該方法返回一個(gè)固定線(xiàn)程數(shù)量的線(xiàn)程池,該線(xiàn)程池中的線(xiàn)程數(shù)量始終不變。當(dāng)有一個(gè)新的任務(wù)提交時(shí),線(xiàn)程池中若有空閑線(xiàn)程,則立即執(zhí)行。若沒(méi)有,則新的任務(wù)會(huì)被暫存在一個(gè)任務(wù)隊(duì)列中,待有線(xiàn)程空閑時(shí),便處理在任務(wù)隊(duì)列中的任務(wù)。
- public static ExecutorService newSingleThreadExecutor()
該方法返回一個(gè)只有一個(gè)線(xiàn)程的線(xiàn)程池。若多余一個(gè)任務(wù)被提交到線(xiàn)程池,任務(wù)會(huì)被保存在一個(gè)任務(wù)隊(duì)列中,待線(xiàn)程空閑,按先入先出的順序執(zhí)行隊(duì)列中的任務(wù)。
- public static ExecutorService newCachedThreadPool()
該方法返回一個(gè)可根據(jù)實(shí)際情況調(diào)整線(xiàn)程數(shù)量的線(xiàn)程池。線(xiàn)程池的線(xiàn)程數(shù)量不確定,但若有空閑線(xiàn)程可以復(fù)用,則會(huì)優(yōu)先使用可復(fù)用的線(xiàn)程。但所有線(xiàn)程均在工作,又有新的任務(wù)提交,則會(huì)創(chuàng)建新的線(xiàn)程處理任務(wù)。所有線(xiàn)程在當(dāng)前任務(wù)執(zhí)行完畢后,將返回線(xiàn)程池進(jìn)行復(fù)用。
- public static ScheduledExecutorService newSingleThreadScheduledExecutor()
該方法返回一個(gè)ScheduledExecutorService對(duì)象,線(xiàn)程池大小為1。ScheduledExecutorService接口在ExecutorService接口之上擴(kuò)展了在給定時(shí)間執(zhí)行某任務(wù)的功能,如在某個(gè)固定的延時(shí)之后執(zhí)行,或者周期性執(zhí)行某個(gè)任務(wù)。
- public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
該方法也返回一個(gè) ScheduledExecutorService 對(duì)象,但該線(xiàn)程池可以指定線(xiàn)程數(shù)量。
4.3 ThreadPoolExecutor與ScheduledThreadPoolExecutor
在前面提到了Executors 類(lèi)扮演著線(xiàn)程池工廠(chǎng)的角色,通過(guò) Executors 可以取得一個(gè)特定功能的線(xiàn)程池。Executors 工廠(chǎng)類(lèi)的主要方法可以創(chuàng)建 ThreadPoolExecutor 和 ScheduledThreadPoolExecutor 線(xiàn)程池。
關(guān)于ThreadPoolExecutor ,前面第3節(jié)已經(jīng)詳細(xì)敘述。ScheduledThreadPoolExecutor 也是ExecutorService接口的實(shí)現(xiàn)類(lèi),可以在給定的延遲后運(yùn)行命令,或者定期執(zhí)行命令。ScheduledThreadPoolExecutor 比 Timer 更靈活,功能更強(qiáng)大。
4.4 Future與FutureTask
上面的示例中使用 execute() 方法提交任務(wù),用于提交不需要返回值的任務(wù)。如果我們需要獲取執(zhí)行任務(wù)之后的返回值,可以使用submit()方法。
示例代碼:
- public static void main(String[] args) throws InterruptedException, ExecutionException {
- //新建一個(gè)線(xiàn)程池
- ExecutorService executor = Executors.newCachedThreadPool();
- List<Future> futureList = new Vector<>();
- //在其它線(xiàn)程中執(zhí)行100次下列方法
- for (int i = 0; i < 100; i++) {
- futureList.add(executor.submit(new Callable<String>() {
- @Override
- public String call() throws Exception {
- return Thread.currentThread().getName()+" "+System.currentTimeMillis()+" ";
- }
- }));
- }
- for (int i = 0;i<futureList.size();i++){
- Object o = futureList.get(i).get();
- System.out.println(o.toString()+i);
- }
- executor.shutdown();
- }
運(yùn)行結(jié)果:
- ...
- pool-1-thread-11 1537872778612 96
- pool-1-thread-11 1537872778613 97
- pool-1-thread-10 1537872778613 98
- pool-1-thread-10 1537872778613 99
到這里,就不得不提Future接口與FutureTask實(shí)現(xiàn)類(lèi),它們代表異步計(jì)算的結(jié)果。
- Future<T> submit(Callable<T> task)
- Future<?> submit(Runnable task);
- Future<T> submit(Runnable task, T result);
當(dāng)我們submit()提交后,會(huì)返回一個(gè)Future對(duì)象,到JDK1.8,返回的實(shí)際是FutureTask實(shí)現(xiàn)類(lèi)。submit() 方法支持 Runnable 或 Callable 類(lèi)型的參數(shù)。Runnable 接口 和Callable 接口的區(qū)別就是 Runnable 不會(huì)返回結(jié)果,Callable 會(huì)返回結(jié)果。
主線(xiàn)程可以執(zhí)行 futureTask.get() 方法來(lái)阻塞當(dāng)前線(xiàn)程直到任務(wù)執(zhí)行完成,任務(wù)完成后返回任務(wù)執(zhí)行的結(jié)果。
futureTask.get(long timeout, TimeUnit unit) 方法則會(huì)阻塞當(dāng)前線(xiàn)程一段時(shí)間立即返回,這時(shí)候有可能任務(wù)沒(méi)有執(zhí)行完。
主線(xiàn)程也可以執(zhí)行 futureTask.cancel(boolean mayInterruptIfRunning) 來(lái)取消此任務(wù)的執(zhí)行。
futureTask.isCancelled方法表示任務(wù)是否被取消成功,如果在任務(wù)正常完成前被取消成功,則返回 true。
futureTask.isDone方法表示任務(wù)是否已經(jīng)完成,若任務(wù)完成,則返回true。