互联网行业前景如何温州网站优化推广方案
设计实现是要求在服务启动时,创建一批常驻线程,从阻塞队列里取元素执行业务逻辑。为此我刚开始使用的代码如下:
使用CommandLineRunner在服务启动时创建好线程
public class ConflictFactory implements CommandLineRunner{private static final int CD_EXECUTOR_THREAD = Runtime.getRuntime().availableProcessors();private static final ThreadPoolExecutor CD_EXECUTOR = new ThreadPoolExecutor(CD_EXECUTOR_THREAD, CD_EXECUTOR_THREAD, 0L,TimeUnit.MILLISECONDS, new SynchronousQueue<>(), new NamedThreadFactory("CD-", false),new ThreadPoolExecutor.AbortPolicy());static {CD_EXECUTOR.prestartAllCoreThreads();}@Overridepublic void run(String... args) throws Exception {for (int i = 0; i < CD_EXECUTOR_THREAD; i++) {CD_EXECUTOR.execute(() -> {while (true) {try {node = singleDomainQueue.take();、、、、、、} catch (Exception e) {、、、、、、}}});}}
}
运行时偶发报错,提示任务被拒绝
创建的任务数量=核心线程数量为什么 任务还会被拒绝呢?
虽然使用了prestartAllCoreThreads()预先创建线程,但是当任务提交时,线程还未全部创建完毕,active threads = 1,还未达到CD_EXECUTOR_THREAD个。由于SynchronousQueue的特性 :
- 不会存储任务,必须由 某个线程立即消费,否则任务会被拒绝。
- 线程的创建、任务提交、任务执行 必须完全同步,否则任务会失败
瞬时过载导致任务被拒绝。
还是老老实实换成了LinkedBlockingQueue,暂存一下任务,等线程逐步创建完成再执行。
private static final ThreadPoolExecutor CD_EXECUTOR = new ThreadPoolExecutor(CD_EXECUTOR_THREAD, CD_EXECUTOR_THREAD, 0L,TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(CD_EXECUTOR_THREAD + 3), new NamedThreadFactory("CD-", false),new ThreadPoolExecutor.AbortPolicy());
SynchronousQueue只适合任务数量<最大线程数量,并且线程已经是就绪状态的场景。高吞吐、低延迟,但适用于短时任务,线程池需要足够的线程数,否则任务会被拒绝