JavaEE:线程池精讲

目录

一.什么是线程池

二.线程池的实现原理

🎈为什么要有工厂模式?

三.线程池的构造方法解读

🎈线程池的拒绝策略

四.自己实现一个线程池


一.什么是线程池

简单来说,线程池就好比一块鱼塘,鱼塘中的每条鱼就是一个线程。那么为什么要有这个线程池呢?就好比 一个“渣女\渣男”,当他和A在一起的时候,如果想和B在一起,那么就需要先想办法和A分手,再和B搞好关系,最终和B在一起。如果她和A谈的时候,已经找好了B C D,此时就可以直接拿来无缝衔接~~

其实线程池也就大概这个作用,里面存放一些线程,需要用的时候直接拿来使用。

二.线程池的实现原理

我们先来看线程池是如何创建的:

package Pool;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class threadPoolDemo {public static void main(String[] args) {ExecutorService executor = Executors.newSingleThreadExecutor();}
}

很明显,此处的线程池竟然不是 new 出来的,那么它是如何被实例化的呢?其实这里就使用了一种设计模式:工厂模式。

🎈为什么要有工厂模式?

其实工厂模式就时给Java中的构造方法填坑的,我们的构造方法其实时有很大缺陷的,我们来看以下例子。

我们期望这个Point类,初始化的时候能够传入 double x,double y,用来构造笛卡尔坐标系

我们又希望在不创建其他类的情况下,这个Point类, 初始化的时候能够传入 double r,double a,用来构造极坐标系。

但是构造方法也是方法,此时的方法由于参数个数和参数的类型都相同,就会编译失败,那么就没办法满足期望!

此时我们可以再写一个类:

此时这个类中又两个静态方法,一个是构造笛卡尔坐标系,并且返回。一个是构造及坐标系,并且返回对象。

那么我们就可以使用以下语句来分别调用:

Point p1 = PointFactory.makePintByXY(10,20) 

Point p2 = PointFactory.makePintByRA(12,63) 

此时通过PointFactory类,来给Point类传入需要的值就可以了。


那么线程池也是通过这样的方式来进行创建的:

三.线程池的构造方法解读

从Excutor这个工厂类的源码中可以得到以下:

其实线程的创建又被封装到了一个叫做ThreadPoolExecutor的类中

点开ThreadPoolExecutor,可以得到如下图片:

其中的每个参数的意思是这样的:

第一个是核心线程数, 第二个是最大线程数

线程池中的线程数目是可以动态变化的

范围就是【int corPoolSize. ~ int maxmumPoolSize】

什么是核心线程:

就好比一个公司中有正式员工(核心线程)和实习生,总的员工数目不能超过一定的值。当人手不够用就招实习生,这样既可以满足效率的需求,又可以避免过多的开销。

第三个是线程的可存活时间

第四个TimeUnit unit是用来设置非核心线程闲置超时时长(keepAliveTime)的单位。当一个非核心线程的闲置时间超过这个参数所设定的时长时,该线程就会被销毁掉。

第五个比较重要

第六个是线程池的拒绝策略,也就是当所有线程都处于忙碌状态,如果还往线程池中添加元素,线程池所做的操作。

这些构造方法,第一个和第五个以及第六个是需要重点掌握的。 

下面来单独讲讲第六个参数:拒绝策略

🎈线程池的拒绝策略

所谓的拒绝策略,其实就是如果线程池中每个线程都是处于忙碌的状态,如何应对新来的线程任务。

举个例子:如果我周一到周五都是满课,此时我一朋友让我给他去代课,那么此时我如何应对?此时就会有相应的应对策略:

  1. AbortPolicy(默认策略):这是默认的拒绝策略,它会抛出一个未检查的RejectedExecutionException,以指示任务被拒绝。也就是我本来都满课了,朋友还让我去代课,此时我就直接崩溃,代课和我自己的课我都不去上了,直接崩溃!
  2. CallerRunsPolicy:这个策略不会抛出异常。相反,它会将任务退回给调用线程,让它自己运行这个任务。 也就是让我朋友自己去上课。
  3. DiscardOldestPolicy:此策略会丢弃队列中等待最久的任务,并立即返回给调用者。也就是我丢弃我课程中一节课,去给他代课。
  4. DiscardPolicy:这个策略会静默地丢弃被拒绝的任务。也就是说,它不会抛出任何异常,也不会通知任务被拒绝。 也就是我拒绝去给他代课,我自己上自己的课。然后我朋友也不去上课了,那么这个课(任务) 也就黄了。

四.自己实现一个线程池

  实现线程池一个最关键的步骤就是拒绝策略,那么说明拒绝策略呢?

由于之前学过阻塞队列的知识,这里就先用阻塞队列来实现以下。

那么这个就是一种自己定义的新的拒绝策略,那就是一直等待~

package Pool;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;class MyPoolDemo {//一个队列BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);//通过这个方法,把任务添加到队列当中public void submit(Runnable task) throws InterruptedException {queue.put(task); //往阻塞队列中放入元素}public MyPoolDemo(int n) throws InterruptedException {//构造方法for (int i = 0; i < n; i++) {Thread t = new Thread(() -> {//让这个线程从队列中消费任务并且进行执行try {//如果队列中没有元素,那就阻塞等待//一旦队列中有了任务,那么就立即执行take方法获取到任务并且开始执行Runnable task = task = queue.take();task.run();} catch (InterruptedException e) {throw new RuntimeException(e);}});t.start();}}}
public class RunDemo {public static void main(String[] args) throws InterruptedException {/*** 步骤理解:* 1.创建线程池并且指定线程数目是 20 ,在实例化线程池的时候已经创建好了20个线程* 2.这20个线程都在等待 take 获取到任务队列中的任务* 3.for 语句 循环 1000次,每次循环都会提交任务到任务队列* 4.一但任务队列里面有元素,这20个线程就会立马获取到,并且执行*/MyPoolDemo myPoolDemo = new MyPoolDemo(20);int taskCount = 1000;while (true) {for (int i = 0; i < taskCount; i++) {int id = i;myPoolDemo.submit(new Runnable() {@Overridepublic void run() {System.out.println("执行任务:" + id);}});}}}}

运行结果:

代码解读:

1.线程池里的线程是需要执行任务的,这个任务可以放到    BlockingQueue 这个阻塞队列中。为什么要使用阻塞队列呢?当线程池中的线程都在工作,此时就直接等待阻塞。

2.submit 方法接受一个实例化好的Runnable类型的任务,负责往队列中添加元素

3. MyPoolDemo(int n) 是这个类的构造放法,当实例化这个类的时候,被指定的 n 就是要创建的线程数量。

4. 由运行结果可以得出:当线程数量为20的时候,可以看到任务被随即执行完了。


总结:Java线程池是Java并发编程中一个重要的概念,它用于管理和控制线程的创建、销毁,以及任务提交和执行。线程池的主要目的是减少创建和销毁线程的开销,提高性能。 

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

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

相关文章

如何在Eclipse中安装WindowBuilder插件,详解过程

第一步&#xff1a;找到自己安装eclipse的版本&#xff0c;在Help-关于eclipse里面&#xff0c;即Version 第二步&#xff1a;去下面这个网站找到对应的 link&#xff08;Update Site&#xff09;&#xff0c;这一步很重要&#xff0c;不然版本下载错了之后还得删除WindowBuil…

常用的Webstrom插件

Active Tab Highlighter 高亮选中的tab Atom Material Icons 图标&#xff0c;个人觉得还是挺好看&#xff0c;各类分拣也能区分的很明显 Code Remark 代码标记 Gitmoji Plus git提交时候的小图标 GitToolBox git工具&#xff0c;免费版本就支持鼠标在哪一行就显示提交的信…

Scala多线程爬虫程序的数据可视化与分析实践

一、Scala简介 Scala是一种多种类型的编程语言&#xff0c;结合了针对对象编程和函数式编程的功能。它运行在Java虚拟机上&#xff0c;具有强大的运算能力和丰富的库支持。Scala常用于大数据处理、并发编程和Web应用程序开发。其灵活性和高效性编程成为编写多线程爬虫程序的理…

Python开发GUI常用库PyQt6和PySide6介绍之一:概述

Python开发GUI常用库PyQt6和PySide6介绍之一&#xff1a;概述 Python开发GUI有许多选择&#xff0c;下面是常见的选择&#xff1a; Tkinter&#xff1a;Tkinter是Python标准库中的一个GUI工具包&#xff0c;易于学习和使用。它提供了丰富的组件和布局选项&#xff0c;适用于简…

企业办公加密系统中——全透明加密和半透明加密的区别

PC端访问地址&#xff1a; www.drhchina.com 天锐绿盾数据防泄密系统中的全透明加密和半透明加密的区别如下&#xff1a; 全透明加密是采用驱动层动态加解密技术&#xff0c;对企业内部所有涉密文档进行强制加密处理&#xff0c;从文件创建开始即可自动加密保护。加密文档在加…

STM32 CAN多节点组网项目实操 挖坑与填坑记录2

系列文章&#xff0c;持续探索CAN多节点通讯&#xff0c; 上一篇文章链接&#xff1a; STM32 CAN多节点组网项目实操 挖坑与填坑记录-CSDN博客文章浏览阅读120次。CAN线性组网项目开发过程中遇到的数据丢包问题&#xff0c;并尝试解决的记录和推测分析。开发了一个多节点线性…

实战 | OpenCV传统方法实现密集圆形分割与计数(详细步骤 + y源码)

导 读 本文主要介绍基于OpenCV传统方法实现密集圆形分割与计数应用,并给详细步骤和代码。 背景介绍 实例图片来源于网络,目标是分割下图中圆形目标并计数。 本文实现效果如下: 实现步骤 【1】灰度转换 + 均值滤波 + 二值化,得到参考背景 img = cv2.imread(src.jpg)c…

基于深度学习的人脸测距&社交距离过近警报系统

1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 研究背景与意义 近年来&#xff0c;随着深度学习技术的快速发展&#xff0c;人脸识别技术在各个领域得到了广泛应用。其中&#xff0c;人脸测距和社交距离过近警报系统成为了人们…

两个月准备信息系统项目管理师来得及吗?

可以尝试加快进度&#xff01;但是时间稍微有些紧迫。当然备考时间也不宜过长&#xff0c;2-3个月时间完全足够。对于没有项目经验的初学者考生们&#xff0c;建议提前做好准备&#xff0c;特别要注意时间安排~ 在备考期间&#xff0c;不要受到外界负面言论的影响&#xff0c;比…

Mysql数据库的基础知识和yum安装步骤

MySQL数据库介绍 什么是数据库DB&#xff1f; DB的全称是database&#xff0c;即数据库的意思。数据库实际上就是一个文件集合&#xff0c;是一个存储数据的仓库&#xff0c;数据库是按照特定的格式把数据存储起来&#xff0c;用户可以对存储的数据进行增删改查操作&#xff1…

[C++] 多态(下) -- 多态原理 -- 动静态绑定

文章目录 1、多态原理2、动态绑定和静态绑定3、单继承和多继承关系的虚函数表3.1 单继承中的虚函数表5.2 多继承中的虚函数表 上一篇文章我们了解了虚函数表&#xff0c;虚函数表指针&#xff0c;本篇文章我们来了解多态的底层原理&#xff0c;更好的理解多态的机制。 [C] 多态…

数据分析场景下,企业大模型选型的思路与建议

来源/作者&#xff1a;爱分析 随着大模型带来能力突破&#xff0c;让AI与数据分析相互结合&#xff0c;使分析结果更好支撑业务&#xff0c;促进企业内部数据价值释放&#xff0c;成为了当下企业用户尤为关注的话题。本次分享主要围绕数据分析场景下大模型底座的选型思路&#…

opencv 入门一(显示一张图片)

头文件添加如下&#xff1a; 库目录添加如下&#xff1a; 依赖的库如下&#xff1a; #include <iostream> #include "opencv2/opencv.hpp" int main(int argc,char ** argv) { cv::Mat img cv::imread(argv[1], -1); if (img.empty()) return -1; …

sourcetree 无效的源路径 细节提示:系统找不到指定的文件

工具–>选项–>git 直接下拉到底 点击红框&#xff0c;重新下载一个内嵌git就可以了 我感觉是因为改变了原有git安装路径的问题

MFC 窗口创建过程与消息处理

目录 钩子简介 代码编写 窗口创建过程分析 消息处理 钩子简介 介绍几个钩子函数&#xff0c;因为它们与窗口创建工程有关 安装钩子函数 HHOOK SetWindowsHookExA([in] int idHook,[in] HOOKPROC lpfn,[in] HINSTANCE hmod,[in] DWORD dwThreadId ); 参数说明…

深度学习笔记_7经典网络模型LSTM解决FashionMNIST分类问题

1、 调用模型库&#xff0c;定义参数&#xff0c;做数据预处理 import numpy as np import torch from torchvision.datasets import FashionMNIST import torchvision.transforms as transforms from torch.utils.data import DataLoader import torch.nn.functional as F im…

是什么导致了我孩子的听力损失?

是什么导致了我孩子的听力损失&#xff1f; 有些婴儿天生就有听力损失&#xff0c;这被称为先天性听力损失。许多不同的因素都可能导致这种类型的听力损失&#xff0c;但并不总是能够确定确切的原因。在大约一半的病例中&#xff0c;原因是遗传的&#xff0c;也就是说&#xff…

深度学习 tensorflow基础介绍

深度学习是一种基于人工神经网络的机器学习方法&#xff0c;其目标是通过模仿人脑的结构和功能&#xff0c;实现对大量复杂数据的学习和理解。它可以在图像识别、语音识别、自然语言处理等领域取得惊人的成就。 深度学习的引入引出了TensorFlow&#xff0c;它是一个由Google Br…

DBeaver Ultimate for Mac/win:掌握数据库的终极利器,助您高效管理数据!

在当今数字化时代&#xff0c;数据管理变得越来越重要。而作为一款功能强大的数据库管理工具&#xff0c;DBeaver Ultimate&#xff08;简称DBU&#xff09;助您轻松应对各种复杂的数据管理任务。无论您是数据库管理员、开发人员还是数据分析师&#xff0c;DBU都能为您提供全面…

带你学C语言~指针(2)

目录 &#x1f3c9;前言 &#x1f680; 数组名的理解 &#x1f680;使用指针访问数组 ✈一维数组传参的本质 ✈冒泡排序 &#x1f3c6;二级指针 &#x1f3c6;指针数组 &#x1f3c6;指针数组模拟二维数组 &#x1f389;结束语 &#x1f3c9;前言 上一章&#xff0c;小…