1. 程式人生 > >java執行緒池之ThreadPoolExecutor(三):提交任務並得到任務執行結果

java執行緒池之ThreadPoolExecutor(三):提交任務並得到任務執行結果

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提供的方法:
<T> Future<T> submit(Callable<T> task);  
<T> Future<T> submit(Runnable task, T result);  
Future<?> submit(Runnable task);  
第一個方法:submit提交一個實現Callable介面的任務,並且返回封裝了非同步計算結果的Future。
第二個方法: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===========
請大家注意文字加粗的地方。