Java 线程池实现的原理

Java 线程池实现原理解析 本文花了大量的篇幅来详细分析了Java线程池ThreadPoolExecutor的执行过程,希望大家能理解处理和调度任务的过程。由于时间和篇幅的原因,我只介绍了Running状态下线程池的运行过程,至于其他的状态我想要比Running状态要容易一些,这些状态的执行过程就留给有兴趣深入研究的小伙伴去分析了哈。线程池是Java多线程并发的核心,希望本篇文章能让你对它有清晰的认识。 阅读详情

在开始介绍线程池的原理之前,我想问一下各位在使用线程的时候,有没有想过为什么一个thread只能start()一次呢?

调用两次start()??

如下代码。

public class Test {

    public static class MyRunnable implements Runnable{
        @Override
        public void run() {
            try {
                System.out.println("start run");
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] agr) throws Exception{
        Thread thread = new Thread(new MyRunnable());
        thread.start();
        //保证了上面的运行完毕
        Thread.sleep(1000);
        thread.start();
    }
}

运行的时候报错:“java.lang.IllegalThreadStateException”

我就在想一个thread只能运行一次,想要复用也做不到,这也太浪费了吧。为什么当初设计Thread的时候,不考虑成:start运行完毕后,可以再次运行呢。

我想是因为,一个线程在无论在运行还是被阻塞都是有一个状态去表示的,如NEW 表示的是,至今尚未启动的线程的状态。RUNNABLE,可运行线程的线程状态。

如果你希望在一个线程在完成任务的时候,再次变成可以运行的状态NEW,那么这个NEW究竟是还没运行的第一次NEW,还是已经运行一次重新开始的NEW呢,说不清。一个完整的生命周期,如果能循环使用,那状态的标识就会失去意义了。

如何使线程复用?

说是复用,但我觉得用“一直用”更合适。假设这里有两个线程,thread1执行唱歌代码,thread2执行跳舞代码。那一般的做法就是开启两个线程去完成即可。

那现在如果有100个人唱歌,100个人跳舞,我们知道线程占用的资源是非常耗cpu的,并且线程的上下文切换也是很耗时的,这时候如果开启200个线程,对cpu的压力可想而知。所以我们需要想一个新的解决方法。

如果我只使用5个线程,这5个线程它一直在运行,就像这样:

public void run(){
     while (true) {
        dothing(); 
    }          
}

在dothing里面,5个线程去一个任务队列中获取这200个任务,然后执行了不就好了嘛!不错,这就是线程池的核心思想了。

这里写图片描述

那么现在需要解决的存放任务的队列,因为是多线程,所以要考虑到安全问题。我这里的实现是阻塞队列ArrayBlockingQueue,里面放着一个个任务。

ArrayBlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(100);

再来看看我们五个工人是怎么工作的:

public class WorkerThread extends Thread{
        @Override
        public void run(){
            try {
                while (true) {//一直跑!!!
                    /**去任务列表拿任务,如果拿到的是null,就休息5秒再去拿*/
                    Runnable runnable = workQueue.poll();
                    if(runnable==null){
                        System.out.println("等待任务中。。。");
                        Thread.sleep(5000);
                    }else{
                        /**执行任务,需要注意的是我用的是run,而不是start两者的区别不再多说*/
                        runnable.run();
                        /**执行完任务,随机休息几秒*/
                        Random random = new Random();
                        Thread.sleep(random.nextInt(5)*1000);
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

完整的代码:

import java.util.Random;
import java.util.Vector;
import java.util.concurrent.ArrayBlockingQueue;

/**
 * Created by JinTX on 2017/10/31.
 */
public class MyThreadPool{

    ArrayBlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(100);

    public MyThreadPool(int count){
        for(int i=0 ;i<count ;i++){
            WorkerThread workerThread = new WorkerThread();
            workerThread.start();
        }
    }

    public class WorkerThread extends Thread{
        @Override
        public void run(){
            try {
                while (true) {
                    /**去任务列表拿任务,如果拿到的是null,就休息5秒再去拿*/
                    Runnable runnable = workQueue.poll();
                    if(runnable==null){
                        System.out.println("等待任务中。。。");
                        Thread.sleep(5000);
                    }else{
                        /**执行任务,需要注意的是我用的是run,而不是start两者的区别不在多说*/
                        runnable.run();
                        /**执行完任务,随机休息几秒*/
                        Random random = new Random();
                        Thread.sleep(random.nextInt(5)*1000);
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    /**生成消息的*/
    public static class MissionRunnable implements Runnable{

        public String job;

        public MissionRunnable(String job){
            this.job = job;
        }
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+""+job);
        }
    }

    public static void main(String[] args) throws Exception{

        MyThreadPool myThreadPool = new MyThreadPool(5);
        for(int i=1 ; i<= 20;i++) {
            MissionRunnable missionRunnable = new MissionRunnable(getJob(i));
            myThreadPool.workQueue.put(missionRunnable);
        }
    }

    public static String getJob(int index){
        if(index%5==0) return "睡觉";
        if(index%5==1) return "唱歌";
        if(index%5==2) return "跳舞";
        if(index%5==3) return "写字";
        if(index%5==4) return "做家务";
        return null;
    }
}

执行的结果:
这里写图片描述

使用线程池的好处

1.减少在创建和销毁线程上所花的时间以及系统资源的开销

2.如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存

NVIDIA Orin AGX开发环境搭建避坑指南:从Ubuntu 22.04到ROS2完整配置流程 本文详细介绍了NVIDIA Orin AGX开发环境搭建的全流程,从Ubuntu 22.04系统安装到ROS2深度优化,涵盖驱动部署、CUDA环境配置、散热与功耗管理等关键步骤。特别针对Orin AGX的特性提供了实用避坑指南和性能优化技巧,帮助开发者高效完成开发环境配置。 阅读详情

相关推荐

手把手教你用MATLAB/Simulink模拟微电网潮流方向(附代码下载)

本文提供了一份详细的MATLAB/Simulink微电网潮流仿真实战指南。通过手把手教学,指导读者从零搭建包含光伏、储能和负荷的微电网模型,并模拟并网、孤岛等多种运行场景下的潮流方向变化。文章核心在于利用Simulink实现微电网的动态潮流分析与可视化,帮助工程师深入理解分布式能源系统中的功率平衡与控制策略。

weixin_28314575的博客 106

线程池的实现原理

线程池的实现原理 线程池做的工作主要是控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数超过了最大数量超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。 什么是线程池 线程池(Thread Pool)是一种基于池化思想管理线程的工具,经常出现在多线程服务器中,如MySQL。线程过多会带来额外的开销,其中包括创建销毁线程的开销、调度线程的开销等等,同时也降低了计算机的整体性能。线程池维护多个线程,等待监督管理者分配可并发执行的任务。这种做法,一方面避

程序猿进阶 1万+

显示模组Bonding IC气泡问题的诊断与优化策略

本文深入分析了显示模组Bonding IC气泡问题的成因与优化策略,涵盖IC两端剥离气泡、彩虹状水汽气泡、电极下方无规律气泡及IC输入端气泡等类型。通过工艺参数优化、材料存储处理、清洁环境控制及维修品特殊处理等多维度解决方案,有效降低气泡不良率。同时介绍了纳米改性ACF材料、激光辅助排泡技术等前沿解决方案,为触控显示行业提供实用参考。

weixin_26805597的博客 420

线程池工作原理

一、线程池默认工作流程 1、线程在有任务的时候会常见核心的线程数corePoolSize 2、当线程满了(有任务但是线程被使用完)不会立即扩容,而是放到阻塞队列中,当阻塞队列满了之后才会继续创建线程。 3、如果队列满了,线程数达到最大线程数则会执行拒绝策略。 4、当线程数大于核心线程数事,超过KeepAliveTime(闲置时间),线程会被回收,最终会保持corePoolSize个线程。 二、五种实现 1、newSingleThreadExecutor() 池里只有一条线程,如果线程因为异常而停止,会自动

promiseful的博客 4万+

机械工程师如何用Codex实现CAD自动化:从重复劳动到智能设计

在机械设计领域,CAD二次开发长期面临学习门槛高、维护成本大的难题。随着AI编程助手如Codex的出现,通过自然语言生成可执行代码,工程师无需精通编程即可实现图纸批量处理、BOM表自动生成、参数化建模等任务。这种技术将重复性操作自动化,显著提升设计效率,让工程师聚焦于核心创新。应用场景涵盖批量修改图纸属性、跨软件数据流转、自动打印等。本文分享机械工程师利用Codex落地自动化的实战经验与避坑指南。

weixin_32296621的博客 357

解决turmex安装kali报错问题

在手机上安装好turmex后,都喜欢安装一个Linux系统,我当时安装的时kali,但是安装过程中,报错不断。 2019.8.24更新 1,出现问题首先看下载kali源文件是否完整 安装步骤中,会显示[解压中.....] ,可以看到解压的大小。 如图所示,完整源文件不小于81M。 如果源文件过小,则说明下载错误,而且在remove kali这个命令下,是不会删除源文件的,下一次安装只...

WeiLuckyStrike的博客 1万+

深入理解线程池(详解)

线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量超出数量的线程排队等候,等其它线程执行完毕,再从队列中取出任务来执行。他的主要特点为:线程复用;控制最大并发数;管理线程。

weixin_44825912的博客 1万+

从零构建:如何在VSCode中为HBuilderX迁移的UniApp项目搭建TypeScript支持环境

本文详细指导如何将HBuilderX中的UniApp项目迁移至VSCode并搭建TypeScript支持环境。通过pnpm包管理器初始化项目、配置tsconfig.json和vite.config.ts文件,实现工程化迁移与TypeScript深度集成,提升开发效率和代码质量。

book8的博客 1050

详述Java线程池实现原理

线程池是什么 线程池就是创建若干个可执行的线程放入一个池(容器)中,有任务需要处理时,会提交到线程池中的任务队列,处理完之后线程并不会被销毁,而是仍然在线程池中等待下一个任务。 使用线程池有什么好处 降低资源消耗:通过重复利用现有的线程来执行任务,避免多次创建和销毁线程 提高响应速度:因为省去了创建线程这个步骤,所以在拿到任务时,可以立刻开始执行 提供附加功能:线程池的可拓展性使得我们可以自己加入新的功能,比如说定时、延时来执行某些线程 提高线程的可管理性:线程是稀缺资源,如果无限制的创建,不仅会消耗系统

养歌的博客 3070

新手必看!BUUCTF-PWN题实战:从零搭建Kali环境到成功RIP栈溢出

本文为CTF二进制安全新手提供了一份详实的BUUCTF-PWN入门指南。内容涵盖从零搭建Kali Linux环境、安装配置pwntools等核心工具,到深入浅出地讲解栈溢出原理与汇编基础,并手把手带领读者完成一道名为“rip”的经典栈溢出题目实战,成功利用漏洞获取系统权限。

t8u9v0w1x的博客 504

进阶05:Labview与汇川PLC通过OPC UA通信(AM500系列)

本文介绍了LabVIEW与汇川PLC通过OPC UA通信的实现方法。主要内容包括:1)编写汇川AM521 PLC结构化文本程序,配置OPC UA服务器并导出变量;2)使用UaExpert客户端测试读取PLC变量;3)开发C#封装库实现OPC UA连接、读写和订阅功能;4)在LabVIEW中创建通信类,封装dll功能;5)设计LabVIEW界面实现变量读写和PLC程序触发。最终实现了PLC变量监控、数据读写及Y1-Y4输出控制功能,为自动化系统开发提供了基础框架。

weixin_38637405的博客 1302

Java线程池实现原理详解

原理概述 其实java线程池的实现原理很简单,说白了就是一个线程集合workerSet和一个阻塞队列workQueue。当用户向线程池提交一个任务(也就是线程)时,线程池会先将任务放入workQueue中。workerSet中的线程会不断的从workQueue中获取线程然后执行。当workQueue中没有任务的时候,worker就会阻塞,直到队列中有任务了就取出来继续执行。 线程池的几...

u013332124的专栏 6万+

实现两端固支梁热力耦合的有限元分析

在本文中,我们将使用Matlab实现两端固支梁的热力耦合有限元分析。我们假设梁的材料是均匀的,梁的截面积为1,长度为1,两端固支,且受到均匀分布的热荷载。接下来,我们需要组装全局刚度矩阵和热传导矩阵。对于两个相邻的元素,它们共享一个节点,因此需要使用连接矩阵将局部矩阵组装成全局矩阵。接下来,我们需要定义元素刚度矩阵和热传导矩阵。然后,我们需要定义载荷向量。然后,我们需要定义边界条件。在这个例子中,梁的两端固支,因此我们需要将两端节点的位移限制为0。最后,我们需要解决线性方程组,得到节点的位移和温度分布。

CyberSparkZ的博客 395

还不懂Java线程池实现原理,看这一篇文章就够了

今天带大家一块详细剖析了Java线程池的实现原理,是不是非常简单?几百行的方法虽然看着复杂,令人头疼,只要由浅入深的梳理清理业务逻辑,源码读起来也是小菜一碟。

weixin_74412978的博客 1180

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Java线程池实现原理

Java线程池的原理与实现

CaffeineDriven的博客 512

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

线程池实现原理_Java高频面试题之“线程池实现原理”

其实java线程池的实现原理很简单,说白了就是一个线程集合workerSet和一个阻塞队列workQueue。当用户向线程池提交一个任务(也就是线程)时,线程池会先将任务放入workQueue中。workerSet中的线程会不断的从workQueue中获取线程然后执行。当workQueue中没有任务的时候,worker就会阻塞,直到队列中有任务了就取出来继续执行。线程池的几个主要参数的作用publ...

weixin_39609407的博客 315

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

java线程池实现原理

原文路径:https://www.jianshu.com/p/87bff5cc8d8c 前言 线程是稀缺资源,如果被无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,合理的使用线程池对线程进行统一分配、调优和监控,有以下好处: 1、降低资源消耗; 2、提高响应速度; 3、提高线程的可管理性。 Java1.5中引入的Executor框架把任务的提交和执行进行解耦,只需要定义好任务,然后提...

洋成林 723

我眼中的java线程池实现原理

最近在看java线程池实现方面的源码,在此做个小结,因为网上关于线程池源码分析的博客挺多的,我也不打算重复造轮子啦,仅仅用纯语言描述的方式做做总结啦!         个人认为要想理解清楚java线程池实现原理,明白下面几个问题就可以了:         (1):线程池存在哪些状态,这些状态之间是如何进行切换的呢?         (2):创建线程池需要哪些参数,这些参数的具体含义是

扇扇来驰的博客 1万+

Java线程池的实现原理

Java中的线程池的使用场景有很多种,大多数并发框架及并发场景都使用了线程池来管理线程,使用线程池带来的好处主要有以下几点。 第一:提升系统资源利用。重复的创建线程对于系统开销很大,通过重复利用已经创建的线程提高系统的性能 第二:提高系统响应时间。当一个任务被提交不需要等待去创建线程,从而提升响应时间 第三:方便管理线程。通过合理的配置线程池,来优化及使用线程 Java线程池的实现原理是怎...

yxz1025的专栏 322

java线程池的实现原理笔记

线程池的实现原理 “池” 1、复用已有资源 2、控制资源总数 线程池优势 1、限流,控制线程数量 2、降低频繁创建和小伙线程 3、对于任务响应速度更快 // 固定线程数线程池 Executors.newFixedThreadPool public static ExecutorService newFixedThreadPool(int nThreads) { retur...

DavidSoCool的博客 339

深入理解 Java 线程池的实现原理

文章目录1 线程状态2 线程池2.1 线程池的作用2.2 线程池的实现 1 线程状态 既然要说线程,我们就先来了解一下线程的几种状态: public enum State { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED; ...

安正勋的博客 1904

Java线程池全面解析:原理、实现与最佳实践

摘要:本文深入讲解Java线程池的核心原理与最佳实践,涵盖ThreadPoolExecutor参数配置、工作流程、拒绝策略等关键内容。重点解析如何合理设置线程池参数(区分CPU/IO密集型任务),推荐手动配置而非使用Executors工厂方法,并提供监控优化和优雅停机方案。文章强调命名线程、队列控制、拒绝策略设置等生产环境实用技巧,帮助开发者构建高效安全的并发程序。适合需要优化高并发系统的Java开发者阅读。(149字)

真正的大师永远怀着一颗学徒的心 1177
上一篇: JVM 之 逃逸分析和TLAB
下一篇: Java并发编程 之 乐观锁和悲观锁
CallMeJiaGu
博客等级 码龄12年 149粉丝 99原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值