Thread Pooling(收藏)

當java程序中要用線程處理多個簡短任務的時候,使用一種叫做Thread Pooling的技術是很明智的選擇。爲了不對單個任務逐個創建(並在任務結束時結束)線程,過去我們經常自己編寫適合不同運行環境需要的線程池。雖然這些線程池的具體屬性參數不盡相同,但是大致都追尋着如下的應用套式:

把任務組引入到線程池裏面,
如果線程池中某個線程滿足執行條件,立刻執行
任務執行完畢,線程返回線程池
不滿足執行條件(比如線程池大小條件),等待執行

J2SE5.0現在提供了全新的java.util.concurrent包,其中有幾經構建好的線程池的框架。
例如:Executor接口提供了單獨的一個辦法execute來接收一個Runnable的實例對象:
public interface Executor {
public void execute(Runnable command);
}

所以我們可以創建一個Executor對象 然後把runnable任務引入:

Executor executor = ...; //可以完成implements後創建...
executor.execute(aRunnable1);
executor.execute(aRunnable2);
例如:

class MyExecutor implements Executor {
public void execute(Runnable r) {
new Thread(r).start();
}
}
在concurrency中還包括一個ThreadPoolExecutor類來提供一般通用用途的線程池操作.下面是4種該類的構造器.我們可以確定該類的某些屬性例如: 池的大小,活動時間,線程工廠和被拒絕運行線程控制器.

  public ThreadPoolExecutor(int corePoolSize,
                             int maximumPoolSize,
                             long keepAliveTime,
                             TimeUnit unit,
                             BlockingQueue workQueue)
   public ThreadPoolExecutor(int corePoolSize,
                             int maximumPoolSize,
                             long keepAliveTime,
                             TimeUnit unit,
                             BlockingQueue workQueue,
                             ThreadFactory threadFactory)
   public ThreadPoolExecutor(int corePoolSize,
                             int maximumPoolSize,
                             long keepAliveTime,
                             TimeUnit unit,
                             BlockingQueue workQueue,
                             RejectedExecutionHandler handler)
   public ThreadPoolExecutor(int corePoolSize,
                             int maximumPoolSize,
                             long keepAliveTime,
                             TimeUnit unit,
                             BlockingQueue workQueue,
                             ThreadFactory threadFactory,
                             RejectedExecutionHandler handler)
其實我們實際使用線程池的時候並不需要用構造器來專門建立上面的ThreadPoolExecutor的對象.Executors類中已經創建了默認的線程池.例如我們可以在Executors中調用newFixedThreadPool辦法規定你需要的線程池的大小.可以使用一個繼承了Executor的ExectuorService類來運行或者提交Runnalbe任務組. ExectuorService的提交辦法 -- submit 允許得到一個結果F, 而且返回FUTURE OBJECT,可以用來檢查是否任務已經執行完畢.
下面是一個具體的應用實例: -- 摘自sun技術論壇

  
     public class NamePrinter implements Runnable {
     private final String name;
     private final int delay;
     public NamePrinter(String name, int delay) {
       this.name = name;
       this.delay = delay;
     }
     public void run() {
       System.out.println("Starting: " + name);
       try {
         Thread.sleep(delay);
       } catch (InterruptedException ignored) {
       }
       System.out.println("Done with: " + name);
     }
   }

----------------------------------------------------------------------------------

   import java.util.concurrent.*;
   import java.util.Random;


   public class UsePool {
     public static void main(String args[]) {
       Random random = new Random();
       ExecutorService executor =
               Executors.newFixedThreadPool(3); //設定線程池容量爲3
       // Sum up wait times to know when to shutdown
       int waitTime = 500;
       for (int i=0; i<10; i++) {
         String name = "NamePrinter " + i;
         int time = random.nextInt(1000);
         waitTime += time;
         Runnable runner = new NamePrinter(name, time);
         System.out.println("Adding: " + name + " / " + time);
         executor.execute(runner);
       }
       try {
         Thread.sleep(waitTime);
         executor.shutdown();
         executor.awaitTermination
                 (waitTime, TimeUnit.MILLISECONDS);
       } catch (InterruptedException ignored) {
       }
       System.exit(0);
     }
    }

----------------------------------------------------------------------------------
可能輸出:


unique with the random sleeps present:

   Adding: NamePrinter 0 / 30
   Adding: NamePrinter 1 / 727
   Adding: NamePrinter 2 / 980  //前3個添加進行的明顯比較快
   Starting: NamePrinter 0
   Starting: NamePrinter 1
   Starting: NamePrinter 2
   Adding: NamePrinter 3 / 409
   Adding: NamePrinter 4 / 49
   Adding: NamePrinter 5 / 802
   Adding: NamePrinter 6 / 211
   Adding: NamePrinter 7 / 459
   Adding: NamePrinter 8 / 994
   Adding: NamePrinter 9 / 459
   Done with: NamePrinter 0    雖然任務全部已經添加到線程池,
   Starting: NamePrinter 3     但是因爲線程池容量爲3個,
   Done with: NamePrinter 3    前3個任務又都在執行,
   Starting: NamePrinter 4     所以任務3一直等到任務0結束纔開始執行
   Done with: NamePrinter 4
   Starting: NamePrinter 5
   Done with: NamePrinter 1
   Starting: NamePrinter 6
   Done with: NamePrinter 6
   Starting: NamePrinter 7
   Done with: NamePrinter 2
   Starting: NamePrinter 8
   Done with: NamePrinter 5
   Starting: NamePrinter 9
   Done with: NamePrinter 7
   Done with: NamePrinter 9
   Done with: NamePrinter 8


線程池框架中還有很多其它的內容,請參考api. 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章