前言
近来工作比较繁忙,剩余的一点时间,也用来逛B站了~ 今天才想起博客许久未更新了
今天就复习下线程池的一点小知识,直接上代码,用一个小demo,来了解Executors自带的三个线程池
public class MainTest {
public static void main(String[] args) {
ExecutorService executorService1 = Executors.newCachedThreadPool();//快
ExecutorService executorService2 = Executors.newFixedThreadPool(10);//慢
ExecutorService executorService3 = Executors.newSingleThreadExecutor();//最慢
for (int i = 1; i <= 100; i++) {
executorService1.execute(new MyTask(i));
}
}
}
class MyTask implements Runnable {
int i = 0;
public MyTask(int i) {
this.i = i;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "程序员做第" + i + "个项目");
try {
Thread.sleep(3000L);//业务逻辑 ,只是为了让打印场景更加明显
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用 Executors 自带的三个线程池执行.execute(new MyTask(i)),会得到不同的“结果”
源码说明:
newCachedThreadPool: 从源码中可看出, 核心线程为0, 非核心线程N多个,使用的是SynchronousQueue队列(这个队列很特殊, 例如来个 100个任务,最多只会存1个),而多出的任务,交给线程处理, 且因为核心线程为0 , 所以会直接创建一个 非核心线程来执行,所以demo中,会频繁创建非核心线程来执行任务, demo场景下它速度最快
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
队列的本质是存储,也就是占用内存,所以SynchronousQueue队列OOM概率很小,但是线程开了很多,cpu容易100%
newFixedThreadPool: 核心线程数和非核心线程数由开发者设置 ,队列为 LinkedBlockingQueue(默认容量为 Integer.Max,所以可认为是无界阻塞队列),demo中传入了 10, 所以100个任务中,会先拿10个 给核心线程执行,90个直接放入队列, 每当核心线程执行完会从队列弹出任务给核心线程执行 (相当于非核心线程没啥用,压根轮不到他出场),因为demo中设置了 sleep 3秒,所以打印出来的效果是10个为一组,慢慢的打印. 如果demo中核心线程设置100,其实瞬间就执行完了
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newSingleThreadExecutor: 核心线程数和非核心线程数都为 1, 队列为 LinkedBlockingQueue, 这个线程池是真的很’菜’,100个任务过来,只有1个核心线程在执行,99个放入了队列,demo场景下,效率之低可想而知
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
更多关于线程池基础可看之前的文章 标题9:为什么用线程池?
小结: 线程池的执行效率,取决于你的实际业务场景, 所以不推荐使用Executors自带的创建线程池,而是应该我们根据业务自定义线程池 new ThreadPoolExecutor()。