JAVA並行非同步程式設計執行緒池+FutureTask
java 在JDK1.5中引入一個新的併發包java.util.concurrent 該包專門為java處理併發而書寫。
在java中熟悉的使用多執行緒的方式為兩種?繼續Thread類,實現Runnale。兩種方式簡單方便。
在Jdk1.5之後其實有第三種方式實現方式,採用併發包中的Callable介面 FuruteTask類 以及ExecutorService介面。
說新的實現方式之前先來說討論一下傳統的java執行過程
首先一個簡單的程式一個方法生成隨機數,在生成隨機數的方法執行中,睡眠1s模擬方法呼叫時候的耗時,把結果放進集合中,最後算到總結果。
Java程式碼-
public
- class Count{
- public static void main(String[] args) throws InterruptedException {
- long start = System.currentTimeMillis();
- Count count = new Count();
-
List<Integer> res = new ArrayList<>();
- res.add(count.random());
- res.add(count.random());
- res.add(count.random());
- res.add(count.random());
- int totle =0;
-
for (int i = 0; i < res.size(); i++) {
- totle+=res.get(i);
- }
- long end = System.currentTimeMillis();
- System.out.println("運算結束 耗時:"+(end-start)+"ms totle:"+totle );
- System.out.println("退出main執行緒!");
- }
- int random() throws InterruptedException{
- Thread.sleep(1000); //
- return new Random().nextInt(100);
- }
- }
結果如下
Java程式碼- 運算結束 耗時:4000ms totle:66
- 退出main執行緒!
在傳統的編寫中是單執行緒的操作,序列操作,當呼叫方法count.random(),main執行緒被阻塞起來,直到睡眠時間到達,自動喚醒main執行緒。
http://dl2.iteye.com/upload/attachment/0098/3095/cc443846-46c3-338b-aa03-27b649c510ca.png
java為我們提供了多執行緒機制,利用多執行緒我們可以實現方法的並行運算,實現多執行緒的辦法,實現Runnable介面重新run,繼承Thread 重寫run;因為run方法的並沒有返回值,我們手動的去建立大量的執行緒並且維護執行緒是件很討厭的事情,並且建立執行緒也是非常耗費資源的操作,能不能有一個池子來幫我們管理執行緒呢?有沒有一個類能夠透明的去進行透明併發的非同步操作呢?這個在JDK1.5之前是沒有的,在1,5之後出現了一個新包,專門為併發而開發的包,使用併發包中提供的類和介面,將很輕易的實現。併發程式設計。
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Random;
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.FutureTask;
- public class TestMain {
- public static void main(String[] args) throws InterruptedException, ExecutionException {
- new TestMain().exec();
- }
- void exec() throws InterruptedException, ExecutionException{
- //進行非同步任務列表
- List<FutureTask<Integer>> futureTasks = new ArrayList<FutureTask<Integer>>();
- //執行緒池 初始化十個執行緒 和JDBC連線池是一個意思 實現重用
- ExecutorService executorService = Executors.newFixedThreadPool(10);
- long start = System.currentTimeMillis();
- //類似與run方法的實現 Callable是一個介面,在call中手寫邏輯程式碼
- Callable<Integer> callable = new Callable<Integer>() {
- @Override
- public Integer call() throws Exception {
- Integer res = new Random().nextInt(100);
- Thread.sleep(1000);
- System.out.println("任務執行:獲取到結果 :"+res);
- return res;
- }
- };
- for(int i=0;i<10;i++){
- //建立一個非同步任務
- FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);
- futureTasks.add(futureTask);
- //提交非同步任務到執行緒池,讓執行緒池管理任務 特爽把。
- //由於是非同步並行任務,所以這裡並不會阻塞
- executorService.submit(futureTask);
- }
- int count = 0;
- for (FutureTask<Integer> futureTask : futureTasks) {
- //futureTask.get() 得到我們想要的結果
- //該方法有一個過載get(long timeout, TimeUnit unit) 第一個引數為最大等待時間,第二個為時間的單位
- count+= futureTask.get();
- }
- long end = System.currentTimeMillis();
- System.out.println("執行緒池的任務全部完成:結果為:"+count+",main執行緒關閉,進行執行緒的清理");
- System.out.println("使用時間:"+(end-start)+"ms");
- //清理執行緒池
- executorService.shutdown();
- }
- }
上述情況如果不用非同步並行,程式將至少睡眠10s
使用之後的結果
Java程式碼- 任務執行:獲取到結果 :99
- 任務執行:獲取到結果 :78
- 任務執行:獲取到結果 :52
- 任務執行:獲取到結果 :78
- 任務執行:獲取到結果 :97
- 任務執行:獲取到結果 :8
- 任務執行:獲取到結果 :97
- 任務執行:獲取到結果 :3
- 任務執行:獲取到結果 :78
- 任務執行:獲取到結果 :31
- 執行緒池的任務全部完成:結果為:621,main執行緒關閉,進行執行緒的清理
- 使用時間:<span style="color: #ff0000;"><span style="color: #000000;">1004ms</span> </span>
我們試著把執行緒池的大小減少一半
Java程式碼- 任務執行:獲取到結果 :87
- 任務執行:獲取到結果 :60
- 任務執行:獲取到結果 :13
- 任務執行:獲取到結果 :18
- 任務執行:獲取到結果 :8
- 任務執行:獲取到結果 :86
- 任務執行:獲取到結果 :52
- 任務執行:獲取到結果 :4
- 任務執行:獲取到結果 :23
- 任務執行:獲取到結果 :16
- 執行緒池的任務全部完成:結果為:367,main執行緒關閉,進行執行緒的清理
- 使用時間:<span style="color: #000000;">2017ms
- </span>
好玩吧 時間延長了一半。