news 2026/4/18 3:25:10

jdk源码解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
jdk源码解析

1. jdk源码

大家可以多看源码,看一下同样的功能,代码是如何构造的;

  • ThreadpoolExector

1.1线程池

我们通常所说的线程池是指Java中的ThreadPoolExecutor,下面将详细说明线程池的参数、实现原理以及如何实现一个简单的线程池。

线程池的参数(以ThreadPoolExecutor为例)

ThreadPoolExecutor有7个核心参数:

  1. corePoolSize(核心线程数):线程池中保持存活的最小线程数,即使它们处于空闲状态。
  2. maximumPoolSize(最大线程数):线程池中允许存在的最大线程数。
  3. keepAliveTime(线程存活时间):当线程数超过核心线程数时,多余的空闲线程在终止前等待新任务的最长时间。
  4. unit(时间单位):keepAliveTime的时间单位。
  5. workQueue(工作队列):用于保存等待执行的任务的阻塞队列。
  6. threadFactory(线程工厂):用于创建新线程的工厂。
  7. handler(拒绝策略):当线程池和工作队列都满了,说明线程池处于饱和状态,必须采取一种策略处理新提交的任务。

线程池的实现原理

线程池的主要工作流程如下:

  1. 提交任务后,线程池首先判断当前线程数是否小于核心线程数(corePoolSize)。如果是,则创建一个新线程来执行任务。
  2. 如果当前线程数已经达到核心线程数,则将任务放入工作队列(workQueue)中。
  3. 如果工作队列已满,且当前线程数小于最大线程数(maximumPoolSize),则创建新的线程来执行任务。
  4. 如果当前线程数已经达到最大线程数,并且工作队列已满,则按照拒绝策略(handler)处理新提交的任务。

线程池中的线程执行完任务后,会从工作队列中获取新的任务来执行。如果超过keepAliveTime仍然没有获取到新任务,并且当前线程数大于核心线程数,则该线程会被终止,直到线程数等于核心线程数。

拒绝策略详解

Java提供了4种内置拒绝策略:

  1. AbortPolicy:直接抛出RejectedExecutionException(默认)

  2. CallerRunsPolicy:由调用者线程执行该任务

  3. DiscardPolicy:直接丢弃任务,不抛异常

  4. DiscardOldestPolicy:丢弃队列中最老的任务,然后重试执行

  5. FixedThreadPool(固定大小线程池)

  6. CachedThreadPool(缓存线程池)

  7. SingleThreadExecutor(单线程线程池)

  8. ScheduledThreadPool(定时任务线程池)

  9. WorkStealingPool(工作窃取线程池,Java 8+)

  10. ForkJoinPool(分治线程池,与WorkStealingPool相关)

下面分别介绍这些线程池的特点和适用场景。

1. FixedThreadPool(固定大小线程池)

  • 创建方法Executors.newFixedThreadPool(int nThreads)
  • 特点:核心线程数和最大线程数相等,即固定大小的线程池。线程池中的线程不会因为任务过多而扩容,也不会因为空闲而收缩。任务队列使用无界队列(LinkedBlockingQueue)。
  • 适用场景:适用于负载较重的服务器,需要限制当前线程数量,以及需要稳定线程数的场景。

2. CachedThreadPool(缓存线程池)

  • 创建方法Executors.newCachedThreadPool()
  • 特点:核心线程数为0,最大线程数为Integer.MAX_VALUE,线程空闲存活时间为60秒。任务队列使用同步队列(SynchronousQueue),该队列不存储元素,每个插入操作必须等待另一个线程的移除操作。因此,如果有空闲线程则复用,如果没有则创建新线程。线程池的线程数可以无限扩大,当线程空闲时会被回收。
  • 适用场景:适用于执行很多短期异步任务,或者负载较轻的服务器。

3. SingleThreadExecutor(单线程线程池)

  • 创建方法Executors.newSingleThreadExecutor()
  • 特点:只有一个线程的线程池,核心线程数和最大线程数均为1。任务队列使用无界队列(LinkedBlockingQueue)。保证所有任务按顺序执行。
  • 适用场景:适用于需要顺序执行任务的场景,并且不需要并发执行。

4. ScheduledThreadPool(定时任务线程池)

  • 创建方法Executors.newScheduledThreadPool(int corePoolSize)
  • 特点:可以执行定时任务和周期性任务。核心线程数由参数指定,最大线程数为Integer.MAX_VALUE,线程空闲存活时间为0,但实际上由于用于调度任务,所以不会回收核心线程。任务队列使用延迟工作队列(DelayedWorkQueue)。
  • 适用场景:适用于需要执行定时任务和周期性任务的场景。

5. WorkStealingPool(工作窃取线程池)

  • 创建方法Executors.newWorkStealingPool(int parallelism), parallelism并行级别,默认为CPU核数。
  • 特点:基于ForkJoinPool实现,使用工作窃取算法,即每个线程维护自己的任务队列,当自己队列中的任务执行完后,可以从其他线程的任务队列中“窃取”任务来执行。这种机制可以减少线程间的竞争,提高吞吐量。
  • 适用场景:适用于任务执行时间不均匀,或者有大量子任务的场景。

6. ForkJoinPool(分治线程池)

  • 创建方法new ForkJoinPool(int parallelism)
  • 特点:与WorkStealingPool类似,也是基于工作窃取算法。ForkJoinPool是WorkStealingPool的底层实现,但WorkStealingPool是ForkJoinPool的封装,调整了一些默认参数。ForkJoinPool适合处理可以递归分解的任务(分治任务)。
  • 适用场景:适用于计算密集型任务,且任务可以分解成更小的子任务。

注意事项

  • FixedThreadPoolSingleThreadExecutor使用无界队列,如果任务提交速度大于处理速度,可能会堆积大量任务,导致内存溢出。
  • CachedThreadPoolScheduledThreadPool的最大线程数很大,如果任务提交过多,可能会创建大量线程,导致资源耗尽。

因此,在实际使用中,通常建议根据业务场景自定义线程池参数,使用ThreadPoolExecutor构造函数来创建,以便更精确地控制线程池的行为。

常见配置建议:

  • CPU密集型:线程数 ≈ CPU核数
  • IO密集型:线程数 ≈ CPU核数 × (1 + 平均等待时间/平均计算时间)
  • 混合型:根据实际情况调整
//中断空闲的线程 private void interruptIdleWorkers(boolean onlyOne){final ReentrantLock mainLock=this.mainLock;//专用锁 mainLock.lock();//添加专用锁 try{for(Worker w:workers){Thread t=w.thread;if(!t.isInterrupted()&&w.tryLock()){try{t.interrupt();//阻塞当前线程}finally{w.unlock();}}if(onlyOne)break;}}finally{mainLock.unlock();//解除专用锁代码}}public booleantryLock(){returnthis.tryAcquire(1);}protected boolean tryAcquire(int unused){if(this.compareAndSetState(0,1)){//cas线程安全 this.setExclusiveOwnerThread(Thread.currentThread());returntrue;}else{returnfalse;}}public voidunlock(){this.release(1);}public final boolean release(int arg){if(tryRelease(arg)){signalNext(head);returntrue;}returnfalse;}protected boolean tryRelease(int unused){setExclusiveOwnerThread(null);setState(0);returntrue;}// setExclusiveOwnerThread(Thread.currentThread());线程非安全,但是由于有cas锁机制是线程安全的;protected boolean tryAcquire(int unused){if(compareAndSetState(0,1)){setExclusiveOwnerThread(Thread.currentThread());returntrue;}returnfalse;}protected boolean tryRelease(int unused){this.setExclusiveOwnerThread((Thread)null);this.setState(0);returntrue;}//若 tryAcquire 和 tryRelease分别两个专项锁,则可能出现线程安全的问题;设计规则上是 若 tryAcquire 和 tryRelease 一块使用 关键因素 ReentrantLock 机制保障 两个方法都在 ReentrantLock 的同步机制控制下 tryAcquire 和 tryRelease 方法的调用都受到同一把锁的保护 互斥访问 ReentrantLock 确保同一时刻只有一个线程能执行临界区代码 无论是获取锁还是释放锁,都是在受保护的上下文中进行 内存可见性 ReentrantLock 的获取和释放操作建立了 happens-before 关系 保证了 setExclusiveOwnerThread 操作的内存可见性 源码方法 private volatile ThreadFactory threadFactory;/** * Sets the thread factory used to create new threads. * * @param threadFactory the new thread factory * @throws NullPointerExceptionifthreadFactory is null * @see#getThreadFactory*/ public void setThreadFactory(ThreadFactory threadFactory){Objects.requireNonNull(threadFactory,"threadFactory");this.threadFactory=threadFactory;//线程安全单独的赋值操作}/** * Initiates an orderlyshutdowninwhichpreviously submitted * tasks are executed, but no new tasks will be accepted. * Invocation has no additional effectifalready shut down. * *<p>This method does notwaitforpreviously submitted tasks to * complete execution. Use{@link#awaitTermination awaitTermination}* todothat. */ public voidshutdown(){//关闭线程池 final ReentrantLock mainLock=this.mainLock;mainLock.lock();try{//如下多个操作(复合操作需要 手动方式枷锁) advanceRunState(SHUTDOWN);interruptIdleWorkers();onShutdown();// hookforScheduledThreadPoolExecutor 钩子函数}finally{mainLock.unlock();}tryTerminate();}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/10 17:22:47

LC.783 | 二叉搜索树节点最小距离 | 树 | 中序遍历有序性

输入&#xff1a; 二叉搜索树的根节点 root。 要求&#xff1a; 计算树中任意两个不同节点值之间的最小差值。 输出&#xff1a; 一个整数&#xff0c;表示最小差值。思路&#xff1a; 这道题如果是一棵普通的二叉树&#xff0c;我们需要把所有节点值存下来&#xff0c;两两比较…

作者头像 李华
网站建设 2026/4/16 0:26:29

Dify工作流并发控制实战指南(并行执行优化全攻略)

第一章&#xff1a;Dify工作流并发控制的核心概念在构建基于 Dify 的自动化工作流时&#xff0c;合理管理并发执行是确保系统稳定性与数据一致性的关键。当多个用户或任务同时触发相同的工作流节点时&#xff0c;若缺乏有效的并发控制机制&#xff0c;可能导致资源竞争、状态错…

作者头像 李华
网站建设 2026/4/14 0:29:14

为什么你的Agent版本总失控?Dify环境下5大陷阱深度剖析

第一章&#xff1a;Agent版本失控的根源解析在分布式系统与自动化运维场景中&#xff0c;Agent作为核心组件承担着数据采集、指令执行和状态上报等关键职责。然而&#xff0c;随着部署规模扩大和迭代频率提升&#xff0c;Agent版本失控问题日益突出&#xff0c;直接影响系统的稳…

作者头像 李华
网站建设 2026/4/13 12:10:41

A29语音模组:100dB消回音黑科技,大音量设备的“降噪救星”

门禁对讲音量拉满就回音&#xff1f;车间广播被机器声盖死&#xff1f;远场呼叫喊破喉咙也听不清&#xff1f;这些音频痛点&#xff0c;A29数字语音处理模组全解决&#xff01;专注声学10年团队研发&#xff0c;100dB超强消回音45dB深度降噪&#xff0c;5米远场拾音稳如“贴耳对…

作者头像 李华
网站建设 2026/4/15 8:16:00

Docker使用案例-部署Python-flask应用

介绍 基于已经有docker基础概念的情况下&#xff0c;可以看我前面的文章Docker使用案例-数据卷启动nginx-CSDN博客 实验环境 操作系统-centsos9.0docker 27.3.1 实验步骤 创建项目目录 mkdir /mywebtouch app.pytouch dockerfile 编写python代码 from http.server impor…

作者头像 李华