当前位置: 首页 > news >正文

线程池总结

一:进程、线程、协程的区别

1.进程是操作系统分配和调度的最小单元,进程有独立的资源空间。
2.线程是CPU调度的最小单元,一个进程可以有多个线程
3.协程是轻量级线程,JDK21之后可以直接创建协程进而减少用户态和内存态的切换。


二:java中创建线程的方式有几种

1.创建Runnable对象使用Thread.start运行线程。
2.创建Callable对象使用Exc.submit运行线程。
3.使用线程池创建对象
4.继承Thread

 

 

三:Future和FutureTask和CompletableFuture的区别

1.Future

1.Future表示一个异步任务的结果,它提供了检查任务是否已完成、以及等待任务完成并获取结果等方法

2.get()方法阻塞获取

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(100), new ThreadPoolExecutor.CallerRunsPolicy());

Future<?> future = threadPoolExecutor.submit(() -> {
//代码逻辑执行
});
future.get();
future.cancel();
future.isCancelled();
future.isDone()

 

2.FutureTask

e2c63892a81719fc02932942aac207bd

 

1.FutureTask实现了RunnableFuture,而RunnableFuture继承了Runnable和Future,所以FutureTask即可获取结果又可被线程执行。
2.创建FutureTask需要实现Runnable或Callable,使用Executor的submit执行Callable的call方法,使用excute执行执行Runnable的run方法,使用Thread.start启动线程。

3.get()方法阻塞获取。

        //FutureTask执行CallableFutureTask callableTask = new FutureTask(new Callable() {@Overridepublic Object call() throws Exception {return "1234";}});//线程执行new Thread(callableTask).start();try {Object o = callableTask.get();System.out.println(o);} catch (Exception e) {e.printStackTrace();}

//FutureTask执行RunnableFutureTask runnableTask = new FutureTask(new Runnable() {@Overridepublic void run() {System.out.println(123);}}, false);//线程执行new Thread(runnableTask).start();}

 

3.CompletableFuture

bde6ddedee2957e26dd2161954853081

1.CompletableFuture是Java 8引入的Future扩展,它提供了更强大的异步编程能力,支持链式调用、组合任务和回调处理。

2.可以通过thenRun() 、thenAccept()、thenApply() 方法将前后任务连接起来,形成前后有依赖的任务链。其中:

  • thenRun(Runnable runnable): 对异步任务的结果进行操作,不能传入参,也没有返回值。
  • thenAccept(Consumer consumer): 对异步任务的结果进行消费,可以传入参,但没有返回值。
  • thenApply(Function function): 对异步任务的结果进行转换,可传入参,返回一个新的CompletableFuture。

3.‌并行聚合‌,同一超时控制

        //带响应结果CompletableFuture<String> supplyAsync = CompletableFuture.supplyAsync(() -> {//执行逻辑return "返回响应结果";}, threadPoolExecutor);//不带响应结果CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {//执行逻辑无需响应
        }, threadPoolExecutor);try {//共同设置超时时间,一个失败全部失败CompletableFuture.allOf(supplyAsync,runAsync).get(500,TimeUnit.MILLISECONDS);//带响应结果String result = supplyAsync.get();//不带响应结果
            runAsync.get();} catch (Exception e) {e.printStackTrace();}

 

 

四:线程池的创建

 

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 5, 60, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(100), new ThreadPoolExecutor.CallerRunsPolicy());

 

五:到底如何设置线程池配置

1.核心线程的设置

1.确认机器配置2C4G、4C8G
2.确认业务类型是:CPU密集型、IO密集型,CPU密集型是基于内存计算较多,比如数据计算、逻辑判断等等,IO密集型是磁盘IO/网络IO,比如调用数据库、Redis、第三方接口等等,这些都有IO操作和等等时间。
CPU密集型核心线程设置一般都是机器核数±1,因为机器型号、性能存在差异具体多少核心线程性能最好需要压测判断。
IO密集型核心线程理论上有公式,但是由于业务的操作不一样,如访问MYSQL、第三方接口耗时不一样,所以无法具体评估,需要根据压测结果进行判断。线程池的配置可以自定义方法或使用第三方插件控制

 

2.最大线程数的设置

1.核心线程已经可以做到最大利用CPU的性能了,最大线程数一般都是等于核心线程数,如果核心线程已经找到最合理的值,最大线程在追加几个线程可能会影响接口性能。

3.最大存活时间

1.一般都是给60S,没有太多要求

4.队列长度

1.判断业务能接受接口延迟时间是多久
2.判断接口的平均耗时是多少
3.延迟时间除于接口耗时乘核心线程数

有界队列:
ArrayBlockingQueue:基于数组实现需要配合固定容量,当队列满时会触发拒绝策略,适合需要控制任务数量的场景
无界队列:
LinkedBlockingQueue:基于链表实现,最大容量是Integer.MAX_VALUE,但有可能造成OOM,适用处理速度慢但是不能拒绝的任务
LinkedBlockingQueue:也可以指定容量
无缓冲队列:
SynchronousQueue‌:不存储任何元素,每个插入操作必须等待对应的删除操作,生产者和消费者线程必须严格同步,适用于高吞吐常见。
优先级队列:
PriorityBlockingQueue‌:通过二叉树实现,确保每次操作返回队列最高/最低的元素,适用于有优先级和资源控制的常见

 

 

5.拒绝策略

1.根据业务重要程度来评估,如果是打印日志的丢就丢了,如果是核心业务一般都是交给调用线程执行

CallerRunsPolicy:将任务交给调用者
AbortPolicy:拒绝任务并排除异常
DiscardPolicy:丢弃任务
DiscardOldestPolicy:丢弃排队时间最长的任务,尝试把自己加进去

2.如果这4种拒绝策略不能满足还可以自己实现RejectedExecutionHandler

   public static class CallerRunsPolicy implements RejectedExecutionHandler {public CallerRunsPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {if (!e.isShutdown()) {r.run();}}}

 

3.线程池的执行原理

aae6bc09d99e2b22dd8df0469a5825ab

 

4.线程池工作线程和普通线程有什么区别

1.线程池工作线程和普通线程本质是没有区别的,如果想用线程只能thread.start()。

2.但是线程池的工作线程封装了一个worker对象,worker对象适配了线程池的逻辑,他实现了Runnable和继承了AQS,为了满足线程池的shutdown和shutdownNow。

//线程执行方法
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();

int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}

//worker对象
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{


final Thread thread;

Runnable firstTask;

volatile long completedTasks;


Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}

 

5.如何在线程池执行任务前后追加逻辑

1.自定义类xx继承ThreadPoolExecutor

2.实现ThreadPoolExecutor中的方法

    protected void beforeExecute(Thread t, Runnable r) { }protected void afterExecute(Runnable r, Throwable t) { }

 

 

 

 
http://www.hskmm.com/?act=detail&tid=27542

相关文章:

  • 合并两个有序链表
  • 深入解析:一款相机是只有桶形畸变 和 枕形畸变的一种,还是两个都有?
  • 数据结构-链表
  • 重组抗体技术:从原理到应用,解锁高效可控的新一代抗体研发
  • P13690 [CEOI 2025] boardgames
  • CSS
  • 关于jinja2的ssti模版注入的学习+过滤
  • WPF Epplus export 10M+ items in excel with multiple sheets batch by batch
  • [EGOI 2023] Guessing Game
  • CF2152G Query Jungle
  • [ROI 2018] Addition without carry
  • [THUPC 2025 决赛] Im Here
  • 解码Linux基础命令
  • 基于 C++ 的高雷诺数湍流直接数值模拟求解器设计与性能优化 - 实践
  • 由等概率(a,b)生成等概率(c,d)
  • AI/LLM应用安全与合规产品(AI安全网关|AI安全围栏|AI应用防火墙) 2025最新推荐
  • 10.8 CSP-S模拟27 改题记录
  • 《可复制的领导力》
  • 经营分析会 - 智慧园区
  • 自动评估问答模型的技术突破
  • Ivanti EPM移动版12.5.0.0身份验证绕过漏洞分析与利用
  • 运行Udacity的MPC控制项目指南(project_10)在Ubuntu 18.04环境下
  • 深入解析:Java 将 PDF 转换为 PDF/A:数字文档归档的基石
  • 入门正当时!MQTT协议轻量简洁,但应用绝不简单
  • 英语阅读
  • CF1832D2 Red-Blue Operations (Hard Version) 模拟赛题目分析
  • 网络流最小割,无向图建图法,求最小割点转换求最小割边
  • 实验1 C语言开发环境使用和数据类型、运算符、表达式
  • 深度学习概述 - -一叶知秋
  • 烧录神器来了!量产工具使用教程,新手也能秒懂