Java并发编程之线程池详解

目录

🐳今日良言:不悲伤 不彷徨 有风听风 有雨看雨

🐇一、简介

🐇二、相关代码

🐼1.线程池代码

🐼2.自定义实现线程池

🐇三、ThreadPoolExecutor类


🐳今日良言:不悲伤 不彷徨 有风听风 有雨看雨

🐇一、简介

首先来介绍一下什么是线程池,线程池是一种利用池化技术思想来实现的线程管理技术,主要是为了复用线程、便利地管理线程和任务并将线程的创建和任务的执行解耦开来。我们可以创建线程池来复用已经创建的线程来降低频繁创建和销毁线程所带来的资源消耗。在JAVA中主要是通过java.util.concurrent包中的ThreadPoolExecutor类来实现线程池 。

🐇二、相关代码

🐼1.线程池代码

这里就是创造出一个10个线程的线程池,然后就可以随机安排这些线程完成任务了。

线程池提供了一个重要的方法 submit 可以给线程池提交若干个任务。

 submit的参数是一个Runnable,用来描述这些线程要执行的任务是什么。

线程池中的线程都是前台线程,前台线程会阻止进程结束,也就是说,运行程序之后,main线程结束了,但是整个进程没有结束。

当前是往线程池里放了 1000 个任务,1000 个任务就是由这 10 个线程来平均分配一下,差不多是一人执行 100个,但是这里并非是严格的平均,可能有的多一个有的少一个都正常。(每个线程都执行完一个任务之后,再立即取下一个任务...由于每个任务执行时间都差不多,因此每个线程做的任务数量就差不多)

上述代码涉及到变量捕获

 这里的 i 是主线程里的局部变量(在主线程的栈上),随着主线程的代码执行结束就销毁了,但是,很可能这里的 for 循环已经执行完了,当前 run 的任务在线程池里还没有排到,此时 i 就已经要销毁了。这里的 run 方法属于 Runnable ,这个方法的执行时机并不是立刻执行,而是在未来的某个时间点(后续在线程池的队列中排到了) 才会执行,为了避免作用域的差异,导致执行 run 方法的时候,i 已经销毁了,于是就有了变量捕获,也就是让 run 方法把主线程的 i 往当前 run 方法的栈上拷贝一份(在定义 run 方法的时候了,把当前 i 的值记住,后续执行 run 的时候,就创建一个也叫做 i 的局部变量,并且把这个值给赋值过去)。

在Java 中,对于变量捕获,做了一些额外的要求,在JDK 1.8之前,要求变量捕获只能捕获 final 修饰的变量,后来发现,这样太麻烦了,于是,在 JDK 1.8 开始,发送了一点标准,要求不一定非得待 final 关键字,只要代码中没有修改过这个变量,也可以捕获。

在上述代码中,i 是被修改的,因此不能捕获,但是 n 没有被修改,所以可以被捕获。

接下来,介绍一下几种不同的线程池:

new FixedThreadPool        创建固定线程数的线程池。

newCachedThreadPool      线程数量是动态变化的,任务多了就多创建几个线程,任务少了 

                                            就少创建几个。

newScheduledThreadPool  类似于定时器,让任务延时执行。

newSingleThreadExecutor  线程池里只有一个线程。

上述这些线程池,本质上都是通过包装 ThreadPoolExecutor 来实现的,这个线程池用起来比较麻烦,所以提供了工厂类,让我们使用更方便,ThreadPoolExecutor 提供的功能更为强大,后面会详细介绍。 

🐼2.自定义实现线程池

 自定义实现线程池代码如下:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;class MyThreadPool {// 阻塞队列private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();// 若干个工作线程// n表示线程的数量public MyThreadPool(int n) {for (int i = 0; i < n; i++) {Thread t = new Thread(() -> {while (true) {try {// 从阻塞队列中取出然后执行Runnable runnable = queue.take();runnable.run();} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();}}// 注册任务给线程池public void submit(Runnable runnable) {try {queue.put(runnable);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
public class Exercise{public static void main(String[] args) {MyThreadPool myThreadPool = new MyThreadPool(10);for (int i = 0; i < 1000; i++) {int n = i;myThreadPool.submit(new Runnable() {@Overridepublic void run() {System.out.println("hello:"+n);}});}}
}

🐇三、ThreadPoolExecutor类

最后,介绍一下ThreadPoolExecutor 里面的参数,如下图:

1)int corePoolSize

核心线程数

2)int maximumPoolSize

最大线程数

ThreadPoolExecutor 相当于是把里面的线程分成了两类,一类是核心线程,一类是临时线程,核心线程相当于是正式工,临时线程相当于是临时工,这二者之和就是最大线程数。

如果任务多,需要创建更多的线程,但是,一个程序的任务不一定始终都有很多,有时候多,有时候少,如果现在任务少了,线程还那么多,就非常不合适了,因此,就需要对现有的线程进行一定的淘汰,整体的淘汰策略是:核心线程保底,临时线程动态调节。

在实际开发的时候,线程池的线程数设置成多少比较合适呢?

实际上,这里不应该回答出具体的数字,在实际开发中,线程池的线程数设置需要根据具体情况进行调整,一般来说,应该设置为CPU核心数的两倍到四倍之间,如果线程数过少,则导致任务等待时间过长,而如果线程数过多,会导致系统资源浪费。如果任务是IO密集型的,那么可以适当的增加线程数,如果任务是CPU密集型的,则可以适当的减少线程数。

3)long keepAliveTime

临时线程的最大空闲时间,超出这个时间,临时线程就会被销毁了。

也就是临时工的最大摸鱼时间。

4)TimeUnit unit 

时间单位(s,ms,分钟...)

5)BlockingQueue<Runnable> workQueue

线程池的任务队列

此处使用的是阻塞队列,每个线程都是在不停的尝试take,如果有任务,就take成功,没有就阻塞。

6)ThreadFactory  threadFactory

用于创建线程,线程池是需要创建线程的

7)RejectedExecutionHandler handler

描述了线程池的“拒绝策略”,也是一个特殊的对象,描述了当线程池任务队列满了,如果继续添加任务会有什么样的行为。

标准库提供了四个拒绝策略,如下图:

 第一个拒绝策略

如果任务太多,任务队列满了,就直接抛出异常。

第二个拒绝策略

如果任务太多,任务队列满了,多出来的任务,谁加的谁负责执行。

第三个拒绝策略

如果任务太多,任务队列满了,丢弃最早的任务。

第四个拒绝策略

如果任务太多,任务队列满了,丢弃最新的任务。


 以上就是本篇博客的所有内容了,望有所帮助~

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

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

相关文章

浅析Python爬虫ip程序延迟和吞吐量影响因素

作为一名资深的爬虫程序员&#xff0c;今天我们很有必要来聊聊Python爬虫ip程序的延迟和吞吐量&#xff0c;这是影响我们爬取效率的重要因素。这里我们会提供一些实用的解决方案&#xff0c;让你的爬虫程序飞起来&#xff01; 网络延迟 首先&#xff0c;让我们来看看网络延迟对…

sql2008 开启端口1433,进行远程连接SQL服务器

设置完成后&#xff0c;接着重启SQL服务器 注意本机测试的话&#xff0c;必须要关闭防火墙&#xff0c;如果是腾讯云或阿里云的话&#xff0c;必须开启1433端口。否则无法远程连接到SQL服务器的。 但是这里我们对于外网的项目&#xff0c;基本不会在客户端上直接用 这种模式去…

记一次oracle数据库迁移至mysql数据库(表同步)

目录 一、利用Navicat将oracle迁移至mysql数据库 1、建立数据传输 2、选择需要迁移的数据库跟目标库 3、数据传输选项 4、选择需要迁移表信息 二、迁移之后遇到的一些问题 1、大小写问题 2、数据库函数问题 3、sql语句是否使用空格隔开问题 4、关于子查询别命名问题 …

GPT-3.5——从 人工智障 到 大人工智障

有人说&#xff0c;GPT是从人工智障到人工智能的蜕变&#xff0c;但是。。。 我认为&#xff0c;GPT是从 人工智障 到 大人工智障 的退化。。。 从 人工智障 到 大人工智障 GPT-3.5学术介绍No.1---- 西红柿炒钢丝球基本信息详细制作方法材料步骤 幕后花絮 No.2---- 顶尖数学家…

Android学习之路(7) Frament

Fragment 表示应用界面中可重复使用的一部分。fragment 定义和管理自己的布局&#xff0c;具有自己的生命周期&#xff0c;并且可以处理自己的输入事件。fragment 不能独立存在。它们必须由 activity 或其他 fragment 托管。fragment 的视图层次结构会成为宿主的视图层次结构的…

HarmonyOS学习路之方舟开发框架—学习ArkTS语言(状态管理 四)

Observed装饰器和ObjectLink装饰器&#xff1a;嵌套类对象属性变化 上文所述的装饰器仅能观察到第一层的变化&#xff0c;但是在实际应用开发中&#xff0c;应用会根据开发需要&#xff0c;封装自己的数据模型。对于多层嵌套的情况&#xff0c;比如二维数组&#xff0c;或者数…

Redis 缓存满了怎么办?

引言 Redis 缓存使用内存来保存数据&#xff0c;随着需要缓存的数据量越来越大&#xff0c;有限的缓存空间不可避免地会被写满。此时&#xff0c;应该怎么办&#xff1f;本篇文章接下来就来聊聊缓存满了之后的数据淘汰机制。 值得注意的是&#xff0c;在 Redis 中 过期策略 和…

深度学习入门教学——二分分类

1、什么是二分分类&#xff1f; 二分分类就是判断“有”和“没有”、“是”和“不是”的问题&#xff0c;也就是监督学习中的分类问题。例如&#xff0c;输入一张图片&#xff0c;输出识别该图片的标签。计算机输入图片转化过程如下&#xff1a; 2、神经网络常用符号表示 (x, …

【openfeign】OpenFeign的使用、GET请求和POST请求

RPC全称是Remote Procedure Call&#xff0c;即远程过程调用&#xff0c;其对应的是我们的本地调用。 RPC的目的是&#xff1a;让我们调用远程方法像调用本地方法一样。 //本地调用 R result orderService.findOrderByUserId(id); //RPC远程调用 orderService为代理对象 R …

高效使用ChatGPT之ChatGPT客户端

ChatGPT客户端&#xff0c;支持Mac, Windows, and Linux 下载地址见文章结尾 软件截图 Windows: Mac&#xff1a; 说明 chatgpt桌面版&#xff0c;相比于网页版的chatgpt&#xff0c;最大的特色是支持历史聊天对话记录导出&#xff0c;且支持三种格式&#xff1a;PNG、PDF、…

Ae 效果:CC Line Sweep

过渡/CC Line Sweep Transition/CC Line Sweep CC Line Sweep&#xff08;CC 线条扫描&#xff09;通过线条的扫描动作来制作一个过渡效果&#xff0c;线条可以根据设定的方向、厚度、倾斜度和方向翻转来扫过画面&#xff0c;从而将一个场景过渡到另一个。 ◆ ◆ ◆ 效果属性…

如何关闭“若要接收后续google chrome更新,您需使用windows10或更高版本”

Windows Registry Editor Version 5.00[HKEY_CURRENT_USER\Software\Policies\Google\Chrome] "SuppressUnsupportedOSWarning"dword:00000001 如何关闭“若要接收后续 google chrome 更新,您需使用 windows 10 或更高版本” - 知乎

数学建模及数据分析 || 4. 深度学习应用案例分享

PyTorch 深度学习全连接网络分类 文章目录 PyTorch 深度学习全连接网络分类1. 非线性二分类2. 泰坦尼克号数据分类2.1 数据的准备工作2.2 全连接网络的搭建2.3 结果的可视化 1. 非线性二分类 import sklearn.datasets #数据集 import numpy as np import matplotlib.pyplot as…

YOLOX在启智AI GPU/CPU平台部署笔记

文章目录 1. 概述2. 部署2.1 拉取YOLOX源码2.2 拉取模型文件yolox_s.pth2.3 安装依赖包2.4 安装yolox2.5 测试运行2.6 运行报错处理2.6.1 ImportError: libGL.so.1: cannot open shared object file: No such file or directory2.6.2 ImportError: libgthread-2.0.so.0: cannot…

2、Spring_DI

DI 1.概述 概述&#xff1a;Dependency Injection 依赖注入&#xff0c;给对象设置属性&#xff0c;曾经我们需要自己去创建 mapper 对象&#xff0c;才能调用&#xff0c;现在交给 spring 创建&#xff0c;并且使用 DI 注入&#xff0c;直接拿来用&#xff0c;程序员就可以更…

[语音识别] 基于Python构建简易的音频录制与语音识别应用

语音识别技术的快速发展为实现更多智能化应用提供了无限可能。本文旨在介绍一个基于Python实现的简易音频录制与语音识别应用。文章简要介绍相关技术的应用&#xff0c;重点放在音频录制方面&#xff0c;而语音识别则关注于调用相关的语音识别库。本文将首先概述一些音频基础概…

Midjourney API 申请及使用

Midjourney API 申请及使用 在人工智能绘图领域&#xff0c;想必大家听说过 Midjourney 的大名吧&#xff01; Midjourney 以其出色的绘图能力在业界独树一帜。无需过多复杂的操作&#xff0c;只要简单输入绘图指令&#xff0c;这个神奇的工具就能在瞬间为我们呈现出对应的图…

多种编程语言运行速度排名-10亿次除7求余数为0的数量

最佳方式是运行10次&#xff0c;取平均数&#xff0c;用时秒数显示3位小数。 因为第一次打开&#xff0c;可能CPU还没优化好&#xff0c;多次取平均&#xff0c;比较准确 第1次共10次&#xff0c;用时3秒&#xff0c;平均3秒 第2次共10次&#xff0c;用时4秒&#xff0c;平均3.…

框架(Git基础详解及Git在idea中集成步骤)

目录 基础&#xff1a; idea集成Git并添加项目到git仓库 1.idea集成git&#xff0c;集成.git.exe文件 2.初始化本地Git仓库项目 3. 将工作区代码添加到暂存区 4.将暂存区代码添加到本地仓库 5.Git本地库操作 Idea集成Gitee并提交代码到第三方库 1.setting里搜索gitee 2.添…

分布式ID

分布式ID 背景Snowflake(雪花算法)uid-generatorleaf背景 分布式系统,用什么做为主键呢? uuid 太长(MySQL官方有明确的建议主键要尽量越短越好[4],36个字符长度的UUID不符合要求。)、 无规律(在InnoDB引擎下,UUID的无序性可能会引起数据位置频繁变动,严重影响性能。…