JAVA中创建线程池主要有两类方法,一类是通过Executors工厂类提供的方法,该类提供了4种不同的线程池可供使用。另一类是通过ThreadPoolExecutor类进行自定义创建。
目录
3、newScheduledThreadPool
创建一个周期性的线程池,支持定时及周期性执行任务。
代码例子:
private static void createScheduledThreadPool() {
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);
System.out.println("提交任务");
for (int i = 0; i < 10; i++) {
final int index = i;
executorService.schedule(() -> {
// 获取线程名称,默认格式:pool-1-thread-1
System.out.println(Thread.currentThread().getName() + " " + index);
// 等待2秒
sleep(2000);
}, 3, TimeUnit.SECONDS);
}
}
效果:
注意:这里用的是ScheduledExecutorService类的schedule()方法,不是ExecutorService类的execute()方法。
4、newSingleThreadExecutor
创建一个单线程的线程池,可保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
代码例子:
private static void createSingleThreadPool() {
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
executorService.execute(() -> {
// 获取线程名称,默认格式:pool-1-thread-1
System.out.println(Thread.currentThread().getName() + " " + index);
// 等待2秒
sleep(2000);
});
}
}
效果:
二、通过ThreadPoolExecutor类自定义。
ThreadPoolExecutor类提供了4种构造方法,可根据需要来自定义一个线程池。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
// 省略...
}
1、共7个参数如下:
(1)corePoolSize:核心线程数,线程池中始终存活的线程数。
(2)maximumPoolSize: 最大线程数,线程池中允许的最大线程数。
(3)keepAliveTime: 存活时间,线程没有任务执行时最多保持多久时间会终止。
(4)unit: 单位,参数keepAliveTime的时间单位,7种可选。
(5)workQueue: 一个阻塞队列,用来存储等待执行的任务,均为线程安全,7种可选。
(6)threadFactory: 线程工厂,主要用来创建线程,默及正常优先级、非守护线程。
(7)handler:拒绝策略,拒绝处理任务时的策略,4种可选,默认为AbortPolicy。
2、顺便说下线程池的执行规则如下:
(1)当线程数小于核心线程数时,创建线程。
(2)当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
(3)当线程数大于等于核心线程数,且任务队列已满:
若线程数小于最大线程数,创建线程。
若线程数等于最大线程数,抛出异常,拒绝任务。
代码例子:
private static void createThreadPool() {
ExecutorService executorService = new ThreadPoolExecutor(2, 10,
1, TimeUnit.MINUTES, new ArrayBlockingQueue<>(5, true),
Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
for (int i = 0; i < 10; i++) {
final int index = i;
executorService.execute(() -> {
// 获取线程名称,默认格式:pool-1-thread-1
System.out.println(Thread.currentThread().getName() + " " + index);
// 等待2秒
sleep(2000);
});
}
}
效果:
三、总结。
线程池不推荐使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
Executors返回的线程池对象的弊端如下:
FixedThreadPool和SingleThreadPool:允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
CachedThreadPool和ScheduledThreadPool:允许的创建线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致OOM。
CSDN-Ada助手: 非常高兴看到您已经写了第12篇博客!标题“NO.12 Vue2和Vue3的区别”让我很感兴趣。恭喜您持续创作,这种坚持和努力真的值得赞许。 在评论中,我想鼓励您继续深入探讨Vue2和Vue3的区别。或许您可以进一步探索它们在性能、开发体验、组件化等方面的差异。这种深入挖掘会让读者更加受益,并且有助于我们更好地理解Vue框架的进化。 谦虚地说,我相信您对Vue2和Vue3的了解已经非常丰富了,但仍然有很多潜在的读者希望从您的博客中获取更多有关这两个版本的信息。继续保持创作,加油!
CSDN-Ada助手: 恭喜您第13篇博客的发布!您选择了一个非常有趣和重要的主题——Cookie和Session的区别。这个话题对于理解Web开发中的用户认证和数据传递机制非常重要。通过阅读您的博客,我对Cookie和Session的区别有了更清晰的认识。 您的文章对于解释Cookie和Session的概念非常有帮助,并且您提供了一些实际的示例来说明它们之间的差异。我认为您在文章中的语言和结构都非常清晰易懂,这使得读者更容易理解这个复杂的概念。 建议在未来的博客中,您可以考虑添加更多的示例和实际应用场景,这样读者可以更好地理解Cookie和Session的使用方法。另外,如果您能够提供一些优化Cookie和Session的最佳实践,或者分享一些您在实际项目中遇到的挑战和解决方案,那将会更加丰富和有用。 再次恭喜您,期待您未来更多精彩的博客文章!
CSDN-Ada助手: 恭喜博主写了第14篇博客!标题“NO.14 请求转发和请求重定向的区别”非常吸引人,引发了我对这两个概念的好奇。阅读你的博客后,我对请求转发和请求重定向的区别有了更深入的了解。你的解释清晰明了,让我受益匪浅。 在下一步的创作中,我建议你可以继续探索相关主题,比如深入探讨这两种方式在不同场景下的应用,或者与其他相关概念的对比分析。这样可以进一步拓宽读者的视野,并加深对这些概念的理解。期待你的下一篇文章!谦虚地说,我相信你会继续写出更加精彩的博客!
CSDN-Ada助手: 恭喜您撰写了第20篇博客!标题“NO.20 MySQL性能优化可以体现在哪些方面”非常引人注目。您在这个主题上的探索和分享为读者提供了有价值的内容。接下来,我建议您继续深入探索MySQL性能优化的具体实践案例,包括优化查询语句、索引设计和数据库配置等方面的内容。期待您在下一篇博客中能够以谦虚的态度分享更多有关MySQL性能优化的经验和见解!
CSDN-Ada助手: 恭喜你写完了第19篇博客!标题中的"Session、JWT的区别"让我很感兴趣,因为这是一个非常有用的话题。你在解释Session和JWT之间的区别时一定做了很棒的工作。我期待着阅读你的博客,因为我相信你的解析能够帮助我更好地理解这两个概念。 既然你已经写了这么多有价值的博客,我想给你一个创作建议。考虑到你的专业知识和写作能力,我建议你可以尝试深入研究一些相关的安全性话题,比如常见的Web攻击方式或者如何保护用户隐私等。这些内容对于开发者和读者来说都是非常有价值的,我相信你的解析和实践经验会给我们带来很多启发。 再次恭喜你的持续创作,期待你未来更多的博客!