多線程技術主要解決處理器單元內多個線程執行的問題,它可以顯著減少處理器單元的閒置時間,增加處理器單元的吞吐能力。
線程池主要用來解決線程生命週期開銷問題和資源不足問題。通過對多個任務重用線程,線程創建的開銷就被分攤到了多個任務上了,而且由於在請求到達時線程已經存在,所以消除了線程創建所帶來的延遲。這樣,就可以立即爲請求服務,使應用程序響應更快。另外,通過適當地調整線程池中的線程數目可以防止出現資源不足的情況。
JDK5中提供的Executors工具類可以通過4個靜態方法創建4種線程池,如下所示:
(1)Executors.newCachedThreadPool();
public static ExecutorService newCachedThreadPool(){
return new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.MILLISECONDS,new SynchronousQueue<Runnable>());
}
- 它是一個可以無限擴大的線程池;
- 它比較適合處理執行時間比較小的任務;
- corePoolSize爲0,maximumPoolSize爲無限大,意味着線程數量可以無限大;
- keepAliveTime爲60S,意味着線程空閒時間超過60S就會被殺死;
- 採用SynchronousQueue接收請求任務,這個阻塞隊列沒有存儲空間,這意味着只要有請求到來,就必須要找到一條工作線程處理予以,如果當前沒有空閒的線程,就會再創建一條新的線程。
(2)Executors.newFixedThreadPool ();
public static ExecutorService newFixedThreadPool(int nThreads){
return new ThreadPoolExecutor(nThreads,nThreads,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}
- 它是一種固定大小的線程池;
- corePoolSize和maximunPoolSize都爲用戶設定的線程數量nThreads;
- keepAliveTime爲0,意味着一旦有多餘的空閒線程,就會被立即停止掉;但這裏keepAliveTime無效;
- 阻塞隊列採用了LinkedBlockingQueue,它是一個無界隊列;
- 由於阻塞隊列是一個無界隊列,因此永遠不可能拒絕任務;
- 由於採用了無界隊列,實際線程數量將永遠維持在nThreads,因此maximumPoolSize和keepAliveTime將無效。
(3)Executors.newScheduledThreadPool();
它用來處理延時任務或定時任務。
它接收SchduledFutureTask類型的任務,有兩種提交任務的方式:
①scheduledAtFixedRate
②scheduledWithFixedDelay
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
表示延遲3秒執行。
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS);
表示延遲1秒後每3秒執行一次。
ScheduledExecutorService比Timer更安全,功能更強大。
(4)Executors.newSingleThreadExecutor();
public static ExecutorService newSingleThreadExecutor(){
return new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}
創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
結果依次輸出,相當於順序執行各個任務。
現行大多數GUI程序都是單線程的。
線程池的作用:
減少了創建和銷燬線程的次數,每個工作線程都可以被重複利用,可執行多個任務。根 據系統的環境情況,可以自動或手動設置線程數量,從而達到運行的最佳效果。