new Thread 的弊端
首先看一段代碼:
public class ThreadTest {
? ? public static void main(String[] args) {
? ? ? ? while (true) {
? ? ? ? ? ? new Thread(new Runnable() {
? ? ? ? ? ? ? ? @Override? ? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? ? System.out.println(Thread.currentThread());
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }).start();
? ? ? ? }
? ? }
}
Thread[Thread-0,5,main]
Thread[Thread-4,5,main]
Thread[Thread-3,5,main]
Thread[Thread-6,5,main]
Thread[Thread-7,5,main]
先說一下此處的打印忱详,第一個參數(shù)是當(dāng)前線程名稱廊遍,由于線程之間是異步執(zhí)行搁吓,有的還沒創(chuàng)建好饰潜,有的后來居上就執(zhí)行完了寓免,導(dǎo)致打印線程的名稱會這樣呈驶,第二個參數(shù)是優(yōu)先級捂掰,默認都是5羡鸥,第三個參數(shù)是線程組名稱蜈块。
如果不停止程序鉴腻,這段代碼會不斷創(chuàng)建和銷毀線程,直到死機或者OOM百揭,更尷尬的是此處的線程爽哎,還無法主動去中斷。
上述的線程啟動方式在日常開發(fā)中經(jīng)称饕唬看到的课锌,但是從性能和優(yōu)化的角度來說,問題還真不小祈秕。
每次都新建渺贤,性能較差(這個在線程池原理中有詳細講解)雏胃。
線程缺乏統(tǒng)一管理,可能無限制的創(chuàng)建線程志鞍,互相競爭瞭亮,會帶來一些不必要的麻煩。
可控性太差固棚,比如定時定期執(zhí)行统翩,比如線程中斷機制。
線程池的優(yōu)點
Java提供了四大線程池玻孟,主要針對new Thread的弊端講述優(yōu)點:
降低資源消耗唆缴,不需要每次都是新建和銷毀鳍征,性能得到了提高黍翎。
統(tǒng)一管理,可有效控制最大并發(fā)量艳丛,提高系統(tǒng)資源的使用率匣掸,同時避免過多資源競爭,避免堵塞氮双。
可控性很好碰酝,可以定期定時執(zhí)行、線程中斷機制等戴差。
newCachedThreadPool
newCachedThreadPool:創(chuàng)建帶有緩存的線程池送爸。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadTest {
? ? public static void main(String[] args) {
? ? ? ? test();
? ? }
? ? private static void test(){
? ? ? ? ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
? ? ? ? for (int i = 0; i < 100; i++) {
? ? ? ? ? ? cachedThreadPool.execute(new Runnable() {
? ? ? ? ? ? ? ? @Override? ? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? ? System.out.println(Thread.currentThread());
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? }
? ? }
}
Thread[pool-1-thread-2,5,main]
Thread[pool-1-thread-4,5,main]
Thread[pool-1-thread-3,5,main]
Thread[pool-1-thread-6,5,main]
由此可見,上述線程在新建的同時暖释,還有部分線程被回收后再利用袭厂,剛剛做了下測試,在每次打印之前加了2ms的延遲球匕,打印的都是“Thread[pool-1-thread-1,5,main]”纹磺。
線程池為無限大(其實是Interger. MAX_VALUE),當(dāng)執(zhí)行第二個任務(wù)時第一個任務(wù)已經(jīng)完成亮曹,會復(fù)用執(zhí)行第一個任務(wù)的線程橄杨,而不用每次新建線程,如果線程池長度超過處理需要照卦,可靈活回收空閑線程式矫,若無可回收,則新建線程役耕。
newFixedThreadPool
newFixedThreadPool:創(chuàng)建一個定長線程池衷佃,可控制線程最大并發(fā)數(shù),超出的線程會在隊列中等待蹄葱。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadTest {
? ? public static void main(String[] args) {
? ? ? ? test();
? ? }
? ? private static void test(){
? ? ? ? ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
? ? ? ? for (int i = 0; i < 100; i++) {
? ? ? ? ? ? fixedThreadPool.execute(new Runnable() {
? ? ? ? ? ? ? ? @Override? ? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? ? System.out.println(Thread.currentThread());
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? }
? ? }
}
Thread[pool-1-thread-2,5,main]
Thread[pool-1-thread-3,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-3,5,main]
Thread[pool-1-thread-3,5,main]
此處配置最大的線程長度是3氏义,由打印可看出锄列,此處始終在三個線程中執(zhí)行。
newScheduledThreadPool
newScheduledThreadPool:支持定時和周期性執(zhí)行的線程池惯悠。
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadTest {
? ? public static void main(String[] args) {
? ? ? ? test();
? ? }
? ? private static void test(){
? ? ? ? ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
? ? ? ? /**
? ? ? ? * 延遲3秒執(zhí)行
? ? ? ? */? ? ? ? scheduledThreadPool.schedule(new Runnable() {
? ? ? ? ? ? @Override? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? System.out.println(Thread.currentThread());
? ? ? ? ? ? }
? ? ? ? }, 3000, TimeUnit.MILLISECONDS);
? ? ? ? /**
? ? ? ? * 延遲1秒后每3秒執(zhí)行一次
? ? ? ? */? ? ? ? scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
? ? ? ? ? ? @Override? ? ? ? ? ?
????????????public void run() {
? ? ? ? ? ? ? ? System.out.println(Thread.currentThread());
? ? ? ? ? ? }
? ? ? ? }, 1, 3000, TimeUnit.MILLISECONDS);
? ? }
}
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-1,5,main]
Thread[pool-1-thread-2,5,main]
Thread[pool-1-thread-1,5,main].
此方法無論任務(wù)執(zhí)行時間長短邻邮,都是當(dāng)?shù)谝粋€任務(wù)執(zhí)行完成之后,延遲指定時間再開始執(zhí)行第二個任務(wù)克婶。
在日常開發(fā)中筒严,newScheduledThreadPool可以作為timer的替代品,對比timer情萤,newScheduledThreadPool更安全更強大鸭蛙。
newSingleThreadExecutor
newSingleThreadExecutor:從名稱上便可以看出,此線程池是一個單線程化的線程池筋岛,它只會用唯一的工作線程來執(zhí)行任務(wù)娶视,保證所有任務(wù)按照指定順序。如果這個線程異常結(jié)束睁宰,會有另一個取代它肪获,保證順序執(zhí)行(我覺得這點是它的特色)。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadTest {
? ? public static void main(String[] args) {
? ? ? ? test();
? ? }
? ? private static void test(){
? ? ? ? ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
? ? ? ? for (int i = 0; i < 100; i++) {
? ? ? ? ? ? singleThreadExecutor.execute(new Runnable() {
? ? ? ? ? ? ? ? @Override? ? ? ? ? ? ? ? public void run() {
? ? ? ? ? ? ? ? ? ? System.out.println(Thread.currentThread());
? ? ? ? ? ? ? ? }
? ? ? ? ? ? });
? ? ? ? }
? ? }
}
得到的結(jié)果會一直是“Thread[pool-1-thread-1,5,main]”柒傻。
總結(jié):對于任務(wù)量少或者只有一個任務(wù)的情況下孝赫,此時使用線程池顯得高射炮打蚊子了,但是對于任務(wù)量多红符,單個任務(wù)處理的時間比較短的情況下青柄,你會對線程池有不一樣的體會和好感。