线程池工具类给我们提供了一些常见的线程池,这篇来谈一谈SingleThreadExecutor线程池
使用方式
创建方式比较简单,直接使用工具创建就ok,Executors.newSingleThreadExecutor()
源码
/**
* Creates an Executor that uses a single worker thread operating
* off an unbounded queue. (Note however that if this single
* thread terminates due to a failure during execution prior to
* shutdown, a new one will take its place if needed to execute
* subsequent tasks.) Tasks are guaranteed to execute
* sequentially, and no more than one task will be active at any
* given time. Unlike the otherwise equivalent
* {@code newFixedThreadPool(1)} the returned executor is
* guaranteed not to be reconfigurable to use additional threads.
*
* @return the newly created single-threaded Executor
*/
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
剖析
- 从源码中可以看到,核心线程数和最大线程数都是1,当没有空闲的线程时,那么任务将会直接丢入队列中
- 看来看一下使用了LinkedBlockingQueue队列,LinkedBlockingQueue我们都知道他是一个无界队列,也就是说这个队列可以无限制的存储任务。
- 因为核心线程数和最大线程数都是1,所有存活时间在这里没有意义
缺点
因为使用了无界队列,那么任务可以无限制的放入队列中,这样做有OOM的风险。
当运行这段代码的时候最好设置一下 -Xms300m -Xmx300m
codeing
package pres.bik.lean.concurrent;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author yangkaifei
* @version 1.0
* @date 2021/11/28 7:00 下午
*/
public class SingleThreadExecutorLean {
/**
* 线程池
*/
private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor();
public static void main(String[] args) {
while (true) {
EXECUTOR_SERVICE.execute(new Thread(() -> {
System.out.println("任务开始执行");
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}));
}
}
}
运行结果:
任务开始执行
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.util.concurrent.LinkedBlockingQueue.offer(LinkedBlockingQueue.java:416)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1371)
at java.util.concurrent.Executors$DelegatedExecutorService.execute(Executors.java:668)
at pres.bik.lean.concurrent.SingleThreadExecutorLean.main(SingleThreadExecutorLean.java:19)
可以看到刚开始执行了1个任务(因为线程数是1),之后的所有任务都被丢到了这个无界的任务队列中,又因为没有空闲的线程,所有的任务都积压到了队列里,最终会抛OOM