从零开始学习 Java:简单易懂的入门指南之线程池(三十六)

线程池

    • 1.1 线程状态介绍
    • 1.2 线程池-基本原理
    • 1.3 线程池-Executors默认线程池
    • 1.4 线程池-Executors创建指定上限的线程池
    • 1.5 线程池-ThreadPoolExecutor
    • 1.6 线程池-参数详解
    • 1.7 线程池-非默认任务拒绝策略

1.1 线程状态介绍

当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。线程对象在不同的时期有不同的状态。那么Java中的线程存在哪几种状态呢?Java中的线程

状态被定义在了java.lang.Thread.State枚举类中,State枚举类的源码如下:

public class Thread {public enum State {/* 新建 */NEW , /* 可运行状态 */RUNNABLE , /* 阻塞状态 */BLOCKED , /* 无限等待状态 */WAITING , /* 计时等待 */TIMED_WAITING , /* 终止 */TERMINATED;}// 获取当前线程的状态public State getState() {return jdk.internal.misc.VM.toThreadState(threadStatus);}}

通过源码我们可以看到Java中的线程存在6种状态,每种线程状态的含义如下

线程状态具体含义
NEW一个尚未启动的线程的状态。也称之为初始状态、开始状态。线程刚被创建,但是并未启动。还没调用start方法。MyThread t = new MyThread()只有线程象,没有线程特征。
RUNNABLE当我们调用线程对象的start方法,那么此时线程对象进入了RUNNABLE状态。那么此时才是真正的在JVM进程中创建了一个线程,线程一经启动并不是立即得到执行,线程的运行与否要听令与CPU的调度,那么我们把这个中间状态称之为可执行状态(RUNNABLE)也就是说它具备执行的资格,但是并没有真正的执行起来而是在等待CPU的度。
BLOCKED当一个线程试图获取一个对象锁,而该对象锁被其他的线程持有,则该线程进入Blocked状态;当该线程持有锁时,该线程将变成Runnable状态。
WAITING一个正在等待的线程的状态。也称之为等待状态。造成线程等待的原因有两种,分别是调用Object.wait()、join()方法。处于等待状态的线程,正在等待其他线程去执行一个特定的操作。例如:因为wait()而等待的线程正在等待另一个线程去调用notify()或notifyAll();一个因为join()而等待的线程正在等待另一个线程结束。
TIMED_WAITING一个在限定时间内等待的线程的状态。也称之为限时等待状态。造成线程限时等待状态的原因有三种,分别是:Thread.sleep(long),Object.wait(long)、join(long)。
TERMINATED一个完全运行完成的线程的状态。也称之为终止状态、结束状态

各个状态的转换,如下图所示:

在这里插入图片描述

1.2 线程池-基本原理

概述 :

​ 提到池,大家应该能想到的就是水池。水池就是一个容器,在该容器中存储了很多的水。那么什么是线程池呢?线程池也是可以看做成一个池子,在该池子中存储很多个线程。

线程池存在的意义:

​ 系统创建一个线程的成本是比较高的,因为它涉及到与操作系统交互,当程序中需要创建大量生存期很短暂的线程时,频繁的创建和销毁线程对系统的资源消耗有可能大于业务处理是对系

​ 统资源的消耗,这样就有点"舍本逐末"了。针对这一种情况,为了提高性能,我们就可以采用线程池。线程池在启动的时,会创建大量空闲线程,当我们向线程池提交任务的时,线程池就

​ 会启动一个线程来执行该任务。等待任务执行完毕以后,线程并不会死亡,而是再次返回到线程池中称为空闲状态。等待下一次任务的执行。

线程池的设计思路 :

  1. 准备一个任务容器
  2. 一次性启动多个(2个)消费者线程
  3. 刚开始任务容器是空的,所以线程都在wait
  4. 直到一个外部线程向这个任务容器中扔了一个"任务",就会有一个消费者线程被唤醒
  5. 这个消费者线程取出"任务",并且执行这个任务,执行完毕后,继续等待下一次任务的到来

1.3 线程池-Executors默认线程池

概述 : JDK对线程池也进行了相关的实现,在真实企业开发中我们也很少去自定义线程池,而是使用JDK中自带的线程池。

我们可以使用Executors中所提供的静态方法来创建线程池

​ static ExecutorService newCachedThreadPool() 创建一个默认的线程池
​ static newFixedThreadPool(int nThreads) 创建一个指定最多线程数量的线程池

代码实现 :

package com.itheima.mythreadpool;//static ExecutorService newCachedThreadPool()   创建一个默认的线程池
//static newFixedThreadPool(int nThreads)	    创建一个指定最多线程数量的线程池import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class MyThreadPoolDemo {public static void main(String[] args) throws InterruptedException {//1,创建一个默认的线程池对象.池子中默认是空的.默认最多可以容纳int类型的最大值.ExecutorService executorService = Executors.newCachedThreadPool();//Executors --- 可以帮助我们创建线程池对象//ExecutorService --- 可以帮助我们控制线程池executorService.submit(()->{System.out.println(Thread.currentThread().getName() + "在执行了");});//Thread.sleep(2000);executorService.submit(()->{System.out.println(Thread.currentThread().getName() + "在执行了");});executorService.shutdown();}
}

1.4 线程池-Executors创建指定上限的线程池

使用Executors中所提供的静态方法来创建线程池

​ static ExecutorService newFixedThreadPool(int nThreads) : 创建一个指定最多线程数量的线程池

代码实现 :

package com.itheima.mythreadpool;//static ExecutorService newFixedThreadPool(int nThreads)
//创建一个指定最多线程数量的线程池import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;public class MyThreadPoolDemo2 {public static void main(String[] args) {//参数不是初始值而是最大值ExecutorService executorService = Executors.newFixedThreadPool(10);ThreadPoolExecutor pool = (ThreadPoolExecutor) executorService;System.out.println(pool.getPoolSize());//0executorService.submit(()->{System.out.println(Thread.currentThread().getName() + "在执行了");});executorService.submit(()->{System.out.println(Thread.currentThread().getName() + "在执行了");});System.out.println(pool.getPoolSize());//2
//        executorService.shutdown();}
}

1.5 线程池-ThreadPoolExecutor

创建线程池对象 :

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(核心线程数量,最大线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略);

代码实现 :

package com.itheima.mythreadpool;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class MyThreadPoolDemo3 {
//    参数一:核心线程数量
//    参数二:最大线程数
//    参数三:空闲线程最大存活时间
//    参数四:时间单位
//    参数五:任务队列
//    参数六:创建线程工厂
//    参数七:任务的拒绝策略public static void main(String[] args) {ThreadPoolExecutor pool = new ThreadPoolExecutor(2,5,2,TimeUnit.SECONDS,new ArrayBlockingQueue<>(10), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());pool.submit(new MyRunnable());pool.submit(new MyRunnable());pool.shutdown();}
}

1.6 线程池-参数详解

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=.%5Cimg%5C1591165506516.png&pos_id=img-0TZaH6p5-169366408644

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)corePoolSize:   核心线程的最大值,不能小于0
maximumPoolSize:最大线程数,不能小于等于0,maximumPoolSize >= corePoolSize
keepAliveTime:  空闲线程最大存活时间,不能小于0
unit:           时间单位
workQueue:      任务队列,不能为null
threadFactory:  创建线程工厂,不能为null      
handler:        任务的拒绝策略,不能为null  

1.7 线程池-非默认任务拒绝策略

RejectedExecutionHandler是jdk提供的一个任务拒绝策略接口,它下面存在4个子类。

ThreadPoolExecutor.AbortPolicy: 		    丢弃任务并抛出RejectedExecutionException异常。是默认的策略。
ThreadPoolExecutor.DiscardPolicy: 		   丢弃任务,但是不抛出异常 这是不推荐的做法。
ThreadPoolExecutor.DiscardOldestPolicy:    抛弃队列中等待最久的任务 然后把当前任务加入队列中。
ThreadPoolExecutor.CallerRunsPolicy:        调用任务的run()方法绕过线程池直接执行。

注:明确线程池对多可执行的任务数 = 队列容量 + 最大线程数

案例演示1:演示ThreadPoolExecutor.AbortPolicy任务处理策略

public class ThreadPoolExecutorDemo01 {public static void main(String[] args) {/*** 核心线程数量为1 , 最大线程池数量为3, 任务容器的容量为1 ,空闲线程的最大存在时间为20s*/ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1 , 3 , 20 , TimeUnit.SECONDS ,new ArrayBlockingQueue<>(1) , Executors.defaultThreadFactory() , new ThreadPoolExecutor.AbortPolicy()) ;// 提交5个任务,而该线程池最多可以处理4个任务,当我们使用AbortPolicy这个任务处理策略的时候,就会抛出异常for(int x = 0 ; x < 5 ; x++) {threadPoolExecutor.submit(() -> {System.out.println(Thread.currentThread().getName() + "---->> 执行了任务");});}}
}

控制台输出结果

pool-1-thread-1---->> 执行了任务
pool-1-thread-3---->> 执行了任务
pool-1-thread-2---->> 执行了任务
pool-1-thread-3---->> 执行了任务

控制台报错,仅仅执行了4个任务,有一个任务被丢弃了

案例演示2:演示ThreadPoolExecutor.DiscardPolicy任务处理策略

public class ThreadPoolExecutorDemo02 {public static void main(String[] args) {/*** 核心线程数量为1 , 最大线程池数量为3, 任务容器的容量为1 ,空闲线程的最大存在时间为20s*/ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(1 , 3 , 20 , TimeUnit.SECONDS ,new ArrayBlockingQueue<>(1) , Executors.defaultThreadFactory() , new ThreadPoolExecutor.DiscardPolicy()) ;// 提交5个任务,而该线程池最多可以处理4个任务,当我们使用DiscardPolicy这个任务处理策略的时候,控制台不会报错for(int x = 0 ; x < 5 ; x++) {threadPoolExecutor.submit(() -> {System.out.println(Thread.currentThread().getName() + "---->> 执行了任务");});}}
}

控制台输出结果

pool-1-thread-1---->> 执行了任务
pool-1-thread-1---->> 执行了任务
pool-1-thread-3---->> 执行了任务
pool-1-thread-2---->> 执行了任务

控制台没有报错,仅仅执行了4个任务,有一个任务被丢弃了

案例演示3:演示ThreadPoolExecutor.DiscardOldestPolicy任务处理策略

public class ThreadPoolExecutorDemo02 {public static void main(String[] args) {/*** 核心线程数量为1 , 最大线程池数量为3, 任务容器的容量为1 ,空闲线程的最大存在时间为20s*/ThreadPoolExecutor threadPoolExecutor;threadPoolExecutor = new ThreadPoolExecutor(1 , 3 , 20 , TimeUnit.SECONDS ,new ArrayBlockingQueue<>(1) , Executors.defaultThreadFactory() , new ThreadPoolExecutor.DiscardOldestPolicy());// 提交5个任务for(int x = 0 ; x < 5 ; x++) {// 定义一个变量,来指定指定当前执行的任务;这个变量需要被final修饰final int y = x ;threadPoolExecutor.submit(() -> {System.out.println(Thread.currentThread().getName() + "---->> 执行了任务" + y);});     }}
}

控制台输出结果

pool-1-thread-2---->> 执行了任务2
pool-1-thread-1---->> 执行了任务0
pool-1-thread-3---->> 执行了任务3
pool-1-thread-1---->> 执行了任务4

由于任务1在线程池中等待时间最长,因此任务1被丢弃。

案例演示4:演示ThreadPoolExecutor.CallerRunsPolicy任务处理策略

public class ThreadPoolExecutorDemo04 {public static void main(String[] args) {/*** 核心线程数量为1 , 最大线程池数量为3, 任务容器的容量为1 ,空闲线程的最大存在时间为20s*/ThreadPoolExecutor threadPoolExecutor;threadPoolExecutor = new ThreadPoolExecutor(1 , 3 , 20 , TimeUnit.SECONDS ,new ArrayBlockingQueue<>(1) , Executors.defaultThreadFactory() , new ThreadPoolExecutor.CallerRunsPolicy());// 提交5个任务for(int x = 0 ; x < 5 ; x++) {threadPoolExecutor.submit(() -> {System.out.println(Thread.currentThread().getName() + "---->> 执行了任务");});}}
}

控制台输出结果

pool-1-thread-1---->> 执行了任务
pool-1-thread-3---->> 执行了任务
pool-1-thread-2---->> 执行了任务
pool-1-thread-1---->> 执行了任务
main---->> 执行了任务

通过控制台的输出,我们可以看到次策略没有通过线程池中的线程执行任务,而是直接调用任务的run()方法绕过线程池直接执行。

后记
👉👉💕💕美好的一天,到此结束,下次继续努力!欲知后续,请看下回分解,写作不易,感谢大家的支持!! 🌹🌹🌹

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/161195.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux文件权限与目录配置

用户与用户组 linux一般将文件可读写的身份分为三个类别&#xff1a;拥有者&#xff08;owner&#xff09;、所属群组&#xff08;group&#xff09;、其他人&#xff08;other&#xff09; 三种身份都有读、写、执行等权限 文件拥有者 linux是个多人多任务的系统&#xff0c…

论文解析-moETM

论文解析-moETM 参考亮点动机发展现状现存问题 功能方法Encoder改进Decoder改进 评价指标生物保守性批次效应移除 实验设置结果多组学数据整合cell-topic mixture可解释性组学翻译性能评估RNA转录本、表面蛋白、染色质可及域调控关系研究1. 验证同一主题下&#xff0c;top gene…

什么是NetApp的DQP和如何安装DQP?

首先看看什么是DQP&#xff0c;DQPDisk Qualification Package&#xff0c;文字翻译就是磁盘验证包。按照NetApp的最佳实践&#xff0c;要定期升级DQP包&#xff0c;保证对最新磁盘和磁盘扩展柜的兼容。 本文主要介绍7-mode下如何升级DQP&#xff0c;至于cluster mode另外文章…

NewStarCTF2023week2-Upload again!

尝试传修改后缀的普通一句话木马&#xff0c;被检测 尝试传配置文件 .htaccess 和 .user.ini 两个都传成功了 接下来继续传入经过修改的木马 GIF89a <script language"php"> eval($_POST[cmd]); </script> 没有被检测&#xff0c;成功绕过 直接上蚁剑…

圣树唤歌最强阵容2023,圣树唤歌阵容推荐

无疑圣树唤歌作为一款备受欢迎的手机游戏&#xff0c;其深刻的战斗系统一直以来都受到大家的追捧。在这个虚拟世界中胜利的关键在于组建一支无懈可击的强大队伍&#xff0c;要想成为强者&#xff0c;就必须拥有最强阵容。 关注【娱乐天梯】&#xff0c;获取内部福利号 在本篇攻…

C++项目实战——基于多设计模式下的同步异步日志系统(总集篇)

文章目录 专栏导读项目介绍开发环境核心技术环境搭建日志系统介绍1.为什么需要日志系统2.日志系统技术实现2.1同步写日志2.2异步写日志 前置知识补充不定参函数C风格不定参函数不定参宏函数设计模式六大原则单例模式饿汉模式懒汉模式 工厂模式简单工厂模式工厂方法模式抽象工厂…

Linux:mongodb数据逻辑备份与恢复(3.4.5版本)

我在数据库aaa的里创建了一个名为tarro的集合&#xff0c;其中有三条数据 备份语法 mongodump –h server_ip –d database_name –o dbdirectory 恢复语法 mongorestore -d database_name --dirdbdirectory 备份 现在我要将aaa.tarro进行备份 mongodump --host 192.168.254…

攻防演练蓝队|Windows应急响应入侵排查

文章目录 日志分析web日志windows系统日志 文件排查进程排查新增、隐藏账号排查启动项/服务/计划任务排查工具 日志分析 web日志 dirpro扫描目录&#xff0c;sqlmap扫描dvwa Python dirpro -u http://192.168.52.129 -b sqlmap -u "http://192.168.52.129/dvwa/vulnera…

Jmeter接口测试:jmeter导入和导出接口的处理

JMeter测试导入接口 利用Jmeter测试上传文件&#xff0c;首先可根据接口文档或者fiddler抓包分析文件上传的接口&#xff1b;如下图&#xff1a; 以下是我通过fiddler所截取的文件上传的接口 1、填写导入接口的信息 查看文件上传栏下的填写信息&#xff1a; 文件名称&#x…

Unity中Shader的深度写入ZWrite

文章目录 前言一、更新深度缓冲区中值二、深度值的写入操作只有两个选择 开启 和 关闭ZWrite OnZWrite Off 三、深度写入在半透明物体物体中开启的情况1、特效一般都需要关闭深度写入2、如果在人物模型上使用 特效半透明 的 Shader&#xff0c;为了不出现模型自身穿透问题&…

Web3D虚拟人制作简明指南

如何在线创建虚拟人? 虚拟人,也称为数字化身、虚拟助理或虚拟代理,是一种可以通过各种在线平台与用户进行逼真交互的人工智能人。 在线创建虚拟人变得越来越流行,因为它为个人和企业带来了许多好处。 通过虚拟助理或代理,您可以以更具吸引力和个性化的方式与客户或受众进…

146.LRU缓存

双向链表哈希表 class LRUCache { public://1、定义双向链表结构、容量、哈希表等LRU数据成员struct Node{int key,value;Node *left,*right;Node(int _key,int _value):key(_key),value(_value),left(NULL),right(NULL){}}*L,*R;int n;unordered_map<int,Node*> ump;//…

李航:关于大模型的思考及研究热点

本文阐述李航老师对 LLM 的一些看法&#xff0c;主要观点如下&#xff1a; ChatGPT 的突破主要在于规模带来的质变和模型调教方式的发明。 LLM 融合了实现人工智能的三条路径。 LLM 的开发需要结合第三者体验和第一者体验。 LLM 能近似生成心智语言。 LLM 需要与多模态大模…

SamSung三星笔记本NP930QCG-K02CN原装出厂OEM预装Win10系统

下载链接&#xff1a;https://pan.baidu.com/s/13GsR_r9caJkLjiWWaXa30Q?pwdncp9 系统自带指纹驱动、声卡,网卡,显卡等所有驱动、三星出厂时主题壁纸、系统属性三星专属LOGO标志、Office办公软件等三星出厂时自带的预装程序 由于时间关系,绝大部分资料没有上传&#xff0c;不…

Unity之ShaderGraph如何实现上下溶解

前言 我们经常在电影中见到的一个物体或者人物&#xff0c;从头上到脚下&#xff0c;慢慢消失的效果&#xff0c;我么今天就来体验一下这个上下溶解。 主要节点 Position节点&#xff1a;提供对网格顶点或片段的Position 的访问 Step节点&#xff1a;如果输入In的值大于或…

双目视觉实战--相机几何

目录 一、针孔摄像机和透镜 1. 针孔摄像机的原理 2. 近轴折射模型 3. 镜头畸变问题 二、摄像机几何 1. 数学基础 2. 相机坐标系&#xff08;空间点&#xff09;→像素坐标系的映射关系&#xff1a; 3. 规范化投影变换 4. 投影变换的性质 三、其他摄像机模型 1. 弱透视…

新时代高效记账:自动化智能如何进行财务管理

随着科技的不断发展&#xff0c;自动化智能已经逐渐渗透到我们生活的各个领域。在财务管理中&#xff0c;自动化智能的应用显得尤为重要。它不仅可以提高财务管理的效率和精度&#xff0c;还能帮助我们更好地规划和掌控公司的财务状况 晨曦记账本提供了多种高效财务管理工具。…

【MultiOTP】Docker安裝MultiOTP, 让Windows登入更安全(MFA)

序 在当前数字时代&#xff0c;网络安全成为了一个非常重要的话题。随着越来越多的人和组织依赖于计算机系统来进行工作和存储敏感信息&#xff0c;确保身份验证安全变得至关重要。双因素身份验证&#xff08;2FA&#xff09;是一种强大的安全措施&#xff0c;可在传统的用户名…

设计模式截图记录

设计模式截图记录

机器人制作开源方案 | 双轮提升搬运小车

1. 功能描述 双轮提升搬运小车是一种用于搬运和移动物体的机械设备&#xff0c;它通常采用双轮驱动和提升装置。一般具备以下特点&#xff1a; ① 双轮驱动&#xff1a;该小车配备两个驱动轮&#xff0c;通过电动机或其它动力源驱动&#xff0c;提供足够的动力和扭矩&#xff0…