一、前言
之前我们获取线程池的时候基本上是通过Executors类去调用所需要的线程池;
但这样或多或少的会出现一些问题。
二、线程池
Executors.newSingleThreadExecutor();
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
如上所调用的单线程线程池:它的keepAliveTime为0,表示不回收线程,它队列所使用的是LinkedBlockingQueue,默认大小为Integer最大值,意味着队列可以存很多的线程,但每个线程都是要占内存空间的,如果任务过多,很有可能会导致内存溢出这一现象发生。那怎么办?
idea都提示你要手动创建线程池了,你再不手动创建那就天理难容了啊!!!
三、自定义线程池
从上面可以看出线程池的实现其实主要是由ThreadPoolExecutor类去实现的。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize:核心线程数
--- 线程池参数
maximumPoolSize:最大线程数
keepAliveTime:空闲线程回收时间间隔
unit:空闲线程回收时间间隔单位
workQueue:提交任务的队列,当线程数量超过核心线程数时,可以将任务提交到任务队列中。比较常用的有:ArrayBlockingQueue; LinkedBlockingQueue; SynchronousQueue;
threadFactory:线程工厂,可以自定义线程的一些属性,比如:名称或者守护线程等
handler:表示当拒绝处理任务时的策略
handler:拒绝策略;默认的拒绝策略为AbortPolicy()
new ThreadPoolExecutor.AbortPolicy():丢弃任务并抛出RejectedExecutionException异常。
new ThreadPoolExecutor.DiscardPolicy():也是丢弃任务,但是不抛出异常。
new ThreadPoolExecutor.DiscardOldestPolicy():丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
new ThreadPoolExecutor.CallerRunsPolicy():由调用线程处理该任务
四、线程池的运行过程
五、自定义线程池例子
private static final AtomicInteger THREAD_NUMBER = new AtomicInteger();
private static final ExecutorService EXECUTOR_SERVICE = new ThreadPoolExecutor(2,4,10, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(1000),(Runnable r)->new Thread(r,"SqlPrintInterceptorThread:"+THREAD_NUMBER.getAndIncrement()),
new ThreadPoolExecutor.DiscardOldestPolicy());
六、源码分析
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
//当前线程数是否小于corePoolSize
if (workerCountOf(c) < corePoolSize) {
//添加新线程,true:corePoolSize作为绑定,false:maximumPoolSize
if (addWorker(command, true))
return;
c = ctl.get();
}
//线程是否处于Running状态,添加任务到队列(队列没满)
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
//从队列里移除任务
if (! isRunning(recheck) && remove(command))
//执行拒绝策略
reject(command);
//当前线程池数量为null
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//如果队列满了,则新增线程,新增失败则执行拒绝策略
else if (!addWorker(command, false))
reject(command);
}
七、线程池到底有多少个线程在运行
在我初学线程的时候,一度认为最大线程数数量就是线程运行的数量,当我深入了解后,发现线程池的顺序是:
1、核心线程数------2、队列------3、最大线程数
于是我及时修改自己的想法:核心线程数才是线程运行的数量,而最大线程数是最多有多少个线程数再执行。