假如我的项目中有一个非常不重要的链路,偶尔需要执行一下。在线程池设计的时候,我想到了线程池的八股文。于是为了尽可能节约资源,于是我把“常驻”的核心线程数配置成了0,这样的线程池能执行任务吗?
任务投递时,有以下几种策略:
大概得流程就是如上了,那corePoolSize == 0 的时候,按照上面的八股文,难道会直接投递进阻塞队列中等待执行吗?如果队列够大,会不会任务一直无法执行(因为队列没满,一直也不会创建“空闲线程”)
靠猜是没有用的,我们实践出真知。 下面我配置了一个线程池,期望投递任务的时候,能够通过“空闲线程”短时间帮忙处理,最终自行销毁掉,不持续占用系统资源。 那这种线程池在执行过程中有可能因为阻塞队列未满,最终任务迟迟没有执行吗?
private static final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
0,
8,
5, TimeUnit.MINUTES,
new LinkedBlockingQueue(512),
new CallerRunsPolicy()
);
这里使用这个线程池打印一个字符串,看看是否能够执行就好了
public static void main(String[] args) {
MonitorThreadPoolConfig.addThreadPoolExecutor(threadPoolExecutor);
threadPoolExecutor.execute(() -> System.out.println("hahahhaha "));
}
通过执行结果可以得知:任务是会被执行的(这里我加了对线程池的定时埋点监控)
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
if (workerCountOf(c)
其实这个问题也不复杂,从粘贴出来的第34行 - 第35行可以看出:当核心线程数 == 0的时候会创建一个新的线程执行当前的任务
既然可以通过corePoolSize == 0的方式来尽可能减少”常驻“线程的资源占用,那有没有别的办法可以达到同样的效果呢?
八股文战神可能会抢答了:ThreadPoolExecutor自1.6开始有一个属性如下,它的作用是支持核心线程超时销毁
/**
* If false (default), core threads stay alive even when idle.
* If true, core threads use keepAliveTime to time out waiting
* for work.
*/
private volatile boolean allowCoreThreadTimeOut;
于是我们可以将线程池配置改成如下再试一下(注意我把超时时间改成了5秒钟):
private static final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
1,
8,
5, TimeUnit.SECONDS,
new LinkedBlockingQueue(512),
new CallerRunsPolicy()
);
public static void main(String[] args) {
MonitorThreadPoolConfig.addThreadPoolExecutor(threadPoolExecutor);
threadPoolExecutor.allowCoreThreadTimeOut(true); //核心线程数可以超时
threadPoolExecutor.execute(() -> System.out.println("hahahhaha "));
}
执行结果如下,符合我们的预期。可以看到任务正常执行、线程池的线程数量初始是0,随后是1,最后自然销毁了,变成了0。
ps:据说JDK1.6之前corePoolSize == 0的话,线程池真的可能会出现投递进阻塞队列后没有线程执行的尴尬。
参与评论
手机查看
返回顶部