java中提供Executors类来创建一些固定模板参数的线程池,如下图(newWorkStealingPool
除外,这个是创建ForkJoinPool的,这里忽略):
拿newFixedThreadPool
方法创建线程池为例,newFixedThreadPool
是创建一个指定线程数的线程池,所以就好奇创建完成之后,是否可以改变他的线程池配置,比如调大核心线程数。于是就查看了一下源码,此方法中,核心线程数和最大线程数都是形参中传入的大小,keepAlive时间为0,返回的对象是ThreadPoolExecutor
类,ThreadPoolExecutor
提供了一系列的修改线程池配置的方法。也就是说通过这种方式创建线程池对象的核心线程数等参数动态调整是可行的。
在下面的代码中,创建了一个线程数量为2的固定线程池对象,然后改变其核心线程池大小,添加9个任务,最后输出,发现核心线程数参数确实被改变了。
public void testFixed() {
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
executorService.setCorePoolSize(3);
executorService.setMaximumPoolSize(5);
executorService.execute(() -> ThreadUtil.sleep(100_000));
executorService.execute(() -> ThreadUtil.sleep(100_000));
executorService.execute(() -> ThreadUtil.sleep(100_000));
executorService.execute(() -> ThreadUtil.sleep(100_000));
executorService.execute(() -> ThreadUtil.sleep(100_000));
executorService.execute(() -> ThreadUtil.sleep(100_000));
executorService.execute(() -> ThreadUtil.sleep(100_000));
executorService.execute(() -> ThreadUtil.sleep(100_000));
executorService.execute(() -> ThreadUtil.sleep(100_000));
ThreadUtil.sleep(2_000);
System.out.println(executorService.getCorePoolSize()); // 3
System.out.println(executorService.getMaximumPoolSize()); // 5
System.out.println(executorService.getActiveCount()); // 3 活动的线程大小为3是因为队列还没有满,所以不会去新建新的线程(<=最大线程数)
System.out.println(executorService.getQueue().size()); // 6
}
newCachedThreadPool
返回值实际上也是一个ThreadPoolExecutor
对象,所以也可以在创建之后动态调整,但其设置的最大线程数量是Integer的最大值。需要注意的一点是,newCachedThreadPool
创建的线程池使用的是SynchronousQueue队列,这种一种同步队列,不存放元素,插入和移除元素是配对的。因此会导致一个问题,也就是当我们将最大线程数调小,当任务量超过了这个最大线程数的时候,就会发现异常,提示说任务被拒绝,因为每个任务都需要一个线程
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newCachedThreadPool();
executorService.setCorePoolSize(20);
executorService.setMaximumPoolSize(50);
executorService.execute(() -> ThreadUtil.sleep(100_000));
executorService.execute(() -> ThreadUtil.sleep(100_000));
executorService.execute(() -> ThreadUtil.sleep(100_000));
executorService.execute(() -> ThreadUtil.sleep(100_000));
executorService.execute(() -> ThreadUtil.sleep(100_000));
executorService.execute(() -> ThreadUtil.sleep(100_000));
executorService.execute(() -> ThreadUtil.sleep(100_000));
executorService.execute(() -> ThreadUtil.sleep(100_000));
executorService.execute(() -> ThreadUtil.sleep(100_000));
ThreadUtil.sleep(2_000);
System.out.println(executorService.getCorePoolSize()); // 20
System.out.println(executorService.getMaximumPoolSize()); // 50
System.out.println(executorService.getActiveCount()); // 9
System.out.println(executorService.getQueue().size()); // 0
将最大线程调整到6,核心调整为5,运行程序,报错
newScheduledThreadPool
方法返回的是一个ScheduledThreadPoolExecutor
对象ScheduledThreadPoolExecutor
类是ThreadPoolExecutor
子类,所以也允许调整。
newSingleThreadExecutor
方法返回的是一个包装类,并没有提供设置线程池参数的方法。
无法强转成ThreadPoolExecutor
类型,强转的话,会发生转换异常
(ThreadPoolExecutor) Executors.newSingleThreadExecutor();