深入Java源码理解线程池原理

本文深入探讨线程池的工作原理,包括线程池的创建、任务分配与处理流程,以及池化技术如何提高资源利用率。同时,文章还介绍了线程池在Java中的具体实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

程序运行,其本质上,是对系统资源(CPU、内存、磁盘、网络等等)的使用。如何高效的使用这些资源是我们编程优化演进的一个方向。今天说的线程池是对CPU的利用的优化手段。

网上有不少介绍如何使用线程池的文章,那我想说点什么呢?我希望查看线程池原理,明白池化技术的基本设计思路。遇到其他相似问题可以解决。

池化技术

何为池化技术,简单点来说,就是提前保存大量的资源,以备不时之需。在资源有限的情况下,该技术可以大大提升资源的利用率,提升性能等。

目前比较典型的池化技术有:
线程池、连接池、内存池、对象池等。

本文主要来介绍一下其中比较简单的线程池的实现原理,希望读者们可以举一反三,通过对线程池的理解,学习并掌握所有的编程中池化技术的底层原理,一通百通。

创建一个线程

在java的并发编程中,线程是十分重要的,在Java中,创建一个线程比较简单:

public class App {
    public static void main(String[] args) throws Exception {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程运行中");
            }
        }).start();
    }
}

我们通过创建一个线程对象,并且实现Runnable接口就可以实现一个简单的线程。可以利用上多核CPU。当一个任务结束,当前线程就结束。

但很多时候,我们不止会执行一个任务。如果每次都是如此的创建线程->执行任务->销毁线程,会造成很大的性能开销的。

那能否一个线程创建后,执行完一个任务后,又去执行另一个任务,而不是销毁。这就是线程池。

这就是池化技术的思想,通过预先创建好多个线程,放在池中,这样可以在需要使用线程的时候直接获取,避免多次重复创建、销毁代理的开销。

线程池的简单使用

以下代码,就是在java中创建线程池:

import java.util.concurrent.*;

public class App {
    public static void main(String[] args) throws Exception {
        ExecutorService executorService = new ThreadPoolExecutor(1, 1,
                60L, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(10));

        executorService.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("abcdefg");
            }
        });

        executorService.shutdown();
    }
}

JDK提供给外部的接口也很简单。直接调用ThreadPoolExecutor构造一个就可以了,也可以通过Executors静态工厂构建,但一般不建议。

可以看到,开发者想要在代码中使用线程池还是比较简单的,这得益于Java给我们封装好了一系列的API。很多时候,我们需要知道这些API后面干了些啥,以便于我们更好的设计与实现我们的代码。

线程池构造函数

通常,一般构造函数会反映出这个工具或这个对象的数据存储结构。
构造函数

如果把线程池比作一个公司。公司会有正式员工处理正常业务,如果工作量大的话,会雇佣外包人员来工作。闲时就可以释放外包人员以减少公司管理开销。一个公司因为成本关系,雇佣的人员始终是有最大数。如果这时候还有任务处理不过来,就走需求池排任务。

  • acc : 获取调用上下文
  • corePoolSize: 核心线程数量,可以类比正式员工数量,常驻线程数量。
  • maximumPoolSize: 最大的线程数量,公司最多雇佣员工数量。常驻+临时线程数量。
  • workQueue:多余任务等待队列,再多的人都处理不过来了,需要等着,在这个地方等。
  • keepAliveTime:非核心线程空闲时间,就是外包人员等了多久,如果还没有活干,解雇了。
  • threadFactory: 创建线程的工厂,在这个地方可以统一处理创建的线程的属性。每个公司对员工的要求不一样,恩,在这里设置员工的属性。
  • handler:线程池拒绝策略,什么意思呢?就是当任务实在是太多,人也不够,需求池也排满了,还有任务咋办?默认是不处理,抛出异常告诉任务提交者,我这忙不过来了。

添加一个任务

源码
核心模块用红框标记了。

  • 第一个红框:判断工作的线程数有没有超过最大核心线程数量,如果没有超过新镇新的worker线程。并且推出。
  • 第二个红框:判断线程池是否在运行,如果在,任务队列是否允许插入,插入成功再次验证线程池是否运行,如果不再运行,移除插入的任务,然后抛出拒绝策略。如果再运行,没有线程了,就启用一个线程。
  • 第三个红框:如果添加非核心线程失败,就直接拒绝了。

这里逻辑稍微有点复杂,画了个流程图仅供参考
添加任务流程.png

接下来,我们看看如何添加一个工作线程的? addWork

添加worker线程

添加work1
这里代码有点长,没关系,也是分块的,总共有5个关键的代码块。

  • 第一个红框:做是否能够添加工作线程条件过滤。
    • 判断线程池状态,如果线程池已经关了,就不提交任务了。
  • 第二个红框:做自旋,更新创建线程数量。
    添加work2
  • 第一个红框:获取线程池主锁。
  • 第二个红框:添加线程到workers中(线程池中)。
  • 第三个红框:启动新建的线程。
    这样就应该清晰很多了。

有人或许会疑问 retry 是什么?这个是java中的goto语法。只能运用在break和continue后面。

接下来,我们看看works是什么。
works
一个hashSet。
到这来就完成了一个任务的提交。当一个线程完成了首次任务的执行,后续如何处理其他的请求的呢?

worker线程处理队列任务

任务的执行

  • 第一个红框:是否是第一次执行任务,或者从队列中可以获取到任务。
  • 第二个红框:获取到任务后,执行任务开始前操作钩子。
  • 第三个红框:执行任务。
  • 第四个红框:执行任务后钩子。

这两个钩子(beforeExecute,afterExecute)允许我们自己继承线程池,做任务执行前后处理。有意思。
到这里,源代码分析到此为止。接下来做一下简单的总结。

总结

  1. 所谓线程池本质是一个hashSet。多余的任务会放在阻塞队列中。
  2. 只有当阻塞队列满了后,才会触发非核心线程的创建。所以非核心线程只是临时过来打杂的。直到空闲了,然后自己关闭了。
  3. 线程池提供了两个钩子(beforeExecute,afterExecute)给我们,我们继承线程池,在执行任务前后做一些事情。
  4. 线程池原理关键技术:锁(lock,cas)、阻塞队列、hashSet(资源池)

线程池原理.png

最后希望对你理解线程池有帮助。

都看到这里了,成神之路上,要不要一起?
微信公众号rudy_tan_home

java源码包实例源码JAVA开发源码50个合集: Ajax框架 ZK.rar Java图书馆管理系统源程序.rar Java图片倒影效果实例源码.rar Java图片翻折,将图像压扁.rar Java坦克大战网络对战版源代码.rar Java声音播放程序源代码.rar JAVA实现CLDC与MIDP底层编程的代码.rar Java实现HTTP连接与浏览,Java源码下载.rar Java实现的FTP连接与数据浏览程序.rar Java实现的放大镜效果附有源文件.rar Java实现的点对点短消息发送协议(smpp)开发包源码.rar Java实现的视频播放程序源码.rar Java实现移动的遮照效果.rar JAVA实现超级玛丽.zip Java实现跟踪鼠标运行坐标的源码.rar Java手机与计算机互发彩信源码.rar Java手机游戏大富翁源代码+注释.rar Java手机短信项目源码.rar Java扫雷源码.rar Java生成自定义控件源代码.rar Java调色板面板源代码.rar Java跳棋(基于SWT).rar Java通讯录手机版源码.rar Java鼠标拖拽功能.rar 乐趣大型购物系统.rar 可实现网上对战和人机对战.rar 基于BS结构的Java可视化工作流定制软件.rar 基于J2ME的Java游戏梦幻炸弹人源程序.rar 基于JAVA的ICQ系统.rar 基于Java的mp3播放器源代码.rar 基于Java的小型人事管理系统,带数据库.rar 基于JAVA的日程提醒簿.rar 基于Java的邮件服务器源程序.rar 基于MVC的Java资源管理器 v2.0.rar 基于smpp协议的Java点对点短信发送源码包.rar 季风进销存管理系统(JSP版).rar 客户管理系统 Alfresco Content Management.rar 家庭多媒体播放器.rar 局域网广播系统java源码.rar 开源Winzip压缩工具Java源码.rar 很不错的Java计算器.rar 很强的Java加密解密算法源码.rar 泡泡堂战车游戏JAVA源码.rar 简单模拟的J2ME潜艇大战源代码.rar 简单的注册与登录功能.rar 类似QQ的聊天软件JAVA源码(附设计文档).rar 进程通信.rar 连接postsql数据库的java代码.rar 附加数据库.rar 雷电游戏JAVA版源程序.rar
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值