Java中的線程池

來源:互聯網
上載者:User

標籤:sub   integer   類型   oop   led   cas   logs   rup   儲存   

1、使用線程池的好處                                             

a、降低資源消耗。通過重複利用已建立的線程降低線程建立和摧毀造成的消耗;

b、提高響應速度。當任務到達時,任務可以不需要等到線程建立就能立即執行;

c、提高線程的可管理性。線程是稀缺資源,如果無限制地建立,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以及進行統一分配、調優和監控。

2、線程池的實現原理                                              

當線程池想提交一個任務之後,線程池的主要處理流程

jdk1.8中ThreadPoolExecutor執行execute()方法的原始碼如下:

 1 public void execute(Runnable command) { 2         if (command == null) 3             throw new NullPointerException(); 4         int c = ctl.get();//原子類型AtomicInteger ctl,擷取值 5         if (workerCountOf(c) < corePoolSize) {//判斷當前背景工作執行緒是否小於核心線程數目 6             if (addWorker(command, true))//是則建立新的背景工作執行緒,並將當前任務傳遞進去處理後返回結果,corePoolSize  7                 return; 8             c = ctl.get();//如果失敗,繼續執行下面的代碼進行判斷 9         }10         if (isRunning(c) && workQueue.offer(command)) {11             int recheck = ctl.get();12             if (! isRunning(recheck) && remove(command))13                 reject(command);14             else if (workerCountOf(recheck) == 0)15                 addWorker(null, false);//加入背景工作執行緒16         }17         else if (!addWorker(command, false))//建立新的線程,maximumPoolSize18             reject(command);19     }

注意addWork的第二個參數core的作用:core ? corePoolSize : maximumPoolSize

 

 1 private boolean addWorker(Runnable firstTask, boolean core) { 2         retry: 3         for (;;) { 4             int c = ctl.get(); 5             int rs = runStateOf(c); 6  7             // Check if queue empty only if necessary. 8             if (rs >= SHUTDOWN && 9                 ! (rs == SHUTDOWN &&10                    firstTask == null &&11                    ! workQueue.isEmpty()))12                 return false;13 14             for (;;) {15                 int wc = workerCountOf(c);16                 if (wc >= CAPACITY ||17                     wc >= (core ? corePoolSize : maximumPoolSize))18                     return false;19                 if (compareAndIncrementWorkerCount(c))20                     break retry;21                 c = ctl.get();  // Re-read ctl22                 if (runStateOf(c) != rs)23                     continue retry;24                 // else CAS failed due to workerCount change; retry inner loop25             }26         }

線程池中的線程執行任務分為兩種情況:

a、在execute()方法中建立一個線程時,會讓這個線程執行當前任務;

b、在這個線程執行完上述任務後,會反覆從BlockingQueue擷取任務來執行。

 3、線程池的使用                                                          

我們可以通過ThreadPoolExecutor來建立一個線程池。

new ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler);

corePoolSize線程池的基本大小,當提交一個任務到線程池時,線程池會建立一個線程來執行任務,即使其他閒置基本線程能夠執行新任務也會建立線程,等到需要執行的任務數大於線程池基本大小時就不再建立。如果調用了線程池的prestartAllCoreThreads()方法,線程池會提前建立並啟動所有基本線程。

maximumPoolSize:線程池的最大數量,線程池允許建立的最大線程數。如果隊列滿了,並且已建立的線程數小於最大線程數,則線程池會再建立新的線程執行任務。值得注意的是,如果使用了無界的任務隊列這個參數就沒什麼效果。

KeepAliveTime:線程活動保持時間,線程池的背景工作執行緒空閑後,保持存活的時間。

unit:線程活動保持時間的單位,可選的單位有天,小時,分鐘,毫秒,微秒,納秒。

workQueue:任務隊列,用來儲存等待執行的任務的阻塞隊列。在任務被執行之前儲存這些任務,工作隊列僅儲存執行了execute方法的任務。可以選擇以下幾個阻塞隊列:ArrayBlockingQueue,LinkedBlockingQueue,SynchronousQueue和PriorityBlockingQueue。

threadFactory:用於設定建立線程的工廠,可以通過線程工廠給每個建立出來的線程設定更有意義的名字。

handler:飽和策略,當隊列和線程池都滿了,說明線程池處於飽和狀態,那麼必須採取一種策略處理提交的新任務。這個策略預設情況下是AbortPolicty,表示無法處理新任務時拋出異常。

4、向線程池提交任務                                                      
可以使用兩個方法向線程池提交任務,分別是execute()和submit()方法。

execute()方法用於提交不需要傳回值的任務,所以無法判斷任務是否被線程池執行成功。

submit()方法用於提交需要傳回值的任務。線程池會返回一個future類型的對象,通過這個future對象可以判斷任務是否執行成功,並且可以通過future的get()方法來擷取傳回值,get()方法會阻塞當前線程知道任務完成,而使用get(long timeout, TimeUnit unit)方法則會阻塞當前線程一段時間後立即返回,這時候可能任務還沒有執行完。

 5、關閉線程池                                                      

可以通過調用線程池的shutdownshutdownNow方法來關閉線程池。

原理:遍曆線程池中的背景工作執行緒,然後逐個調用線程的interrupt方法來中斷線程,所以無法響應中斷的任務可能永遠無法終止

區別shutdownNow先將線程池的狀態設定成STOP,然後嘗試停止所有正在執行或暫停任務的額線程,並返回等待執行任務的列表;

shutdown只是將線程池的狀態設定成SHUTDOWN狀態,然後中斷所有沒有正在執行任務的線程。

通常調用shutdown來關閉線程池,如果任務不一定要執行完,則可以調用shutdownNow方法。

建議使用有界隊列:能增加系統的穩定性和預警能力。

Java中的線程池

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.