Java 线程池使用总结

咱们直接进入正题吧:线程池用得好的话会省事,用得不好的话就会被破坏。

我们先来说说创作。
不要使用执行者。
执法者是作弊的工具。
新的 ThreadPoolExecutor 指令。
参数自己写。
控制自己和理解问题的能力。

只有几个基本参数。
基本主题数量、最大主题数量、等待名单、拒绝政策。
老实说,核心线程计数仅在空闲时才起作用。
最大线程数是可以跑死的线程数。
队列是人们排队做事的过程。
拒绝策略是如果队列满了该怎么办。

等待名单有多种类型。
有限的、无限的、没有任务。
这取决于具体情况。
拒绝策略有四种类型。
炒着吃就行了,自己动手,旧的扔掉,扔掉,别管它。
请勿将其丢弃,否则可能会导致事故。

举个栗子。
例如,我上周做了一个。
两个核心线程,最多四个线程,五个线程在队列中。
主题名称由您决定。
拒绝策略使用CallerRunsPolicy。
简单而原始。

线程池有五种状态。
开始、关闭、停止、安排、终止。
简单来说,就是运行、停止、硬停止、退出,仅此而已。

监控很重要。
SpringBootActuator 非常易于使用。
或者直接使用API​​进行搜索。
例如,当前的线程数、已完成的任务数以及队列的大小。

改进建议。
不要严格要求参数。
因怀孕而异。
设置闹钟。
多线程池由框架管理。

常见问题解答。
惯性是最糟糕的。
如果您自己执行父任务和其他子任务,您将会陷入困境。
解决方案是使用不同的线程池。
任务失败了。
使用 DiscardPolicy 会导致您丢失它。
解决办法:注册,不要使用该策略。

资源耗尽。
无限的排队很容易让人筋疲力尽。
解决方案是使用有限队列并设置拒绝策略。
监控等候名单。

总结。
不要使用执行者。
自行设置参数。
监控很重要。
提前思考问题。

你自己看看。
这是第一。

JDK线程池之ThreadPoolExecutor

嘿嘿,说起ThreadPoolExecutor,这是Java线程池管理领域的老手了。
我参加问答论坛很多年了,看到了很多关于主题池的讨论。
ThreadPoolExecutor 绝对是其中的明星。

首先我们来说说ThreadPoolExecutor的核心参数。
corePoolSize是线程池的基础,决定了线程池中始终存在的线程数量。
我记得之前有一个项目。
为了保证服务稳定性,corePoolSize设置得很高。
导致线程永远不会闲置,资源利用率不高。
maxPoolSize,这是线程池的最大容量。
当任务数量达到一定程度时,线程池根据该值决定是否创建新线程。

keepAliveTime,这个比较有趣,它指定了非核心线程的空闲生存期。
过了这个时间,如果线程不再使用,它​​将被销毁。
之前有一个项目。
由于不设置该参数,会导致线程频繁创建和销毁,影响性能。

workQueue,这是一个存储等待执行的任务的队列。
LinkedBlockingQueue,这是一个无限队列。
如果使用得当的话确实很好,但是如果使用不当可能会导致内存不足(OOM)。
ArrayBlockingQueue,这个东西是一个有限的队列,容量必须自己指定,这样使用起来会比较安全。

threadFactory,它可以创建新线程并设置线程名称、优先级等handler,这就是deny策略。
当任务太多,线程池和队列都满了的时候,这个策略就有用了。

工作原理,简单来说:任务提交到线程池。
如果当前线程数小于 corePoolSize 则创建新线程;如果达到corePoolSize,任务进入WorkQueue并等待;如果WorkQueue已满并且线程数小于MaximumPoolSize则继续创建新线程;如果全部满了,就会触发拒绝策略。

我以前见过的一个用法示例是:
java 执行器ExecutorService = new ThreadPoolExecutor( 5 , // 核心池大小 1 0, //最大池大小 6 0, // 保持活动时间 时间单位.秒, 新的 LinkedBlockingQueue(1 00), Executors.defaultThreadFactory(), 新的 ThreadPoolExecutor.AbortPolicy() );
作为最佳实践,我通常建议避免使用 Executor 工厂方法,例如 newFixedThreadPool 和 newCachedThreadPool。
这些默认配置可能会导致资源耗尽。
适当设置队列大小、监视线程池状态并正常关闭线程池非常重要。

注意,我要提醒大家,避免线程泄漏,保证任务能够正常完成;为避免死锁风险,任务执行过程中不要向同一个线程池提交新任务;根据业务需求自动调整线程池参数。

总之,ThreadPoolExecutor还可以改进如果使用得当,它可以显着提高系统性能,但如果使用不当,它可能会成为性能瓶颈。
只有根据实际情况配置合理的参数,才能最大限度地发挥其作用。

为什么要使用线程池?线程池的使用原理是什么?

直接给出结论。

线程池提高了性能。
重复使用电线。
控制竞争。
任务队列管理。

频繁创建和销毁线程会消耗资源。
内存溢出的风险。
反应慢。
管理复杂。

基本结构:线程集合+阻塞队列。
线程集合:Worker对象。
阻塞队列:任务正在等待。

任务调度:提交->重用->队列->拒绝。
线程复用:执行空闲线程。
超时回收:keepAliveTime。

参数: corePoolSize:核心线程数。
队列容量:队列容量。
maxPoolSize:最大线程数。
keepAliveTime:空闲回收时间。
allowedCoreThreadTimeout:主线程超时。
rejectedExecutionHandler:拒绝策略。

执行者: 固定线程池:固定大小。
CachedThreadPool:动态调整。
SingleThreadExecutor:单线程。
ScheduledThreadPool:计划任务。

示例: ExecutorService es = Executors.newCachedThreadPool(); es.提交(任务); es.shutdown();
线程池修复了该问题。
配置设置以优化性能。

创建线程推荐使用哪些方法

兄弟,你的问题有点深奥,不过我刚入行的时候就是这么想的,所以我们就来说说这个吧。

我记得那一年在公司接过一个项目。
项目很大,任务繁重,所以我不得不使用多线程来加快速度。
当时我刚刚开始学习Java,所以我选择了最简单的创建线程的方式,直接继承Thread类,然后写一个run方法。
结果就出现了问题。
这个类已经有父类了,继承Thread类会比较困难。
我当时就傻眼了,这怎么行?
然后我在网上查了资料,嘿,我发现了Runnable接口。
这个东西不错,很灵活,可以和其他类一起使用,不用担心继承问题。
我按照教程定义了一个类来实现Runnable接口,然后重写了run方法,将任务代码写入其中。
最后,我将此类的实例转换为 Thread 并创建了线程。
感觉就像解锁了一项新技能。

后来项目进行到一半的时候,需求发生了变化,需要线程执行完毕后返回结果。
当我看到它时,Runnable接口不起作用。
我必须找到一个能够带来成果的方法。
当时我学习了Callable接口,它和Runnable类似但是可以返回值并抛出异常。
我写了一个实现了Callable接口的类,然后在call方法中写了计算逻辑,最后用FutureTask对其进行了包装,然后用FutureTask创建了一个线程。
结果一运行,不仅返回了结果,还处理了异常,非常棒。

后来项目越来越大,线程需求也随之增加。
那时我已经不满足于一个一个地创建线程,我必须分组管理它们。
一开始想用Executors来创建线程池,但是发现那个东西的设置不够灵活,容易出问题。
我改变了方法,使用ThreadPoolExecutor创建线程池。
自己设置核心线程数、最大线程数、空闲时间等参数,更容易控制。

总之,创建线程、实现Runnable接口、实现Callable接口、使用ThreadPoolExecutor创建线程池都是非常方便的方法。
你根据自己的需求来选择,各有各的优点。
我就是这样一步一步走过来的。
现在回想起来,觉得挺有趣的。
哈哈,废话不多说,你在那边过得怎么样?有没有具体的场景?让我详细告诉你。