java线程池

在juc包下有很多多线程相关的工具,其中线程池是比较常用的一个。线程池就是针对线程的一种池化技术。我们知道,线程的创建维护都是要操作系统来完成,是一件耗费资源的事情,频繁创建销毁线程将会占用较多的系统资源,影响应用程序性能。因而,线程共享成为一种需求。

在java中Thread代表线程,ThreadPoolExecutor是基础的线程池类。我们先看一下线程池类ThreadPoolExecutor的构造方法。

new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);

各参数解释

corePoolSize:核心线程数

maximumPoolSize:最大线程数

keepAliveTime:时间值

unit:时间单位

workQueue:缓存队列

threadFactory:线程工厂

handler:拒绝策略


线程池运行机制:

1、刚开始线程池为空,没有任何线程;

2、当有一个任务被提交的时候,如果线程数不大于corePoolSize,则使用线程工厂创建一个线程来处理该任务

3、当线程数已经等于corePoolSize,又有任务被提交的时候,则该任务被放到缓存队列workQueue,等待被调度。

4、当线程数等于corePoolSize且小于maximumPoolSize,缓存队列workQueue也已经满了,再有任务提交的话,则创建一个新线程用于处理该任务。5

5、当线程数等于maximumPoolSize,缓存队列workQueue也是满的,再有任务提交的话执行拒绝策略handler

6、如果任务比较少,线程池中已创建的线程会有空闲。如果线程数大于corePoolSize,且有线程空闲时间超过keepAliveTime和unit指定的时间,则该线程会被销毁,一直到线程数等于corePoolSize。当然也可以设置核心线程空闲回收。


关于拒绝策略

默认有四种,都是实现了RejectedExecutionHandler接口。

public static class CallerRunsPolicy implements RejectedExecutionHandler {

public CallerRunsPolicy() { }

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

if (!e.isShutdown()) {

r.run();

}

}

}

CallerRunsPolicy:由主线程直接调用任务的run方法执行。

public static class AbortPolicy implements RejectedExecutionHandler {

public AbortPolicy() { }

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

throw new RejectedExecutionException("Task " + r.toString() +

" rejected from " +

e.toString());

}

}

AbortPolicy :由主线程抛出异常。

public static class DiscardPolicy implements RejectedExecutionHandler {

public DiscardPolicy() { }

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

}

}

DiscardPolicy :由主线程什么也不做,队列满加不了就加不了了,直接丢弃当前任务了。

public static class DiscardOldestPolicy implements RejectedExecutionHandler {

public DiscardOldestPolicy() { }

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

if (!e.isShutdown()) {

e.getQueue().poll();

e.execute(r);

}

}

}

DiscardOldestPolicy :丢弃缓存队列头部的任务,并将当前任务重新提交。


关于线程工厂

默认使用的是DefaultThreadFactory,其核心方法是newThread,为一个任务Runnable创建一个Thread。

public Thread newThread(Runnable r) {

Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);

if (t.isDaemon())

t.setDaemon(false);

if (t.getPriority() != Thread.NORM_PRIORITY)

t.setPriority(Thread.NORM_PRIORITY);

return t;

}

里面做了很少的变动,跟我们自己new的比起来定制的东西挺少的,我们通常使用默认的线程工厂即可。


关于Executors中的线程池

因为一般是对ThreadPoolExecutor的定制,所以我们只要对ThreadPoolExecutor足够清楚就行。Executors中的线程池在生产上不见得适用。例如固定线程数的线程池,相关代码如下:

public static ExecutorService newFixedThreadPool(int nThreads) {

return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<runnable>());/<runnable>

}

由于缓存队列没有容量限制,在高并发情况下,很容易占用大量内存导致OOM,所以阿里巴巴开发手册明确禁止使用Executors中封装的线程池,要求程序开发者自己new ThreadPoolExecutor。


最后,一个面试中遇到的问题,我也不知道答案:线程池为什么要按顺序“创建达到corePoolSize、任务放缓存队列、创建达到maximumPoolSize”?如果后两步交换一下行不行?为什么这么设计?


谁理解这个设计的请积极回复,感谢。


java线程池



分享到:


相關文章: