为什么要用线程池:
1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。
一、常用的线程池
FixedThreadPool:返回一个固定数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则会暂存在任务队列中,等到有空闲线程时执行。
Executors.newFixedThreadPool(int):执行长期任务性能好
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
SingleThreadExecutor:只有一个线程的线程池,按顺序执行
Executors.newSingleThreadExecutor():一个一个任务执行
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
CachedThreadPool:线程数量不确定,若有空闲线程,则优先选择,若无空闲线程,则会创建新的线程。线程执行完毕后会返回线程池复用。
Executors.newCachedThreadPool():短期异步小程序或负载较轻的服务器
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
二、线程池的七大参数
使用ThreadPoolExecutor创建线程池更值得推荐
以下是其源码的构造方法,其中包含七个参数:
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.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
- corePoolSize:线程池中常驻核心线程数,即最小可以同时运行的线程数量。
- maximumPoolSize:线程池能够容纳同时执行的最大线程数
- keepAliveTime:多余线程的存活时间,当前线程池数量超过corePoolSize且空闲时间达到keepAliveTime时,多余的空间线程被销毁到剩下corePoolSize。
- unit:keepAliveTime的单位
- workQueue:任务队列的类型
- threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程一般用默认的即可
- handler:拒绝策略。
三、拒绝策略
- 调用者执行(CallerRunsPolicy):任务被线程池拒绝后,任务会被退回到调用者
- 终止执行(AbortPolicy):任务被拒绝时,抛出RejectedExecutionException异常报错
- 丢弃任务(DiscardPolicy):任务被直接丢弃,不会抛异常报错;
- 丢失老任务(DiscardOldestPolicy):把等待队列中最老的任务删除,删除后重新提交当前任务。
四、案例
阿里巴巴开发手册中明确表示:
image.png
所以我们需要通过ThreadPoolExecutor的方式创建线程:
ExecutorService executorService=new ThreadPoolExecutor(10,10,60,TimeUnit.MILLISECONDS,new LinkedBlockingDeque<>(1024),new ThreadPoolExecutor.CallerRunsPolicy());
CountDownLatch countDownLatch=new CountDownLatch(10);
for (int i=0;i<10;i++){
int finalI = i;
executorService.execute(() -> {
System.out.println(finalI);
countDownLatch.countDown();
});
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.shutdown();
System.out.println("Thread shut down");
网友评论