每天一篇系列:
強(qiáng)化知識體系,查漏補(bǔ)缺。
歡迎指正,共同學(xué)習(xí)!
如果并發(fā)的線程數(shù)量很多,并且每個線程都是執(zhí)行一個時間很短的任務(wù)就結(jié)束了,這樣頻繁創(chuàng)建線程就會大大降低系統(tǒng)的效率,因?yàn)轭l繁創(chuàng)建線程和銷毀線程需要時間。
線程池可以復(fù)用線程避免頻繁創(chuàng)建和銷毀。
public class MyThread extends Thread {
public String name;
public MyThread(String name) {
// TODO Auto-generated constructor stub
this.name = name;
}
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(Thread.currentThread().getName() + "正在執(zhí)行...." + name);
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorTest {
public static final int NUM_THREADS = 10;
public static List<Thread> threads = Collections
.synchronizedList(new ArrayList<Thread>());
public static void main(String[] args) {
// TODO Auto-generated method stub
// 創(chuàng)建一個可重用固定線程數(shù)的線程池
ExecutorService pool = Executors.newSingleThreadExecutor();
// 創(chuàng)建一個可重用固定線程數(shù)的線程池
// ExecutorService pool = Executors.newFixedThreadPool(4);
// 創(chuàng)建一個可重用固定線程數(shù)的線程池
// ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < NUM_THREADS; i++) {
Thread t = new MyThread(" i am " + i);
threads.add(t);
}
for (int i = 0; i < NUM_THREADS; i++) {
pool.execute(threads.get(i));
}
// 關(guān)閉線程池
pool.shutdown();
}
}
java提供了四種線程池的實(shí)現(xiàn):
-
newSingleThreadExecutor
創(chuàng)建一個單線程的線程池。這個線程池只有一個線程在工作,也就是相當(dāng)于單線程串行執(zhí)行所有任務(wù)。如果這個唯一的線程因?yàn)楫惓=Y(jié)束,那么會有一個新的線程來替代它。此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行。
輸出結(jié)果:
pool-1-thread-1正在執(zhí)行.... i am 0
pool-1-thread-1正在執(zhí)行.... i am 1
pool-1-thread-1正在執(zhí)行.... i am 2
pool-1-thread-1正在執(zhí)行.... i am 3
pool-1-thread-1正在執(zhí)行.... i am 4
pool-1-thread-1正在執(zhí)行.... i am 5
pool-1-thread-1正在執(zhí)行.... i am 6
pool-1-thread-1正在執(zhí)行.... i am 7
pool-1-thread-1正在執(zhí)行.... i am 8
pool-1-thread-1正在執(zhí)行.... i am 9
可以看到線程池里面只有線程1,并且excute()執(zhí)行復(fù)用線程1線程來執(zhí)行新的任務(wù)。
只有一個核心線程,確保所有任務(wù)都在同一線程中按順序完成。因此不需要處理線程同步的問題。
2.newFixedThreadPool
創(chuàng)建固定大小的線程池。每次提交一個任務(wù)就創(chuàng)建一個線程,直到線程達(dá)到線程池的最大大小。線程池的大小一旦達(dá)到最大值就會保持不變,如果某個線程因?yàn)閳?zhí)行異常而結(jié)束,那么線程池會補(bǔ)充一個新線程。
輸出結(jié)果:
pool-1-thread-1正在執(zhí)行.... i am 0
pool-1-thread-1正在執(zhí)行.... i am 4
pool-1-thread-1正在執(zhí)行.... i am 5
pool-1-thread-1正在執(zhí)行.... i am 6
pool-1-thread-1正在執(zhí)行.... i am 7
pool-1-thread-1正在執(zhí)行.... i am 8
pool-1-thread-1正在執(zhí)行.... i am 9
pool-1-thread-2正在執(zhí)行.... i am 1
pool-1-thread-3正在執(zhí)行.... i am 2
pool-1-thread-4正在執(zhí)行.... i am 3
可以看到,最終線程池里面只有四條線程,執(zhí)行是無序的,但是線程還是被復(fù)用了。
FixThreadPool只有核心線程,并且數(shù)量固定的,也不會被回收,所有線程都活動時,因?yàn)殛?duì)列沒有限制大小,新任務(wù)會等待執(zhí)行。由于線程不會回收,F(xiàn)ixThreadPool會更快地響應(yīng)外界請求,這也很容易理解。
3. newCachedThreadPool
創(chuàng)建一個可緩存的線程池。如果線程池的大小超過了處理任務(wù)所需要的線程,
那么就會回收部分空閑(60秒不執(zhí)行任務(wù))的線程,當(dāng)任務(wù)數(shù)增加時,此線程池又可以智能的添加新線程來處理任務(wù)。此線程池不會對線程池大小做限制,線程池大小完全依賴于操作系統(tǒng)(或者說JVM)能夠創(chuàng)建的最大線程大小。CachedThreadPool是有線程超時機(jī)制的,它的超時時間為60秒
輸出結(jié)果:
pool-1-thread-1正在執(zhí)行.... i am 0
pool-1-thread-2正在執(zhí)行.... i am 1
pool-1-thread-3正在執(zhí)行.... i am 2
pool-1-thread-5正在執(zhí)行.... i am 4
pool-1-thread-6正在執(zhí)行.... i am 5
pool-1-thread-7正在執(zhí)行.... i am 6
pool-1-thread-9正在執(zhí)行.... i am 8
pool-1-thread-8正在執(zhí)行.... i am 7
pool-1-thread-10正在執(zhí)行.... i am 9
pool-1-thread-4正在執(zhí)行.... i am 3
可以看到線程池里面一共有10條線程,執(zhí)行是無序的。
CachedThreadPool只有非核心線程,最大線程數(shù)非常大,所有線程都活動時,會為新任務(wù)創(chuàng)建新線程,否則利用空閑線程(60s空閑時間,過了就會被回收,所以線程池中有0個線程的可能)處理任務(wù)。比較適合執(zhí)行大量的耗時較少的任務(wù),這樣才能達(dá)到線程被復(fù)用的效果,最大程度上減少創(chuàng)建和銷毀線程的情況。
4.newScheduledThreadPool
創(chuàng)建一個大小無限的線程池。此線程池支持定時以及周期性執(zhí)行任務(wù)的需求??梢岳斫鉃槟軌蚨〞r的newCachedThreadPool。