手動(dòng)創(chuàng)建線程
平時(shí)開發(fā)中經(jīng)常會(huì)碰到需要用異步方式來(lái)實(shí)現(xiàn)某個(gè)需求幅虑,這時(shí)首先會(huì)想到這種寫法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("to do something");
}
}).start();
或者用lambda簡(jiǎn)寫
new Thread(()-> System.out.println("to do something")).start();
雖然這種寫法可以實(shí)現(xiàn)需求,但是我們最好不要這樣寫同规,因?yàn)檫@種是不可控的盯孙。復(fù)雜的系統(tǒng)里,如果有很多這種寫法宫患,就會(huì)導(dǎo)致明明可以幾個(gè)線程就能完成的任務(wù),最后創(chuàng)建了幾十個(gè)線程这弧,導(dǎo)致線程過(guò)度切換娃闲,降低系統(tǒng)性能。
因此當(dāng)我們需要異步處理的時(shí)候匾浪,應(yīng)該使用線程池皇帮。
線程池
第一種 使用Executors創(chuàng)建
Executors提供了四種創(chuàng)建線程池的方法
- newSingleThreadExecutor 創(chuàng)建只有一個(gè)線程的線程池,這個(gè)線程池可以在線程死后(或發(fā)生異常時(shí))重新啟動(dòng)一個(gè)線程來(lái)替代原來(lái)的線程繼續(xù)執(zhí)行下去蛋辈!
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Worker());
executorService.execute(new Worker());
executorService.shutdown();
}
static class Worker implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":working");
}
}
結(jié)果
pool-1-thread-1:working
pool-1-thread-1:working
- newCachedThreadPool 創(chuàng)建一個(gè)可緩存線程池
- newFixedThreadPool 創(chuàng)建一個(gè)定長(zhǎng)線程池
- newScheduledThreadPool 創(chuàng)建一個(gè)線程池属拾,它可安排在給定延遲后運(yùn)行命令或者定期地執(zhí)行。
不推薦使用Executors創(chuàng)建線程池
其實(shí)通過(guò)Executors創(chuàng)建的四種線程池方法冷溶,底層都是通過(guò)創(chuàng)建ThreadPoolExecutor來(lái)實(shí)現(xiàn)的渐白,這四種方法只是為我們封裝了創(chuàng)建的細(xì)節(jié)。但是我們平時(shí)開發(fā)中最好要知道逞频,核心線程數(shù)多少纯衍,緩存隊(duì)列大小等等這些重要的參數(shù),這樣以后出現(xiàn)bug不至于無(wú)從下手苗胀。
第二種 使用ThreadPoolExecutor創(chuàng)建
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
- corePoolSize 核心線程數(shù)
- maximumPoolSize 最大線程數(shù)
- keepAliveTime 當(dāng)線程數(shù)大于核心線程數(shù)時(shí)襟诸,空余線程等待新任務(wù)的最長(zhǎng)時(shí)間
- unit 時(shí)間單位
- workQueue 等待隊(duì)列
- threadFactory 線程工廠
- handler 當(dāng)線程大于最大線程數(shù)時(shí)采用的拒絕策略
各個(gè)參數(shù)如下圖所示
我們?cè)趧?chuàng)建的時(shí)候也可以采用ThreadPoolExecutor缺省的構(gòu)造方法瓦堵,其中一些參數(shù)使用默認(rèn)即可。
public static void main(String[] args) {
ThreadFactory threadFactory = new ThreadNameFactory();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10),threadFactory);
threadPoolExecutor.execute(new Worker());
threadPoolExecutor.execute(new Worker());
threadPoolExecutor.shutdown();
}
static class ThreadNameFactory implements ThreadFactory {
private final AtomicInteger threadNumber = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, threadNumber.getAndIncrement()+"號(hào)員工");
}
}
static class Worker implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":working");
}
}
結(jié)果
1號(hào)員工:working
2號(hào)員工:working
上面例子中我們?cè)O(shè)置了核心線程數(shù)是5歌亲,最大線程數(shù)是10菇用,等待時(shí)間是5s,等待隊(duì)列采用的是ArrayBlockingQueue应结,線程工廠使用自定義的刨疼,只是自定義了線程名稱。
總結(jié)
平時(shí)開發(fā)中鹅龄,不論什么時(shí)候都最好不要手動(dòng)創(chuàng)建線程執(zhí)行異步任務(wù),應(yīng)該使用線程池來(lái)處理亭畜,有利于線程可控和復(fù)用扮休,提升系統(tǒng)性能,線程池采用ThreadPoolExecutor創(chuàng)建拴鸵。