ExecutorService線程池講解


ExecutorService 建立多線程的步驟:

1。定義線程類 class Handler implements Runnable{
} 
2。建立ExecutorService線程池 ExecutorService executorService = Executors.newCachedThreadPool();

或者

int cpuNums = Runtime.getRuntime().availableProcessors();
               //獲取當前系統的CPU 數目
ExecutorService executorService =Executors.newFixedThreadPool(cpuNums * POOL_SIZE);
               //ExecutorService通常根據系統資源情況靈活定義線程池大小
 
3。調用線程池操作 循環操作,成為daemon,把新實例放入Executor池中
     while(true){
       executorService.execute(new Handler(socket)); 
          // class Handler implements Runnable{
       或者
       executorService.execute(createTask(i));
           //private static Runnable createTask(final int taskID)
     }

execute(Runnable對象)方法
其實就是對Runnable對象調用start()方法
(當然還有一些其他后台動作,比如隊列,優先級,IDLE timeout,active激活等)
 

幾種不同的ExecutorService線程池對象

1.newCachedThreadPool()  -緩存型池子,先查看池中有沒有以前建立的線程,如果有,就reuse.如果沒有,就建一個新的線程加入池中
-緩存型池子通常用於執行一些生存期很短的異步型任務
 因此在一些面向連接的daemon型SERVER中用得不多。
-能reuse的線程,必須是timeout IDLE內的池中線程,缺省timeout是60s,超過這個IDLE時長,線程實例將被終止及移出池。
 注意,放入CachedThreadPool的線程不必擔心其結束,超過TIMEOUT不活動,其會自動被終止。 
2. newFixedThreadPool -newFixedThreadPool與cacheThreadPool差不多,也是能reuse就用,但不能隨時建新的線程
-其獨特之處:任意時間點,最多只能有固定數目的活動線程存在,此時如果有新的線程要建立,只能放在另外的隊列中等待,直到當前的線程中某個線程終止直接被移出池子
-和cacheThreadPool不同,FixedThreadPool沒有IDLE機制(可能也有,但既然文檔沒提,肯定非常長,類似依賴上層的TCP或UDP IDLE機制之類的),所以FixedThreadPool多數針對一些很穩定很固定的正規並發線程,多用於服務器
-從方法的源代碼看,cache池和fixed 池調用的是同一個底層池,只不過參數不同:
fixed池線程數固定,並且是0秒IDLE(無IDLE)
cache池線程數支持0-Integer.MAX_VALUE(顯然完全沒考慮主機的資源承受能力),60秒IDLE   
3.ScheduledThreadPool -調度型線程池
-這個池子里的線程可以按schedule依次delay執行,或周期執行 
4.SingleThreadExecutor -單例線程,任意時間池中只能有一個線程
-用的是和cache池和fixed池相同的底層池,但線程數目是1-1,0秒IDLE(無IDLE) 

上面四種線程池,都使用Executor的缺省線程工廠建立線程,也可單獨定義自己的線程工廠
下面是缺省線程工廠代碼:

   static class DefaultThreadFactory implements ThreadFactory {
       static final AtomicInteger poolNumber = new AtomicInteger(1);
       final ThreadGroup group;
       final AtomicInteger threadNumber = new AtomicInteger(1);
       final String namePrefix;

       DefaultThreadFactory() {
           SecurityManager s = System.getSecurityManager();
           group = (s != null)? s.getThreadGroup() :Thread.currentThread().getThreadGroup();
          
           namePrefix = “pool-” + poolNumber.getAndIncrement() + “-thread-“;
       }

       public Thread newThread(Runnable r) {
           Thread t = new Thread(group, r,namePrefix + threadNumber.getAndIncrement(),0);
           if (t.isDaemon())
               t.setDaemon(false);
           if (t.getPriority() != Thread.NORM_PRIORITY)
               t.setPriority(Thread.NORM_PRIORITY);
           return t;
       }
   }
 

也可自己定義ThreadFactory,加入建立池的參數中

 public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { 

Executor的execute()方法
execute() 方法將Runnable實例加入pool中,並進行一些pool size計算和優先級處理
execute() 方法本身在Executor接口中定義,有多個實現類都定義了不同的execute()方法
如ThreadPoolExecutor類(cache,fiexed,single三種池子都是調用它)的execute方法如下:

   public void execute(Runnable command) {
       if (command == null)
           throw new NullPointerException();
       if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
           if (runState == RUNNING && workQueue.offer(command)) {
               if (runState != RUNNING || poolSize == 0)
                   ensureQueuedTaskHandled(command);
           }
           else if (!addIfUnderMaximumPoolSize(command))
               reject(command); // is shutdown or saturated
       }
   } 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM