当前位置: 首页 > 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.zskr.cn/news/17827.html

相关文章:

  • 深入解析:一款相机是只有桶形畸变 和 枕形畸变的一种,还是两个都有?
  • WPF Epplus export 10M+ items in excel with multiple sheets batch by batch
  • CF2152G Query Jungle
  • 下好多雨
  • 戴尔电脑开机出现supportassist怎么办_戴尔电脑开机出现supportassist多种解决优秀的方法
  • 项目经理常见面试题7:作为项目经理,你如何协调项目中不同角色(构建、测试、产品)的矛盾?
  • 由等概率(a,b)生成等概率(c,d)
  • 详细介绍:C#练习题——泛型实现单例模式和增删改查
  • 运行Udacity的MPC控制项目指南(project_10)在Ubuntu 18.04环境下
  • 网络流最小割,无向图建图法,求最小割点转换求最小割边
  • 2025/10/9
  • 深度学习概述 - -一叶知秋
  • C#性能优化基础:内存诊断(dump)
  • 2025年企业级LLM内容安全防护指南:鉴冰AI FENCE流式网关技术深度解析
  • 完整教程:FPGA学习笔记——图像处理之亮度调节(Gamma)
  • IObit Uninstaller一款强大的卸载工具!IObit Uninstaller卸载工具,IObit Uninstaller下载安装教程
  • 网络配置不再难:4G/Wi-Fi/以太网/虚拟网卡全指南
  • 一种排查java.lang.OutOfMemoryError: Metaspace的方法
  • MDX Blog Post
  • 本站点即将在2025年改变研究方向和目标
  • 实用指南:12_OkHttp初体验
  • 乒乓球
  • wmctf2025
  • Java基础-Eclipse工具-面向对象(1)
  • Qwen3技术报告
  • 在Ubuntu 22.04系统上安装libimobiledevice的步骤
  • 破解安防整合难题:详解国标GB28181EasyGBS如何实现零插件Web直播
  • leetCod热题100-73、买股票的最佳时期
  • 有限体积法和有限差分法、有限元法的区别。
  • “十五五”战略下,央国企人事系统如何破局增效?T集团数字化转型案例分享