標籤:線程池 並發 編程 java
概述:
線程池機制是事先建立一些線程等待服務端程式的調用,這些線程儲存在一個數組結構中,稱為“線程池”。當伺服器有任務執行時,就從線程池中取出一個線程並給其分配任務,當線程任務執行完成後,再被放回線程池中。
優點:
1. 由於在任務到達之前,線程已經存在,所以這裡為系統消除了線程建立的資源和時間的開銷。可以立即為請求服務,使程式響應更快。
2. 通過適當地調節線程池中的線程數目,就強制使一些新到的任務處於等待狀態,可以防止資源不足。
參考:
http://www.cnblogs.com/dolphin0520/p/3932921.html
《Java語言程式設計》——清華大學出版社
樣本及分析:
MyTask.java
public class MyTask implements Runnable {private int taskNum;public MyTask(int num) {this.taskNum = num;}@Overridepublic void run() {System.out.println("正在執行task " + taskNum);try {Thread.currentThread().sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("task " + taskNum + "執行完畢");}}上面的程式很簡單,就只是去列印一些簡單的資訊。
Executor.java
public class Executor {public static void main(String[] args) {ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5));for (int i = 0; i < 15; i++) {MyTask myTask = new MyTask(i);if (!executor.isShutdown()) {executor.execute(myTask);}printExecutor(executor);}executor.shutdown();}private static void printExecutor(ThreadPoolExecutor executor) {System.out.println("線程池中線程數目:" + executor.getPoolSize()+ ",隊列中等待執行的任務數目:" + executor.getQueue().size()+ ",已執行完別的任務數目:" + executor.getCompletedTaskCount());}}
上面用到了java為我們提供的類ThreadPoolExecutor,這是一個很好的類。上面用到建立執行個體時用到的構造器如下:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }
它包含了下面這隻個參數:
int corePoolSize:線程池中線程數
int maximumPoolSize:線程池中最大的線程數
long keepAliveTime:表示線程沒有任務執行時最多保持多久時間會終止
TimeUnit unit:參數keepAliveTime的時間單位,在TimeUnit類中有7種靜態屬性:
TimeUnit.DAYS; //天TimeUnit.HOURS; //小時TimeUnit.MINUTES; //分鐘TimeUnit.SECONDS; //秒TimeUnit.MILLISECONDS; //毫秒TimeUnit.MICROSECONDS; //微妙TimeUnit.NANOSECONDS; //納秒
BlockingQueue<Runnable> workQueue:一個阻塞隊列,用來儲存等待執行的任務
<pre name="code" class="java">ArrayBlockingQueue;LinkedBlockingQueue;SynchronousQueue;
上面代碼中使用的是ArrayBlockingQueue阻塞隊列,並傳入了參數5。這裡有一點需要注意一下,如果我們假設所有任務數為mTaskCount(即代碼中的15),那麼我們最好去滿足這樣一個公式:maximumPoolSize >= mTaskCount - corePoolSize,不然就會拋出一個java.util.concurrent.RejectedExecutionException異常。當然,你也可以有一個通用的行為:將maximumPoolSize設定為Integer.MAX_VALUE。
還有一種方式可以補救:
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 200, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
不過目前可能大家對ThreadPoolExecutor的使用可能也不那麼頻繁了。因為Java為我們封裝好了一些更方便的建立方式:
ExecutorService executor1 = Executors.newFixedThreadPool(5); // 建立固定容量大小的緩衝池ExecutorService executor2 = Executors.newSingleThreadExecutor(); // 建立容量為1的緩衝池ExecutorService executor3 = Executors.newCachedThreadPool(); // 建立一個緩衝池,緩衝池容量大小為Integer.MAX_VALUE
下面是上面三種建立方式對應的結果輸出:
建立固定容量大小的緩衝池
正在執行task 0正在執行task 2正在執行task 4正在執行task 1正在執行task 3task 4執行完畢正在執行task 5task 0執行完畢正在執行task 6task 2執行完畢正在執行task 7task 1執行完畢正在執行task 8task 3執行完畢正在執行task 9task 5執行完畢task 7執行完畢正在執行task 10task 6執行完畢正在執行task 11正在執行task 12task 9執行完畢正在執行task 13task 8執行完畢正在執行task 14task 11執行完畢task 12執行完畢task 10執行完畢task 13執行完畢task 14執行完畢
建立容量為1的緩衝池
正在執行task 0task 0執行完畢正在執行task 1task 1執行完畢正在執行task 2task 2執行完畢正在執行task 3task 3執行完畢正在執行task 4task 4執行完畢正在執行task 5task 5執行完畢正在執行task 6task 6執行完畢正在執行task 7task 7執行完畢正在執行task 8task 8執行完畢正在執行task 9task 9執行完畢正在執行task 10task 10執行完畢正在執行task 11task 11執行完畢正在執行task 12task 12執行完畢正在執行task 13task 13執行完畢正在執行task 14task 14執行完畢
建立一個緩衝池,緩衝池容量大小為Integer.MAX_VALUE
正在執行task 0正在執行task 2正在執行task 4正在執行task 6正在執行task 8正在執行task 10正在執行task 12正在執行task 14正在執行task 1正在執行task 3正在執行task 5正在執行task 9正在執行task 7正在執行task 11正在執行task 13task 2執行完畢task 8執行完畢task 6執行完畢task 4執行完畢task 0執行完畢task 10執行完畢task 14執行完畢task 12執行完畢task 1執行完畢task 3執行完畢task 5執行完畢task 7執行完畢task 9執行完畢task 13執行完畢task 11執行完畢
RejectedExecutionException異常:
http://blog.csdn.net/wzy_1988/article/details/38922449
Java並發編程——線程池初步