Java併發之Executor + Callable + Future

chi633發表於2017-12-21
  • 引入 Callable + Future
  • Callable + Future例項

引入 Callable + Future

Executor框架的優勢之一就是,可以執行併發任務並且返回結果。 我們知道Runnable物件是沒有返回值的,所以自然利用Runnable物件就無法返回結果,於是就定義了一個新的介面,可以理解為是“帶有返回值的Runnable物件”。 這個介面就是 Callable介面:這個介面宣告瞭一個call方法,類似於Runnable介面的run方法,是任務具體的邏輯,不同就在於可以有返回值,而且這個介面是一個泛型介面,這就意味著必須宣告call方法的返回型別。

image.png

我們任務交給執行緒執行之後,什麼時候執行結束,將結果返回這個時間往往是無法具體確定的,所以為了接受這個來自未來某個時刻執行完之後的返回結果,又新增了一個Future介面: Future介面:這個介面宣告瞭一些方法獲取由callable物件產生的結果,並管理他們的狀態。

image.png

Callable + Future例項

接下來,我們編寫一個例項來接受任務的返回結果

實現一個Callable物件,由於返回值是Integer,所以定義為Callable

package CreateExecutorCallableFuture;

import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

public class FactorialCaculator implements Callable<Integer> {
	
	private Integer number;
	
	

	public FactorialCaculator(Integer number) {
		super();
		this.number = number;
	}



	@Override
	public Integer call() throws Exception {
		int result = 1;
		if((number == 0) || (number == 1))
			return 1;
		else {
			for(int i=2;i<=number;i++) {
				result *= i;
				TimeUnit.MILLISECONDS.sleep(20);
			}
		}
		
		System.out.printf("%s : %d\n",Thread.currentThread().getName(),result);
		
		return result;
	}
	
}
複製程式碼

Main類建立一個執行緒池來執行這些任務,並在任務執行完之後輸出結果

package CreateExecutorCallableFuture;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Main {

	public static void main(String[] args) throws InterruptedException {
		ThreadPoolExecutor executor = (ThreadPoolExecutor)Executors.newFixedThreadPool(2);
		List<Future<Integer>> resList = new ArrayList<>();
		
		Random random = new Random();
		
		for(int i=0;i<10;i++) {
			Integer number = random.nextInt(10);
			FactorialCaculator caculator = new FactorialCaculator(number);
			
			Future<Integer> res = executor.submit(caculator);
			resList.add(res);
		}
		
		do {
			System.out.println("Main : Number of CompleteTasks : " + executor.getCompletedTaskCount());
			for(int i=0;i<resList.size();i++) {
				Future<Integer> res = resList.get(i);
				System.out.printf("Main : task %d : %s\n", i, res.isDone());
			}
			
			TimeUnit.MILLISECONDS.sleep(50);
			
		}while(executor.getCompletedTaskCount() < resList.size());
		
		for(int i=0;i<resList.size();i++) {
			Future<Integer> res = resList.get(i);
			Integer number = null;
			try {
				number = res.get();
			} catch (ExecutionException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.printf("Main : Task %d : %s\n",i,number);
		}
	}

}
複製程式碼

執行結果

Main : Number of CompleteTasks : 0
Main : task 0 : false
Main : task 1 : false
Main : task 2 : false
Main : task 3 : false
Main : task 4 : false
Main : task 5 : false
Main : task 6 : false
Main : task 7 : false
Main : task 8 : false
Main : task 9 : false
pool-1-thread-1 : 24
pool-1-thread-2 : 120
Main : Number of CompleteTasks : 2
Main : task 0 : true
Main : task 1 : true
Main : task 2 : false
Main : task 3 : false
Main : task 4 : false
Main : task 5 : false
Main : task 6 : false
Main : task 7 : false
Main : task 8 : false
Main : task 9 : false
pool-1-thread-2 : 2
pool-1-thread-2 : 2
Main : Number of CompleteTasks : 4
Main : task 0 : true
Main : task 1 : true
Main : task 2 : false
Main : task 3 : true
Main : task 4 : true
Main : task 5 : false
Main : task 6 : false
Main : task 7 : false
Main : task 8 : false
Main : task 9 : false
pool-1-thread-2 : 6
Main : Number of CompleteTasks : 6
Main : task 0 : true
Main : task 1 : true
Main : task 2 : false
Main : task 3 : true
Main : task 4 : true
Main : task 5 : true
Main : task 6 : true
Main : task 7 : false
Main : task 8 : false
Main : task 9 : false
pool-1-thread-1 : 40320
Main : Number of CompleteTasks : 7
Main : task 0 : true
Main : task 1 : true
Main : task 2 : true
Main : task 3 : true
Main : task 4 : true
Main : task 5 : true
Main : task 6 : true
Main : task 7 : false
Main : task 8 : false
Main : task 9 : false
pool-1-thread-2 : 720
Main : Number of CompleteTasks : 9
Main : task 0 : true
Main : task 1 : true
Main : task 2 : true
Main : task 3 : true
Main : task 4 : true
Main : task 5 : true
Main : task 6 : true
Main : task 7 : true
Main : task 8 : false
Main : task 9 : true
Main : Number of CompleteTasks : 9
Main : task 0 : true
Main : task 1 : true
Main : task 2 : true
Main : task 3 : true
Main : task 4 : true
Main : task 5 : true
Main : task 6 : true
Main : task 7 : true
Main : task 8 : false
Main : task 9 : true
pool-1-thread-1 : 362880
Main : Task 0 : 24
Main : Task 1 : 120
Main : Task 2 : 40320
Main : Task 3 : 2
Main : Task 4 : 2
Main : Task 5 : 6
Main : Task 6 : 1
Main : Task 7 : 720
Main : Task 8 : 362880
Main : Task 9 : 1
複製程式碼

Future物件主要有一下兩個目的:

  • 控制任務的狀態:可以取消和檢查任務是否完成。可以使用isDone檢查任務是否完成,檢查isCancel檢查任務是否暫停,也可以直接呼叫cancle方法暫停任務。

  • 通過call方法獲取返回結果,為了達到這個目的,可以使用get方法,這個方法會一直等到callable物件的call方法返回結果。如果此時任務尚未完成,get方法就會一直阻塞到執行緒完成。

** Future物件是用來管理Callavle任務的!**

相關文章