百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

详解Java线程池的使用及工作原理

mhr18 2025-05-14 14:56 4 浏览 0 评论

在日常开发过程中总是以单线程的思维去编码,没有考虑到在多线程状态下的运行状况。由此引发的结果就是请求过多,应用无法响应。为了解决请求过多的问题,又衍生出了线程池的概念。通过“池”的思想,从而合理的处理请求。本文记录了Java中线程池的使用及工作原理,如有错误,欢迎指正。总结了一张Java多线程图谱分享给大家:

什么是线程池?

线程池是一种用于实现计算机程序并发执行的软件设计模式。线程池维护多个线程,等待由调度程序分配任务以并发执行,该模型提高了性能,并避免了由于为短期任务频繁创建和销毁线程而导致的执行延迟。

线程池要解决什么问题?

说到线程池就一定要从线程的生命周期讲起。

从图中可以了解无论任务执行多久,每个线程都要经历从生到死的状态。而使用线程池就是为了避免线程的重复创建,从而节省了线程的New至Runnable, Running至Terminated的时间;同时也会复用线程,最小化的节省系统资源,于此同时提高了响应速度。

线程池的使用

线程池的创建

使用ThreadPoolExecutor并配置7个参数完成线程池的创建

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)

corePoolSize

线程池中核心线程的最大值

maximumPoolSize

线程池中最大线程数

keepAliveTime

非核心线程空闲的存活时间大小

unit

keepAliveTime的单位,常用的有秒、分钟、小时等

workQueue

阻塞队列类型

threadFactory

线程工厂,用于配置线程的名称,是否为守护线程等

handler

线程池的拒绝策略

常用阻塞队列

ArrayBlockingQueue

底层基于数组的实现的有界阻塞队列

LinkedBlockingQueue 底层基于单链表的阻塞队列,可配置容量,不配置容量默认为Integer.MAX_VALUE

线程工厂

在《阿里巴巴Java开发手册》中强制要求指定线程的名称

由于工作是使用hutool比较多,里面也包含对ThreadFactory的封装,可以很方便的指定名称

ThreadFactory threadFactory = ThreadFactoryBuilder.create().setNamePrefix("myThread-").build();

拒绝策略

当线程池内工作线程数大于maximumPoolSize时,线程就不再接受任务,执行对应的拒绝策略;目前支持的拒绝策略有四种:

1.AbortPolicy(默认):丢弃任务并抛出
RejectedExecutionException异常

2.CallerRunsPolicy:由调用者处理

3.DiscardOldestPolicy:丢弃队列中最前面的任务,并重新入队列

4.DiscardPolicy:丢弃任务但不抛出异常

线程池的执行逻辑

// 创建线程工厂
ThreadFactory threadFactory = ThreadFactoryBuilder.create().setNamePrefix("myThread-").build();
// 创建线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100), threadFactory, new ThreadPoolExecutor.AbortPolicy());

execute()方法

// 组合值;保存了线程池的工作状态和工作线程数
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
public void execute(Runnable command) {
     // 任务为空 抛出NPE
        if (command == null)
            throw new NullPointerException();
        // 获取线程池状态
        int c = ctl.get();
        // 如果工作线程数小于核心线程数就创建新线程
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        // 如果线程池处于Running状态,就把任务放在队列尾部
        if (isRunning(c) && workQueue.offer(command)) {
            // 重新检查线程池状态
            int recheck = ctl.get();
            // 如果线程池不是Running状态,就移除刚才添加的任务,并执行拒绝策略
            if (! isRunning(recheck) && remove(command))
                reject(command);
            // 是Running状态,就添加线程
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        // 添加任务失败,执行拒绝策略
        else if (!addWorker(command, false))
            reject(command);
    }
// addWorker()完成线程的创建

执行流程

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

最后

另外还整理成了40多套PDF文档:全套的Java面试宝典手册,“性能调优+微服务架构+并发编程+开源框架+分布式”等七大面试专栏,包含Tomcat、JVM、MySQL、SpringCloud、SpringBoot、Dubbo、并发、Spring、SpringMVC、MyBatis、Zookeeper、Ngnix、Kafka、MQ、Redis、MongoDB、memcached等等。如果你对这个感兴趣,小编可以免费分享。

资料获取方式:关注小编+转发文章+私信【面试题】获取上述资料~

重要的事情说三遍,转发+转发+转发,一定要记得转发哦!!

相关推荐

B站收藏视频失效?mybili 收藏夹备份神器完整部署指南

本内容来源于@什么值得买APP,观点仅代表作者本人|作者:羊刀仙很多B站用户都有过类似经历:自己精心收藏的视频突然“消失”,点开一看不是“已被删除”,就是“因UP主设置不可见”。而B站并不会主动通知...

中间件推荐初始化配置

Redis推荐初始化配置bind0.0.0.0protected-modeyesport6379tcp-backlog511timeout300tcp-keepalive300...

Redis中缓存穿透问题与解决方法

缓存穿透问题概述在Redis作为缓存使用时,缓存穿透是常见问题。正常查询流程是先从Redis缓存获取数据,若有则直接使用;若没有则去数据库查询,查到后存入缓存。但当请求的数据在缓存和数据库中都...

后端开发必看!Redis 哨兵机制如何保障系统高可用?

你是否曾在项目中遇到过Redis主服务器突然宕机,导致整个业务系统出现数据读取异常、响应延迟甚至服务中断的情况?面对这样的突发状况,作为互联网大厂的后端开发人员,如何快速恢复服务、保障系统的高可用...

Redis合集-大Key处理建议

以下是Redis大Key问题的全流程解决方案,涵盖检测、处理、优化及预防策略,结合代码示例和最佳实践:一、大Key的定义与风险1.大Key判定标准数据类型大Key阈值风险场景S...

深入解析跳跃表:Redis里的&quot;老六&quot;数据结构,专治各种不服

大家好,我是你们的码农段子手,今天要给大家讲一个Redis世界里最会"跳科目三"的数据结构——跳跃表(SkipList)。这货表面上是个青铜,实际上是个王者,连红黑树见了都要喊声大哥。...

Redis 中 AOF 持久化技术原理全解析,看完你就懂了!

你在使用Redis的过程中,有没有担心过数据丢失的问题?尤其是在服务器突然宕机、意外断电等情况发生时,那些还没来得及持久化的数据,是不是让你夜不能寐?别担心,Redis的AOF持久化技术就是...

Redis合集-必备的几款运维工具

Redis在应用Redis时,经常会面临的运维工作,包括Redis的运行状态监控,数据迁移,主从集群、切片集群的部署和运维。接下来,从这三个方面,介绍一些工具。先来学习下监控Redis实时...

别再纠结线程池大小 + 线程数量了,没有固定公式的!

我们在百度上能很轻易地搜索到以下线程池设置大小的理论:在一台服务器上我们按照以下设置CPU密集型的程序-核心数+1I/O密集型的程序-核心数*2你不会真的按照这个理论来设置线程池的...

网络编程—IO多路复用详解

假如你想了解IO多路复用,那本文或许可以帮助你本文的最大目的就是想要把select、epoll在执行过程中干了什么叙述出来,所以具体的代码不会涉及,毕竟不同语言的接口有所区别。基础知识IO多路复用涉及...

5分钟学会C/C++多线程编程进程和线程

前言对线程有基本的理解简单的C++面向过程编程能力创造单个简单的线程。创造单个带参数的线程。如何等待线程结束。创造多个线程,并使用互斥量来防止资源抢占。会使用之后,直接跳到“汇总”,复制模板来用就行...

尽情阅读,技术进阶,详解mmap的原理

1.一句话概括mmapmmap的作用,在应用这一层,是让你把文件的某一段,当作内存一样来访问。将文件映射到物理内存,将进程虚拟空间映射到那块内存。这样,进程不仅能像访问内存一样读写文件,多个进程...

C++11多线程知识点总结

一、多线程的基本概念1、进程与线程的区别和联系进程:进程是一个动态的过程,是一个活动的实体。简单来说,一个应用程序的运行就可以被看做是一个进程;线程:是运行中的实际的任务执行者。可以说,进程中包含了多...

微服务高可用的2个关键技巧,你一定用得上

概述上一篇文章讲了一个朋友公司使用SpringCloud架构遇到问题的一个真实案例,虽然不是什么大的技术问题,但如果对一些东西理解的不深刻,还真会犯一些错误。这篇文章我们来聊聊在微服务架构中,到底如...

Java线程间如何共享与传递数据

1、背景在日常SpringBoot应用或者Java应用开发中,使用多线程编程有很多好处,比如可以同时处理多个任务,提高程序的并发性;可以充分利用计算机的多核处理器,使得程序能够更好地利用计算机的资源,...

取消回复欢迎 发表评论: