程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> J2SE >> J2SE5.0中的線程緩沖 ---- 線程池

J2SE5.0中的線程緩沖 ---- 線程池

編輯:J2SE

一、前言

用Java編寫多線程程序已經是一個非常簡單的事了,不過與其它多線程系統相比,一些高級特性在Java中仍然不具備,然而在J2SE5.0中這一切將會改變。J2SE5.0增加大量的線程相關類使得編寫多線程程序更加容易!

二、線程池-Thread Pools

線程庫的基本思想簡單的講就是,一個線程庫中擁有一定數量的線程,當有任務要執行時,就從線程庫中找一個空閒的線程來執行這個任務,任務執行完後,該線程返回線程庫等待下一個任務;如果線程庫中沒有空閒的線程來執行該任務,這時該任務將要等待直到有一個空閒的線程來執行它。這聽起來有點不爽,那麼我們為什麼還要使用線程庫呢?

三、使用線程庫的三大理由

重用線程能夠獲得性能上的好處。在多線程環境中,創建一個線程要花很高的代價。線程庫使得線程能夠被重用,當有大量任務要執行時,線程庫避免了不斷創建與銷毀線程所帶來的系統開銷,使用得你的程序整體運行效率得到了一定程度的提高。

還有一個很重要的原因就是,線程庫考慮到了較好的程序設計。如果有大量任務要執行,如果不用線程庫,你不得不不重復創建一個線程、管理這個線程的生命同期的代碼。斷重復這些步驟是一件很乏味的工作,因為這與我們的業務邏輯(任務)無關。使用線程庫,這一切將由線程庫代為管理,你只需關注於你的商務邏輯,當要執行一個任務時,你只需簡單的創建一個任務,並把它丟給線程庫去執行就OK。

最後一個也是最為重要的一個:當有大量任務需要同時執行時,線程庫能夠帶來重大的性能提升。這一點看上去與第一點相似,事實上,任何時候活動的線程都比CPU數量多得多,因此線程庫能夠充分利用CPU的時間片,使得程序看去上運行較快且高效。

四、如何使用線程庫

在使用線程庫需要做兩件事:創建任務及建立線程庫本身。

一個任務是一個實現了Runnable或Callable接口的對象。

線程庫則基於Executor接口。

Java.util.concurrent.Executor


Java.util.concurrent.ExecutorService


Java.util.concurrent.ThreadPoolExecutor

package Java.util.concurrent;
public class ThreadPoolExecutor implements ExecutorService ...{
   public ThreadPoolExecutor(int corePoolSize,
                int maximumPoolSize,
                long keepAliveTime,
                TimeUnit unit,
                BlockingQueue<Runnable> workQueue);
   public ThreadPoolExecutor(int corePoolSize,
                int maximumPoolSize,
                long keepAliveTime,
                TimeUnit unit,
                BlockingQueue<Runnable> workQueue,
                ThreadFactory threadFactory);
   public ThreadPoolExecutor(int corePoolSize,
                int maximumPoolSize,
                long keepAliveTime,
                TimeUnit unit,
                BlockingQueue<Runnable> workQueue,
                RejectedExecutionHandler handler);
   public ThreadPoolExecutor(int corePoolSize,
                int maximumPoolSize,
                long keepAliveTime,
                TimeUnit unit,
                BlockingQueue<Runnable> workQueue,
                ThreadFactory threadFactory,
                RejectedExecutionHandler handler);
}

五、兩個重要概念Sizes與Queues

Size

一個線程庫創建後,其的大小在最小值(corePoolSize)與最大值(maximumPoolSize)之間,運行時可根據getPoolSize()確定其當前的大小。

Queue

隊列用於存放等候執行的任務。

下面一步步分析這兩個值在線程庫的工作中是如何運作:

1.  ThreadPoolExecutor tpe = new ThreadPoolExecutor(M, N, TIMEOUT, TimeUnit.MILLISECONDS,
2.      new LinkedBlockingQueue<Runnable>());
3.
4.    Task[] tasks = new Task[nTasks];
5.    for (int i = 0; i < nTasks; i++) {
6.      tasks[i] = new Task(n, "Task " + i);
7.      tpe.execute(tasks[i]);
8.    }
9.    tpe.shutdown();

行1-2構造了一個線程庫,M個core threads和N maximum threads,這時實際上並沒有線程被創建。(可能過prestartAllCoreThreads() 和 prestartCoreThread() 方法分別預先創建)

第7行 一個任務被加入到線程庫,這時下列5種情況之一將會發生:

如果庫中的線程數少於M,線程庫將立即啟動一個新的線程來運行這個任務。即使庫中有空閒的線程,仍然會產生一個新線程直到數量到達M。

如果庫中的線程數在M和N之間,並且只少有一個是空閒線程,那麼任務將由這個空閒線程執行。

如果庫中的線程數在M和N之間,並且沒有空閒線程,這時庫會檢查存在的工作隊列,如果任務能夠放置在隊列中而不被阻塞,那麼任務就會放置在該列隊中,不會有新的線程啟動。

如果庫中的線程數在M和N之間,並且沒有空閒線程,且任務不能無阻塞地加入到隊列中,這時庫會開始一個新線程來運行這個任務。

如果庫中的線程數量已到達N且沒有空閒線程,這時庫將會試著放置新任務到一個隊列。如果該隊列已到達它的最大大小,任務將會被拒絕,添加失敗,否則任務將被接受等待有空閒的線程來運行它。

一個任務執行完成,運行這個任務的線程將去運行隊列中的下一個任務,如果隊列中沒有任務,將會發生下面兩種情況之一:

如果庫中的線程數大於M,線程將等待一個隊列中有新的任務。如果隊列中的新任務沒有超時,該線程將運行這個任務,否則線程將退出以減少庫中的線程數量。超時值是在新構造線程庫時指定的TIMEOUT,如果TIMEOUT為0,不管庫的最小大小(corePoolSize)是多少,線程執行完任務後總是退出。

如果庫中的線程數量等於M或小於M,該線程將不確定地被阻塞以等待一個新的任務被加入到隊列(除非TIMEOUT=0,它將退出),當它有效時就會運行這個新任務。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved