1. 程式人生 > >JAVA並行非同步程式設計執行緒池+FutureTask

JAVA並行非同步程式設計執行緒池+FutureTask

java 在JDK1.5中引入一個新的併發包java.util.concurrent 該包專門為java處理併發而書寫。

在java中熟悉的使用多執行緒的方式為兩種?繼續Thread類,實現Runnale。兩種方式簡單方便。

在Jdk1.5之後其實有第三種方式實現方式,採用併發包中的Callable介面 FuruteTask類 以及ExecutorService介面。

說新的實現方式之前先來說討論一下傳統的java執行過程

首先一個簡單的程式一個方法生成隨機數,在生成隨機數的方法執行中,睡眠1s模擬方法呼叫時候的耗時,把結果放進集合中,最後算到總結果。

Java程式碼  收藏程式碼
  1. public
       
  2.         class Count{  
  3.                 public static void main(String[] args) throws InterruptedException {  
  4.                         long start = System.currentTimeMillis();  
  5.                        Count count = new Count();  
  6.                        List<Integer> res = new ArrayList<>();  
  7.                        res.add(count.random());  
  8.                        res.add(count.random());  
  9.                        res.add(count.random());  
  10.                        res.add(count.random());  
  11.                        int totle =0;  
  12.                        for (int i = 0; i < res.size(); i++) {  
  13.                                totle+=res.get(i);  
  14.                        }  
  15.                       long end = System.currentTimeMillis();  
  16.                        System.out.println("運算結束 耗時:"+(end-start)+"ms  totle:"+totle );  
  17.                        System.out.println("退出main執行緒!");  
  18.                }  
  19.                 int random() throws InterruptedException{  
  20.                         Thread.sleep(1000); //  
  21.                         return new Random().nextInt(100);  
  22.                 }  
  23.         }  

    結果如下

Java程式碼  收藏程式碼
  1. 運算結束 耗時:4000ms  totle:66  
  2. 退出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之後出現了一個新包,專門為併發而開發的包,使用併發包中提供的類和介面,將很輕易的實現。併發程式設計。

Java程式碼  收藏程式碼
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3. import java.util.Random;  
  4. import java.util.concurrent.Callable;  
  5. import java.util.concurrent.ExecutionException;  
  6. import java.util.concurrent.ExecutorService;  
  7. import java.util.concurrent.Executors;  
  8. import java.util.concurrent.FutureTask;  
  9.  public class TestMain {  
  10.         public static void main(String[] args) throws InterruptedException, ExecutionException {  
  11.                 new  TestMain().exec();  
  12.         }  
  13.         void exec() throws InterruptedException, ExecutionException{  
  14.                 //進行非同步任務列表  
  15.                 List<FutureTask<Integer>> futureTasks = new ArrayList<FutureTask<Integer>>();  
  16.                 //執行緒池 初始化十個執行緒 和JDBC連線池是一個意思 實現重用   
  17.                 ExecutorService executorService = Executors.newFixedThreadPool(10);  
  18.                 long start = System.currentTimeMillis();  
  19.                 //類似與run方法的實現 Callable是一個介面,在call中手寫邏輯程式碼  
  20.                 Callable<Integer> callable = new Callable<Integer>() {  
  21.                         @Override  
  22.                         public Integer call() throws Exception {  
  23.                                 Integer res = new Random().nextInt(100);  
  24.                                 Thread.sleep(1000);  
  25.                                 System.out.println("任務執行:獲取到結果 :"+res);  
  26.                                 return  res;  
  27.                         }  
  28.                 };  
  29.                 for(int i=0;i<10;i++){  
  30.                         //建立一個非同步任務  
  31.                         FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);  
  32.                         futureTasks.add(futureTask);  
  33.                         //提交非同步任務到執行緒池,讓執行緒池管理任務 特爽把。  
  34.                                //由於是非同步並行任務,所以這裡並不會阻塞  
  35.                         executorService.submit(futureTask);   
  36.                 }  
  37.                 int count = 0;  
  38.              for (FutureTask<Integer> futureTask : futureTasks) {  
  39.                      //futureTask.get() 得到我們想要的結果   
  40.                      //該方法有一個過載get(long timeout, TimeUnit unit) 第一個引數為最大等待時間,第二個為時間的單位  
  41.                      count+= futureTask.get();  
  42.         }  
  43.            long end = System.currentTimeMillis();  
  44.            System.out.println("執行緒池的任務全部完成:結果為:"+count+",main執行緒關閉,進行執行緒的清理");  
  45.            System.out.println("使用時間:"+(end-start)+"ms");  
  46.            //清理執行緒池   
  47.            executorService.shutdown();  
  48.         }  
  49. }  

 上述情況如果不用非同步並行,程式將至少睡眠10s

 使用之後的結果

Java程式碼  收藏程式碼
  1. 任務執行:獲取到結果 :99  
  2. 任務執行:獲取到結果 :78  
  3. 任務執行:獲取到結果 :52  
  4. 任務執行:獲取到結果 :78  
  5. 任務執行:獲取到結果 :97  
  6. 任務執行:獲取到結果 :8  
  7. 任務執行:獲取到結果 :97  
  8. 任務執行:獲取到結果 :3  
  9. 任務執行:獲取到結果 :78  
  10. 任務執行:獲取到結果 :31  
  11. 執行緒池的任務全部完成:結果為:621,main執行緒關閉,進行執行緒的清理  
  12. 使用時間:<span style="color: #ff0000;"><span style="color: #000000;">1004ms</span> </span>  

   我們試著把執行緒池的大小減少一半

Java程式碼  收藏程式碼
  1. 任務執行:獲取到結果 :87  
  2. 任務執行:獲取到結果 :60  
  3. 任務執行:獲取到結果 :13  
  4. 任務執行:獲取到結果 :18  
  5. 任務執行:獲取到結果 :8  
  6. 任務執行:獲取到結果 :86  
  7. 任務執行:獲取到結果 :52  
  8. 任務執行:獲取到結果 :4  
  9. 任務執行:獲取到結果 :23  
  10. 任務執行:獲取到結果 :16  
  11. 執行緒池的任務全部完成:結果為:367,main執行緒關閉,進行執行緒的清理  
  12. 使用時間:<span style="color: #000000;">2017ms  
  13. </span>  

   好玩吧 時間延長了一半。