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() {
                    @Override
                    public void run() {
                        System.out.println("执行任务:" + id);
                    }

                });
            }
        }
    }
    }

运行结果:

代码解读:

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

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

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

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


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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HackTheBox - Medium - Windows - Authority

Authority 终于把easy的机器刷的八八九九了&#xff0c;开始新一轮的Medium机器&#xff0c;Medium难度以上的我都会写wp&#xff0c;保持学习&#xff0c;我的CRTO进度也快结束了。 Authority是一台中等难度的 Windows 计算机&#xff0c;它强调了错误配置、密码重用、在共享…

2023 英特尔On技术创新大会直播 |让更多人了解AI魅力

2023 英特尔On技术创新大会直播 |让更多人了解AI魅力 前言&#xff1a;主要领域:人工智能&#xff1a;使用 OpenVINO™ 落地边缘端生成式 AIOpenVINO™学习总结&#xff1a; 新一代 AI PC计算平台&#xff1a;新一代至强平台&#xff1a;边云协同&#xff1a;先进技术&#xff…

深入探索Git的高级技巧与神奇操作(分支,高效合并)

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 深入探索Git的高级技巧与神奇操作 前言强制推送的妙用1. 什么是强制推送&#xff1f;2. 为什么需要使用强制推送&#xff1f;3. 强制推送的风险与注意事项4. 如何正确、安全地执行强制推送步骤&#x…

JDK21+HADOOP3.2.2+Windows安装步骤

哈哈哈 最近转战大数据这块了&#xff0c;分享一下hadoop3.2.2的安装步骤 借鉴了不少大佬的文章&#xff0c;如有雷同&#xff0c;都是大佬们的 1.JDK安装 我选择的是JDK21 以下是下载网址和截图&#xff0c;这个没有太多的&#xff0c;一般下载最新的就可以 JDK: Java Down…

Golang学习之路一一Hello, World

Golang学习之路一一Hello, World golang工作目录下src下新建一个项目demo,如图: 在demo下新建hello_world.go文件,内容如下: package main //声明本文件的package名import "fmt" //import语言的fmt库——---用于输出func main() {fmt.Println("Hello, World!&…

【2.2操作系统】进程管理

目录 1.进程的基本概念2.进程的状态3.信号量与PV操作4.前趋图5.死锁6.银行家算法 1.进程的基本概念 &#x1f31f;进程是程序在一个数据集合上运行的过程&#xff0c;它是系统进行资源分配和调度的一个独立单位。它由程序块、进程控制块 (PCB) 和数据块三部分组成。 &#x1f…

一款视频行为分析系统,可轻松开发安全行为检测

系列版本介绍 基于视频行为分析系统v4系列版本可以在不用考虑流媒体音视频开发&#xff0c;编解码开发&#xff0c;界面开发等情况下&#xff0c; 只需要训练自己的模型&#xff0c;开发自己的行为算法插件&#xff0c;就可以轻松开发出任何你想要的安全行为检测&#xff0c;比…

浅谈云性能测试的关键要点

随着云计算的广泛应用&#xff0c;云性能测试成为确保云服务质量和性能的关键环节。云性能测试不仅涵盖了传统性能测试的方面&#xff0c;还需要考虑云环境的特殊性。以下是云性能测试的几个关键要点&#xff1a; 1. 模拟真实云环境 云环境具有虚拟化、弹性扩展等特点&#xff…

视频去水印怎么去掉?这三个去水印方法值得收藏

视频去水印怎么去掉&#xff1f;对于视频去水印&#xff0c;对于那些对去水印软件不是很熟悉的人来说&#xff0c;可能会感到有些困难。但是&#xff0c;不用担心&#xff0c;今天就来为大家介绍几种视频去水印软件和教你们视频去水印的详细步骤&#xff0c;让你们轻松去掉视频…

TOUGH系列软件实践技术应用

TOUGH系列软件是由美国劳伦斯伯克利实验室开发的&#xff0c;旨在解决非饱和带中地下水、热运移的通用模拟软件。和传统地下水模拟软件Feflow和Modflow不同&#xff0c;TOUGH系列软件采用模块化设计和有限积分差网格剖分方法&#xff0c;通过配合不同状态方程&#xff08;EOS模…

whisper深入-语者分离

文章目录 学习目标&#xff1a;如何使用whisper学习内容一&#xff1a;whisper 转文字1.1 使用whisper.load_model()方法下载&#xff0c;加载1.2 使用实例对文件进行转录1.3 实战 学习内容二&#xff1a;语者分离&#xff08;pyannote.audio&#xff09;pyannote.audio是huggi…

选数C语言

分析&#xff1a;这个题目主要解决两个问题 1.将数字选出来&#xff0c;不能重复的选出k个数字&#xff0c;并且要对选出来的数字进行求和 2.对求和的数字进行判断是否为素数&#xff0c;如果是就统计一次&#xff0c;如果不是就不统计 1.如果我们想选两两为一组的数字&#…

ansible远程操作主机功能和自动化运维

ansible 两个功能&#xff1a;1、远程操作主机功能 2、自动化运维&#xff08;play 剧本 yaml&#xff09; 简述&#xff1a; 是基于python开发的配置管理和应用部署工具。在自动化运维中&#xff0c;现在是异军突起。 Asible能批量配置&#xff0c;部署&#xff0c;管理上千…

锐捷 | AP利用路由网络发现AC

//AP与交换机进行测试获取信息 how lldp neighbors detail //在DHCP服务器中查看是否将IP分配给了AP 注&#xff1a;若AP为静态IP地址&#xff0c;则该命令无法查看 show ip dhcp binding | inc 300d.9e86.a9xx (到底啦~~~)

LLM之RAG实战(六)| 高级RAG 02:选择最佳embedding和重排序模型

在构建检索增强生成&#xff08;RAG&#xff09;Pipeline时&#xff0c;一个关键组件是Retriever。我们有多种embedding模型可供选择&#xff0c;包括OpenAI、CohereAI和开源sentence transformers。此外&#xff0c;CohereAI和sentence transformers还提供了几个重排序器。 但…

探索Qt 6.3:了解基本知识点和新特性

学习目标&#xff1a; 理解Qt6.3的基本概念和框架&#xff1a;解释Qt是什么&#xff0c;它的核心思想和设计原则。学会安装和配置Qt6.3开发环境&#xff1a;提供详细的步骤&#xff0c;让读者能够顺利安装和配置Qt6.3的开发环境。掌握Qt6.3的基本编程技巧&#xff1a;介绍Qt6.…

python接口自动化测试--requests使用和基本方法封装

之前学习了使用jmeterant做接口测试&#xff0c;并实现了接口的批量维护管理(大概500多条用例)&#xff0c;对“接口”以及“接口测试”有了一个基础了解&#xff0c;最近找了一些用python做接口测试的资料&#xff0c;一方面为了学习下如何使用python进行接口测试(如何做出一个…

MSA【3】:SAMed

文章目录 前言1. Abstract & Introduction1.1. Abstract1.2. Introduction 2. Methods2.1. Overview2.2. LoRA in image encoder2.3. Prompt encoder and mask decoder2.4. Training strategies2.4.1. Loss function2.4.2. Warmup2.4.3. AdamW optimizer 总结 前言 SAMed …

青藤销售云助力企业数智化销售

青藤销售云助力企业数智化销售覆盖&#xff1a; 1.人工自动外呼群呼 2.AI电销销售机器人自动筛选意向客户 3.crm企业微信智能客户管理运行系统 4.电话回拨系统不限拨打频次高频外呼不封号 5.语音通知系统覆盖工单提醒、发货提醒、缴费提醒等场景 6.手机号外显专号专用高接通率线…

【数据分享】2019-2023年我国地级市逐年新房房价数据(免费获取/Excel/Shp格式)

房价是一个城市发展程度的重要体现&#xff0c;一个城市的房价越高通常代表这个城市越发达&#xff0c;对于人口的吸引力越大&#xff01;因此&#xff0c;房价数据是我们在各项城市研究中都非常常用的数据&#xff01;之前我们分享了2019—2023年我国地级市逐月的新房房价数据…