java執行緒池之ThreadPoolExecutor(三):提交任務並得到任務執行結果
阿新 • • 發佈:2019-02-01
1.Callable<V>介面
ThreadPoolExecutor不僅可以執行Runnable的實現類,還可以執行Callable介面的實現類。Callable的介面和Runnable介面的區別是:Callable有一個call方法能夠得到任務執行結果,而Runnable的run方法無法得到返回結果。Callable的介面的定義如下:
public interface Callable<V> {
V call() throws Exception;
}
該介面聲明瞭一個名稱為call()的方法,同時這個方法可以有返回值V,也可以丟擲異常。嗯,對該介面我們先了解這麼多就行,下面我們來說明如何使用,前篇文章我們說過,無論是Runnable介面的實現類還是Callable介面的實現類,都可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor執行,ThreadPoolExecutor或ScheduledThreadPoolExecutor都實現了ExcutorService介面,而因此Callable需要和Executor框架中的ExcutorService結合使用,我們先看看ExecutorService提供的方法:第一個方法:submit提交一個實現Callable介面的任務,並且返回封裝了非同步計算結果的Future。<T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task);
第二個方法:submit提交一個實現Runnable介面的任務,並且指定了在呼叫Future的get方法時返回的result物件。
第三個方法:submit提交一個實現Runnable介面的任務,並且返回封裝了非同步計算結果的Future。
因此我們只要建立好我們的執行緒物件(實現Callable介面或者Runnable介面),然後通過上面3個方法提交給執行緒池去執行即可。還有點要注意的是,除了我們自己實現Callable物件外,我們還可以使用工廠類Executors來把一個Runnable物件包裝成Callable物件。Executors工廠類提供的方法如下:
public static Callable<Object> callable(Runnable task) public static <T> Callable<T> callable(Runnable task, T result)
2.Future<V>介面
Future<V>介面是用來獲取非同步計算結果的,說白了就是對具體的Runnable或者Callable物件任務執行的結果進行獲取(get()),取消(cancel()),判斷是否完成等操作。我們看看Future介面的原始碼:
方法說明:public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled(); boolean isDone(); V get() throws InterruptedException, ExecutionException; V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
V get() :獲取非同步執行的結果,如果沒有結果可用,此方法會阻塞直到非同步計算完成。
V get(Long timeout , TimeUnit unit) :獲取非同步執行結果,如果沒有結果可用,此方法會阻塞,但是會有時間限制,如果阻塞時間超過設定的timeout時間,該方法將丟擲異常。
boolean isDone() :如果任務執行結束,無論是正常結束或是中途取消還是發生異常,都返回true。
boolean isCanceller() :如果任務完成前被取消,則返回true。
boolean cancel(boolean mayInterruptRunning) :如果任務還沒開始,執行cancel(...)方法將返回false;如果任務已經啟動,執行cancel(true)方法將以中斷執行此任務執行緒的方式來試圖停止任務,如果停止成功,返回true;當任務已經啟動,執行cancel(false)方法將不會對正在執行的任務執行緒產生影響(讓執行緒正常執行到完成),此時返回false;當任務已經完成,執行cancel(...)方法將返回false。mayInterruptRunning引數表示是否中斷執行中的執行緒。
通過方法分析我們也知道實際上Future提供了3種功能:(1)能夠中斷執行中的任務(2)判斷任務是否執行完成(3)獲取任務執行完成後額結果。
接下來,我們用一個具體的例子說明他們的用法:
/*
* 主執行緒類
*/
public class ThreadPoolTest2 {
//向執行緒池提交一個單獨的任務並得到任務執行的結果
public static void subTask(ThreadPoolExecutor executor){
Future<Integer> fut=executor.submit(new Callable<Integer>() {
public Integer call() throws Exception {
System.out.println("計算任務正在執行。。。");
int summ=0;
for(int i=1;i<=100;i++){
Thread.currentThread().sleep(100);
summ=summ+i;
}
System.out.println("計算任務結束");
return summ;
}
});
try {
//當然這裡我們還可以中途終止任務的執行,但也有可能終止不了。
//Thread.currentThread().sleep(15000);
//fut.cancel(true);//15秒後取消任務的執行
Integer result=fut.get();
System.out.println("單獨提交的任務執行結果:"+result);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// 建立執行緒池物件
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
// 該執行緒用於對執行緒池的檢測
new Thread(new CheckTask(executor)).start();
try {
//執行15個任務
for (int i = 1; i <= 15; i++) {
MyTask myTask = new MyTask("task==" + i);
executor.execute(myTask);
}
} catch (Exception e) {
e.printStackTrace();
}
//向執行緒池提交一個單獨的任務並得到任務執行的結果
subTask(executor);
executor.shutdown();
}
}
其它的類請參照【java執行緒池之ThreadPoolExecutor(一)】
如果有人看不懂內部類的話,我們也可以改成這個樣子:
/*
* 自定義Callable任務
*/
class MyCallable implements Callable<Integer>{
public Integer call() throws Exception {
System.out.println("計算任務正在執行。。。");
int summ=0;
for(int i=1;i<=100;i++){
Thread.currentThread().sleep(100);
summ=summ+i;
}
System.out.println("計算任務結束");
Integer result=new Integer(summ);
return result;
}
}
=============================
/*
* 主執行緒類
*/
public class ThreadPoolTest2 {
//向執行緒池提交一個單獨的任務並得到任務執行的結果
public static void subTask(ThreadPoolExecutor executor){
Future<Integer> fut=executor.submit(new MyCallable());
try {
//當然這裡我們還可以中途終止任務的執行,但也有可能終止不了。
//Thread.currentThread().sleep(15000);
//fut.cancel(true);//15秒後取消任務的執行
Integer result=fut.get();
System.out.println("單獨提交的任務執行結果:"+result);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// 建立執行緒池物件
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
// 該執行緒用於對執行緒池的檢測
new Thread(new CheckTask(executor)).start();
try {
//執行15個任務
for (int i = 1; i <= 15; i++) {
MyTask myTask = new MyTask("task==" + i);
executor.execute(myTask);
}
} catch (Exception e) {
e.printStackTrace();
}
//向執行緒池提交一個單獨的任務並得到任務執行的結果
subTask(executor);
executor.shutdown();
}
}
==================執行結果如下所示:==============
正在執行task==2
正在執行task==4
正在執行task==1
正在執行task==3
正在執行task==5
=========第1次檢測start===========
執行緒池中核心執行緒數:5
執行緒池中活躍執行緒數目:5
執行緒池中允許的最大執行緒數目:10
佇列中等待執行的任務數目:11
已經執行完成的任務數目:0
=========第1次檢測end===========
=========第2次檢測start===========
執行緒池中核心執行緒數:5
執行緒池中活躍執行緒數目:5
執行緒池中允許的最大執行緒數目:10
佇列中等待執行的任務數目:11
已經執行完成的任務數目:0
=========第2次檢測end===========
......
執行緒:task==11執行完畢
正在執行task==14
執行緒:task==8執行完畢
正在執行task==15
執行緒:task==10執行完畢
計算任務正在執行。。。
=========第14次檢測start===========
執行緒池中核心執行緒數:5
執行緒池中活躍執行緒數目:5
執行緒池中允許的最大執行緒數目:10
佇列中等待執行的任務數目:0
已經執行完成的任務數目:11
=========第14次檢測end===========
........
計算任務結束單獨提交的任務執行結果:5050
=========第24次檢測start===========
執行緒池中核心執行緒數:5
執行緒池中活躍執行緒數目:0
執行緒池中允許的最大執行緒數目:10
佇列中等待執行的任務數目:0
已經執行完成的任務數目:16
=========第24次檢測end===========
請大家注意文字加粗的地方。