標籤:his 計時 void numbers time 時間 incr return color
來自:https://www.cnblogs.com/shipengzhi/articles/2067154.html : java並發編程-Executor架構+Future
import java.util.concurrent.*;public class ConcurrentCalculator2 { private ExecutorService executorService; private CompletionService<Long> completionService; private int cpuCoreNumber; public ConcurrentCalculator2() { cpuCoreNumber = Runtime.getRuntime().availableProcessors(); executorService = Executors.newFixedThreadPool(cpuCoreNumber); completionService = new ExecutorCompletionService<Long>(executorService); } public Long sum(final int[] numbers) { for (int i = 0; i < cpuCoreNumber; i++) { // 根據CPU核心個數分割任務,建立FutureTask並提交到Executor int increment = numbers.length / cpuCoreNumber + 1; int start = increment * i; int end = increment * i + increment; if (end > numbers.length) end = numbers.length; SumCalculator subCalc = new SumCalculator(numbers, start, end); if (!executorService.isShutdown()) { completionService.submit(subCalc); } } return getResult(); } public Long getResult() { //迭代每個只任務,獲得部分和,相加返回 Long result = 0l; for (int i = 0; i < cpuCoreNumber; i++) { try { Long subSum = completionService.take().get(); result += subSum; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } return result; } public void close() { executorService.shutdown(); } class SumCalculator implements Callable<Long> {//Runnable private int[] numbers; private int start; private int end; public SumCalculator(final int[] numbers, int start, int end) { this.numbers = numbers; this.start = start; this.end = end; } @Override public Long call() throws Exception { Long sum = 0l; for (int i = start; i < end; i++) { sum += numbers[i]; } return sum; } } public static void main(String[] args) { int[] numbers = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; ConcurrentCalculator2 calculator = new ConcurrentCalculator2(); Long sum = calculator.sum(numbers); System.out.println(sum); calculator.close(); } /** * Callable 和 Future介面 * Callable是類似於Runnable的介面,實現Callable介面的類和實現Runnable的類都是可被其它線程執行的任務。 * Callable和Runnable有幾點不同: * (1)Callable規定的方法是call(),而Runnable規定的方法是run(). * (2)Callable的任務執行後可傳回值,而Runnable的任務是不能傳回值的。 * (3)call()方法可拋出異常,而run()方法是不能拋出異常的。 * (4)運行Callable任務可拿到一個Future對象, * Future 表示非同步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,並檢索計算的結果。 * 通過Future對象可瞭解任務執行情況,可取消任務的執行,還可擷取任務執行的結果。 */}
https://www.jb51.net/article/132606.htm:
我們都知道實現多線程有2種方式,一種是繼承Thread,一種是實現Runnable,但這2種方式都有一個缺陷,在任務完成後無法擷取返回結果。要想獲得返回結果,就得使用Callable,Callable任務可以有傳回值,但是沒法直接從Callable任務裡擷取傳回值;想要擷取Callabel任務的傳回值,需要用到Future。所以Callable任務和Future模式,通常結合起來使用。
試想一個情境:需要一個貼文清單介面,除了需要返回貼文清單之外,還需要返回每條文章的點贊列表和評論列表。一頁10條文章來計算,這個介面需要訪問21次資料庫,訪問一次資料庫按100ms計算,21次,累計時間為2.1s。這個回應時間,怕是無法令人滿意的。怎麼辦呢?非同步化改造介面。
查出貼文清單後,迭代貼文清單,在迴圈裡起10個線程,並發去擷取每條文章的點贊列表,同時另起10個線程,並發去擷取每條文章的評論列表。這樣改造之後,介面的回應時間大大縮短,在200ms。這個時候就要用Callabel結合Future來實現。
private List<PostResponse> createPostResponseList(Page<PostResponse> page,final String userId){ if(page.getCount()==0||page==null||page.getList()==null){ return null; } //擷取貼文清單 List<PostResponse> circleResponseList = page.getList(); int size=circleResponseList.size(); ExecutorService commentPool = Executors.newFixedThreadPool(size); ExecutorService supportPool = Executors.newFixedThreadPool(size); try { List<Future> commentFutureList = new ArrayList<Future>(size); if (circleResponseList != null && circleResponseList.size() > 0) { for (PostResponse postResponse : circleResponseList) { final String circleId=postResponse.getId(); final String postUserId=postResponse.getUserId(); //查評論列表 Callable<List<CircleReviews>> callableComment = new Callable<List<CircleReviews>>() { @Override public List<CircleReviews> call() throws Exception { return circleReviewsBiz.getPostComments(circleId); } }; Future f = commentPool.submit(callableComment); commentFutureList.add(f); //查點贊列表 Callable<List<CircleZan>> callableSupport = new Callable<List<CircleZan>>() { @Override public List<CircleZan> call() throws Exception { return circleZanBiz.findList(circleId); } }; Future supportFuture = supportPool.submit(callableSupport); commentFutureList.add(supportFuture); } } // 擷取所有並發任務的執行結果 int i = 0; PostResponse temp = null; for (Future f : commentFutureList) { temp = circleResponseList.get(i); temp.setCommentList((List<CircleReviews>) f.get(); temp.setSupportList((List<CircleZan>) f.get(); circleResponseList.set(i, temp); i++; } } catch (Exception e) { e.printStackTrace(); } finally { // 關閉線程池 commentPool.shutdown(); supportPool.shutdown(); } return circleResponseList; }
★ 下面給出一個Executor執行Callable任務的範例程式碼(17465497?utm_source=blogxgwz0):
import java.util.ArrayList; import java.util.List; import java.util.concurrent.*; public class CallableDemo{ public static void main(String[] args){ ExecutorService executorService = Executors.newCachedThreadPool(); List<Future<String>> resultList = new ArrayList<Future<String>>(); //建立10個任務並執行 for (int i = 0; i < 10; i++){ //使用ExecutorService執行Callable類型的任務,並將結果儲存在future變數中 Future<String> future = executorService.submit(new TaskWithResult(i)); //將任務執行結果儲存到List中 resultList.add(future); } //遍曆任務的結果 for (Future<String> fs : resultList){ try{ while(!fs.isDone);//Future返回如果沒有完成,則一直迴圈等待,直到Future返回完成 System.out.println(fs.get()); //列印各個線程(任務)執行的結果 }catch(InterruptedException e){ e.printStackTrace(); }catch(ExecutionException e){ e.printStackTrace(); }finally{ //啟動一次順序關閉,執行以前提交的任務,但不接受新任務 executorService.shutdown(); } } } } class TaskWithResult implements Callable<String>{ private int id; public TaskWithResult(int id){ this.id = id; } /** * 任務的具體過程,一旦任務傳給ExecutorService的submit方法, * 則該方法自動在一個線程上執行 */ public String call() throws Exception { System.out.println("call()方法被自動調用!!! " + Thread.currentThread().getName()); //該返回結果將被Future的get方法得到 return "call()方法被自動調用,任務返回的結果是:" + id + " " + Thread.currentThread().getName(); } }
某次執行結果如下:
從結果中可以同樣可以看出,submit也是首先選擇空閑線程來執行任務,如果沒有,才會建立新的線程來執行任務。另外,需要注意:如果Future的返回尚未完成,則get()方法會阻塞等待,直到Future完成返回,可以通過調用isDone()方法判斷Future是否完成了返回。
Executors Future Callable 執行個體