程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java線程池(一)

Java線程池(一)

編輯:關於JAVA

Java線程池(一)。本站提示廣大學習愛好者:(Java線程池(一))文章只能為提供參考,不一定能成為您想要的結果。以下是Java線程池(一)正文


為何運用線程池?

  • 第一:降低資源耗費。經過反復應用已創立的線程降低線程創立和銷毀形成的耗費。

  • 第二:進步呼應速度。當義務抵達時,義務可以不需求等到線程創立就能立刻執行。

  • 第三:進步線程的可管感性。線程是稀缺資源,假如有限制地創立,不只會耗費零碎資源,還會降低零碎的波動性,運用線程池可以停止一致分配、調優和監控。

線程池如何處置義務?

先看線程池處置義務的機制圖:

線程池處理流程

 

 

 

 

 

 

 

 

 

 

 

 

 

從上圖中可以看出,當提交一個新義務到線程池時,線程池的處置流程如下:

  1. 線程池判別中心線程池裡的線程能否都在執行義務。假如不是,則創立一個新的任務線程來執行義務。假如中心線程池裡的線程都在執行義務,則進入下個流程。

  2. 線程池判別任務隊列能否曾經滿。假如任務隊列沒有滿,則將新提交的義務存儲在這個任務隊列裡。假如任務隊列滿了,則進入下個流程。

  3. 線程池判別線程池的線程能否都處於任務形態。假如沒有,則創立一個新的任務線程來執行義務。假如曾經滿了,則交給飽和戰略來處置這個義務。

ThreadPoolExecutor執行execute辦法分上面4種狀況:

  1. 假如以後運轉的線程少於corePoolSize,則創立新線程來執行義務(留意,執行這一步驟需求獲取全局鎖)。

  2. 假如運轉的線程等於或多於corePoolSize,則將義務參加BlockingQueue。

  3. 假如無法將義務參加BlockingQueue(隊列已滿),則創立新的線程來處置義務(留意,執行這一步驟需求獲取全局鎖)。

  4. 假如創立新線程將使以後運轉的線程超出maximumPoolSize,義務將被回絕,並調用RejectedExecutionHandler.rejectedExecution()辦法。

上面是ThreadPoolExecutor的執行流程圖:

ThreadPoolExecutor執行流程

 

 

 

 

 

 

 

 

 

 

 

如何創立一個線程池?

創立線程池很復雜,Java提供了ThreadPoolExecutor類。上面的語句就能創立一個大小為10的線程池。

1 new ThreadPoolExecutor(10,10,1,TimeUnit.DAYS);

先來看看ThreadPoolExecutor類的辦法簽名:

 1 public ThreadPoolExecutor(int corePoolSize,        //線程池根本大小
 2                           int maximumPoolSize,    //線程池最大線程數
 3                           long keepAliveTime,    //線程活動堅持時間
 4                           TimeUnit unit,        //線程活動時間單位
 5                           BlockingQueue<Runnable> workQueue,
 6 
 7 public ThreadPoolExecutor(int corePoolSize,        //線程池根本大小
 8                           int maximumPoolSize,    //線程池最大線程數
 9                           long keepAliveTime,    //線程活動堅持時間
10                           TimeUnit unit,        //線程活動時間單位
11                           BlockingQueue<Runnable> workQueue,    //義務隊列
12                           ThreadFactory threadFactory,        //發生線程的工廠
13                           RejectedExecutionHandler handler    //飽和戰略);

上面詳細的解說一下這幾個參數:

  • corePoolSize(線程池的根本大小):當提交一個義務到線程池時,線程池會創立一個線程來執行義務,即便其他閒暇的根本線程可以執行新義務也會創立線程,等到需求執行的義務數大於線程池根本大小時就不再創立。假如調用了線程池的prestartAllCoreThreads()辦法,線程池會提早創立並啟動一切根本線程。

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

  • keepAliveTime(線程活動堅持時間):線程池的任務線程閒暇後,堅持存活的時間。所以,假如義務很多,並且每個義務執行的時間比擬短,可以調大時間,進步線程的應用率。

  • TimeUnit(線程活動堅持時間的單位):可選的單位有天、小時、分鐘、毫秒、微秒和納秒。

  • runnableTaskQueue(義務隊列):用於保管等候執行的義務的阻塞隊列。可選項有:

    • ArrayBlockingQueue:是一個基於數組構造的有界阻塞隊列,此隊列按FIFO(先進先出)准繩對元素停止排序。

    • LinkedBlockingQueue:一個基於鏈表構造的阻塞隊列,此隊列按FIFO排序元素,吞吐量通常要高於ArrayBlockingQueue。靜態工廠辦法Executors.newFixedThreadPool()運用了這個隊列。

    • SynchronousQueue:一個不存儲元素的阻塞隊列。每個拔出操作必需等到另一個線程調用移除操作,否則拔出操作不斷處於阻塞形態,吞吐量通常要高於Linked-BlockingQueue,靜態工廠辦法Executors.newCachedThreadPool運用了這個隊列。

    • PriorityBlockingQueue:一個具有優先級的有限阻塞隊列。

  • ThreadFactory:用於設置創立線程的工廠。

  • RejectedExecutionHandler(飽和戰略):當隊列和線程池都滿了,闡明線程池處於飽和狀態,那麼必需采取一種戰略處置提交的新義務。這個戰略默許狀況下是AbortPolicy,表示無法處置新義務時拋出異常。

向線程池提交義務

ThreadPoolExecutor提供了兩個辦法可以向線程池提交義務去執行:submit()和execute()。

  • execute()辦法用於執行不需求前往後果的義務。所以無法判別義務能否被線程池執行成功。

  • submit()辦法用於提交需求前往值的義務。線程池會前往一個future類型的對象,經過這個future對象可以判別義務能否執行成功,並且可以經過future的get()辦法來獲取前往值。get()辦法會阻塞以後線程直就任務完成,而運用get(long timeout,TimeUnit unit)辦法則會阻塞以後線程一段時間後立刻前往,這時分有能夠義務沒有執行完。

看上面一段代碼:

 1 package com.alibaba.thread;
 2 
 3 import java.util.concurrent.*;
 4 
 5 /**
 6  * Created by zhouxuanyu on 2016/12/6.
 7  */
 8 public class CallableAndFuture {
 9     public static void main(String[] args) throws ExecutionException, InterruptedException {
10         ExecutorService executorService = Executors.newScheduledThreadPool(3);
11 
12         Runnable runnable = new Runnable() {
13             public void run() {
14                 System.out.print("runnable()");
15             }
16         };
17 
18         executorService.execute(runnable);  //execute()拿不到前往值
19 
20         Callable<String> callable = new Callable<String>() {
21             public String call() throws Exception {
22                 return "callable";
23             }
24         };
25 
26         Future<String> future = executorService.submit(callable);//submit()可以拿到前往值
27 
28         System.out.print(future.get());
29 
30     }
31 }

 

CompletionService

​  有了下面的根底,我們可以知道,當我們需求異步執行某個義務的時分,可以將這個義務丟到線程池中,假如不需求後果前往,那麼可以運用execute();相反,則需求運用submit()。當有多個義務執行,比方十個,在交給線程池去執行時,我們固然可以為這十個義務關聯十個Future而拿到後果。但是這樣做真實比擬low!

​ Java為我們提供了一個名叫CompletionService的接口,它是Executor和BlockQueue的結合體。你可以將Callable義務交給CompletionService去執行,然後運用相似隊列的take()和poll()辦法拿到Future類型的後果。ExecutorCompletionService是CompletionService的一個完成,它將義務交給executor去執行。

​  先看一下ExecutorCompletionService的結構辦法:

1 public ExecutorCompletionService(Executor executor,
2                                  BlockingQueue<Future<V>> completionQueue)

  由結構函數可以看到,executor是執行義務的執行器,而completionQueue是用來保管執行後果的隊列。當提交一個義務之後,會首先把這個義務包裝為一個QueueingFuture。QueueingFuture是FutureTask的子類。然後復寫了done()辦法,將執行後果放入completionQueue中。

從下面可以知道,ExecutorCompletionService完成了哪一個義務先執行完就前往,而不是按義務添加的順序前往。

上面一個例子:

 1 package com.alibaba.thread;
 2 
 3 import java.util.Random;
 4 import java.util.concurrent.*;
 5 
 6 /**
 7  * Created by zhouxuanyu on 2016/12/14.
 8  */
 9 public class TestCompletionService {
10 
11     public static void main(String[] args){
12 
13         ExecutorService executorService = Executors.newFixedThreadPool(11); //創立一個大小為11的線程池
14         final BlockingQueue<Future<String>> blockingQueue = new LinkedBlockingQueue<Future<String>>();//創立一個後果隊列
15 
16         CompletionService<String> completionService = new ExecutorCompletionService<String>(executorService,blockingQueue);
17 
18         //運用completionService向線程池中添加10個義務
19         for (int i = 0; i < 10; i++) {
20             completionService.submit(new Callable<String>() {
21                 public String call() throws Exception {
22                     int random = new Random().nextInt(10000);
23                     Thread.sleep(random);
24                     return Thread.currentThread().getName() + "---sleep---" + random;
25                 }
26             });
27         }
28 
29         //依照執行完成的特地取出曾經完成的義務。
30         for (int i = 0; i < 10; i++) {
31             try {
32                 Future future = completionService.take();
33                 System.out.println(future.get(1000,TimeUnit.NANOSECONDS));
34             } catch (InterruptedException e) {
35                 e.printStackTrace();
36             } catch (ExecutionException e) {
37                 e.printStackTrace();
38             } catch (TimeoutException e) {
39                 e.printStackTrace();
40             }
41         }
42 
43         //封閉線程池
44         executorService.shutdown();
45     }
46 }
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved