【Java开发】JUC进阶 04:线程池详解

news2024/11/16 3:31:28

1 线程池介绍

由于频繁创建销毁线程要调用native方法比较消耗资源,为了保证内核的充分利用,所以引入了线程池的概念。

📌 线程池优点

  • 降低资源消耗

  • 提高响应速度

  • 方便管理

📌 创建线程池

  • 使用Executors创建

  • 使用ThreadPoolExecutor创建

📌 工作流程

2 Executors创建线程池

📌 三大方法

  • ExecutorService threadPool = Executors.newSingleThreadExecutor();--创建单个线程

  • ExecutorService threadPool = Executors.newFixedThreadPool(5);--创建固定大小的线程池

  • ExecutorService threadPool = Executors.newCachedThreadPool();--创建不固定大小的线程池

📌 代码举例

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorsDemo {
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
//        ExecutorService threadPool = Executors.newFixedThreadPool(5);
//        ExecutorService threadPool = Executors.newCachedThreadPool();

        try {
            //使用线程池创建线程池
            for (int i = 0; i < 5; i++) {
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" Ok");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

3 ThreadPoolExecutor创建线程池

📌 七大参数说明

  1. corePoolSize:核心线程数量,线程池维护线程的最少数量

  1. maximumPoolSize:线程池维护线程的最大数量

  1. keepAliveTime:线程池除核心线程外的其他线程的最长空闲时间,超过该时间的空闲线程会被销毁

  1. unit:keepAliveTime的单位,TimeUnit中的几个静态属性:NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS

  1. workQueue:线程池所使用的任务缓冲队列

  1. threadFactory:线程工厂,用于创建线程,一般用默认的即可

  1. handler:线程池对拒绝任务的处理策略

📢 官方推荐ThreadPoolExecutor创建线程池

阿里代码规范如下:

源码解析👇

//1.newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
//2.newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
//3.newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE, //21亿
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

public ThreadPoolExecutor(int corePoolSize, // 核心线程数
                          int maximumPoolSize, // 最大线程数 
                          long keepAliveTime, // 存活时间
                          TimeUnit unit, // 存活时间单位
                          BlockingQueue<Runnable> workQueue, // 阻塞队列
                          ThreadFactory threadFactory, // 线程工厂
                          RejectedExecutionHandler handler //拒绝策略) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         threadFactory, defaultHandler);
}

可以看到Executors创建线程池的三个方法都调用了ThreadPoolExecutor!

4 四大拒绝策略

📌 UML图

📌 要点

  • AbortPolicy:被拒绝了抛出异常

  • CallerRunsPolicy:使用调用者所在线程执行,就是哪里来的回哪里去

  • DiscardOldestPolicy: 当触发拒绝策略,只要线程池没有关闭的话,丢弃阻塞队列 workQueue 中最老的一个任务,并将新任务加入

  • DiscardPolicy:直接丢弃,其他啥都没有

4.1 AbortPolicy

ThreadPoolExecutor 默认AbortPolicy拒绝策略

public class AbortPolicyDemo {
    public static void main(String[] args) {
        //自定义线程池!
        ExecutorService threadPool = new ThreadPoolExecutor(
                3,//核心线程为3
                5,//最大线程数是5,包括核心线程
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),//阻塞队列数
                Executors.defaultThreadFactory());

        try {
            for (int i = 0; i < 10; i++) {
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" OK");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

控制台输出:

4.2 CallerRunsPolicy

public class CallerRunsPolicyDemo {
    public static void main(String[] args) {
        //自定义线程池!
        ExecutorService threadPool = new ThreadPoolExecutor(
                3,//核心线程为3
                5,//最大线程数是5,包括核心线程
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),//阻塞队列数
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());

        try {
            for (int i = 0; i < 10; i++) {
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" OK");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

控制台输出:

📢 可以看到,多出来的两个线程回到了主线程,因为这10个线程都是从主线程丢到线程池的。

4.3 DiscardPolicy

它会尝试丢掉任务队列中的最早任务,也不会抛出异常。

public class DiscardOldestPolicyDemo {
    public static void main(String[] args) {
        //自定义线程池!
        ExecutorService threadPool = new ThreadPoolExecutor(
                3,//核心线程为3
                5,//最大线程数是5,包括核心线程
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),//阻塞队列数
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardOldestPolicy());

        try {
            for (int i = 0; i < 8; i++) {
                threadPool.execute(()->{
                    try {//添加等待时间,防止过早结束
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" OK");
                });
            }
            //第九个线程,他会尝试插入,替代最老的线程
            threadPool.execute(()->{
                System.out.println(Thread.currentThread().getName()+" OK11");
            });
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

控制台输出:

📢 可以看到总数还是8个线程,而且“0K11”输出了,说明其中一个线程被顶掉了。

4.4 DiscardOldestPolicy

public class DiscardPolicyDemo {
    public static void main(String[] args) {
        //自定义线程池!
        ExecutorService threadPool = new ThreadPoolExecutor(
                3,//核心线程为3
                5,//最大线程数是5,包括核心线程
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),//阻塞队列数
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardPolicy());

        try {
            for (int i = 0; i < 8; i++) {
                threadPool.execute(()->{
                    try {//添加等待时间,防止过早结束
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+" OK");
                });
            }
            //第九个线程,他会尝试插入,替代最老的线程
            threadPool.execute(()->{
                System.out.println(Thread.currentThread().getName()+" OK11");
            });
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            threadPool.shutdown();
        }
    }
}

控制台输出:

📢 第9个线程被丢掉了!

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

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

相关文章

Git图解-为啥是Git?怎么装?

目录 零、学习目标 一、版本控制 1.1 团队开发问题 1.2 版本控制思想 1.2.1 版本工具 二、Git简介 2.1 简介 2.2 Git环境的搭建 三、转视频版 零、学习目标 掌握git的工作流程 熟悉git安装使用 掌握git的基本使用 掌握分支管理 掌握IDEA操作git 掌握使用git远程仓…

【教程】记录Typecho Joe主题升级与Joe魔改版

目录 升级Joe 其他魔改版 Joe主题挺好看的&#xff0c;很早之前我就装了。后来官方升级了主题&#xff0c;但没有给升级教程。这里记录一下我的升级过程&#xff0c;供大家参考。 Joe Github&#xff1a;GitHub - HaoOuBa/Joe: A Theme of Typecho 升级站点&#xff1a;小锋学…

WSL2使用Nvidia-Docker实现CUDA版本自由切换

众所周知&#xff0c;深度学习的环境往往非常麻烦&#xff0c;经常不同的项目所依赖的 torch、tensorflow 包对 CUDA 的版本也有不同的要求&#xff0c;Linux 下进行 CUDA 的管理比较麻烦&#xff0c;是一个比较头疼的问题。 随着 WSL2 对物理机显卡的支持&#xff0c;Nvidia-…

用二极管和电容过滤电源波动,实现简单的稳压 - 小水泵升压改装方案

简而言之&#xff0c;就是类似采样保持电路&#xff0c;当电源电压因为电机启动而骤降时&#xff0c;用二极管避免电容电压跟着降低&#xff0c;从而让电容上连接的低功耗芯片有一个比较稳定的供电电压。没什么特别的用处&#xff0c;省个LDO 吧&#xff0c;电压跌幅太大的时候…

最详细Sql语句优化大汇总 面试必问 含解释

欢迎补充和纠正&#xff01;&#xff01;&#xff01; 目录 欢迎补充和纠正&#xff01;&#xff01;&#xff01; 基础知识 相关索引的创建 一条sql语句的执行过程 sql语句关键字的执行顺序 SQL优化 使用explain来分析Sql语句 尽量用varchar代替char 使用数值代替字符…

Vector - CAPL - 定时器函数和使用

定时器在C语言中的使用我想学习过C编程的都不会陌生&#xff0c;它能够提供延时&#xff0c;完成等待一定的时间&#xff1b;它也可以实现多线程的操作&#xff0c;并行实行某些软件功能。那在CAPL中&#xff0c;定时器又能做哪些工作呢&#xff1f;又是怎么使用的呢&#xff1…

SPringCloud:Nacos快速入门及相关属性配置

目录 一、Nacos快速入门 1、在父工程中添加spring-cloud-alilbaba的管理依赖 2、如果有使用eureka依赖&#xff0c;将其注释 3、添加nacos的客户端依赖 4、修改yml文件&#xff0c;注释eureka配置 5、启动测试 二、Nacos相关属性配置 1、Nacos服务分级存储 2、根据集群…

ELasticsearch基本使用——基础篇

1.初识elasticsearch1.1.了解ES1.1.1.elasticsearch的作用elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能&#xff0c;可以帮助我们从海量数据中快速找到需要的内容例如&#xff1a;在GitHub搜索代码在电商网站搜索商品在谷歌搜索答案在打车软件搜索…

Oracle中merge Into的用法

Oracle中merge Into的用法 使用场景 在操作数据库时&#xff0c;数据存在的情况下&#xff0c;进行update操作&#xff1b;不存在的情况下&#xff0c;进行insert操作&#xff1b;在Oracle数据库中&#xff0c;能够使用merge into来实现。 基本语法 merge into table_name …

Go项目的目录结构基本布局

前言 随着项目的代码量在不断地增长&#xff0c;不同的开发人员按自己意愿随意布局和创建目录结构&#xff0c;项目维护性就很差&#xff0c;代码也非常凌乱。良好的目录与文件结构十分重要&#xff0c;尤其是团队合作的时候&#xff0c;良好的目录与文件结构可以减少很多不必要…

HashSet原理

HashSet原理HashSet原理1.概述2.底层代码3.原理图解4.总结4.1: 1.7原理总结4.2: 1.8原理总结HashSet原理 1.概述 ​ HashSet 实现 Set 接口&#xff0c;由哈希表&#xff08;实际上是一个 HashMap 实例&#xff09;支持。它不保证 set 的 迭代顺序&#xff1b;特别是它不保证…

MathType7最新版免费数学公式编辑器

话说我也算是 MathType准资深(DB)用户了,当然自从感觉用DB不好之后,我基本上已经抛弃它了,只是前不久因为个别原因又捡起来用了用,30天试用期间又比较深入的折腾了下,也算是变成半个MathType砖家,coco玛奇朵简单介绍一下这款软件:在很可能看到这儿的你还没有出生的某个年月&…

汇编语言程序设计(三)之汇编程序

系列文章 汇编语言程序设计&#xff08;一&#xff09; 汇编语言程序设计&#xff08;二&#xff09;之寄存器 汇编程序 经过上述课程的学习&#xff0c;我们可以编写一个完整的程序了。这章开始我们将开始编写完整的汇编语言程序&#xff0c;用编译和连接程序将它们连接成可…

反转链表——C语言经典单链表题目

首先&#xff0c;把oj题目的链接放在这&#xff0c;大家可以先去练习一下&#xff0c;再来看解析。 反转链表——力扣 题目&#xff1a;给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 现在让我们来看一下解决代码&#xff0c;先看一下我写…

网上销售笔记本系统

技术&#xff1a;Java、JSP等摘要&#xff1a;本文讲述了基于B/S模式的笔记本电脑在线销售系统的设计与实现。所谓的笔记本电脑在线销售系统是通过网站推广互联企业的笔记本电脑和技术服务&#xff0c;并使客户随时可以了解企业和企业的产品&#xff0c;为客户提供在线服务和订…

04_Apache Pulsar的可视化监控管理、Apache Pulsar的可视化监控部署

1.4.Apache Pulsar的可视化监控管理 1.4.1.Apache Pulsar的可视化监控部署 1.4.Apache Pulsar的可视化监控管理 1.4.1.Apache Pulsar的可视化监控部署 第一步&#xff1a;下载Pulsar-Manager https://archive.apache.org/dist/pulsar/pulsar-manager/pulsar-manager-0.2.0/…

OpenCV-Python学习(22)—— OpenCV 视频读取与保存处理(cv.VideoCapture、cv.VideoWriter)

1. 学习目标 学习 OpenCV 的视频的编码格式 cv.VideoWriter_fourcc&#xff1b;学会使用 OpenCV 的视频读取函数 cv.VideoCapture&#xff1b;学会使用 OpenCV 的视频保存函数 cv.VideoWriter。 2. cv.VideoWriter_fourcc()常见的编码参数 2.1 参数说明 参数说明cv.VideoWr…

用代码实现解析解的方式求解_梯度下降法思路_导函数有什么用_接23节---人工智能工作笔记0026

这里24节,25节,介绍了一下人工智能高等数学要学习的一些内容,初步了解了一下,微积分中用到的知识~微分~以及导数这里... 然后接着23节,我们还是继续,走人工智能的主线,先把整体的人工智能的内容学习一遍,然后再去回去看数学知识更有目的性. 然后首先来回顾一下,这里机器学习,其…

为什么我给蓝牙芯片KT6368A发送AT指令没有反应呢

目录 一、问题描述简介 为什么我给蓝牙芯片KT6368A发送AT指令没有反应呢&#xff1f;查看了文档也没找到具体的解决办法 二、详细描述 这个问题&#xff0c;主要分为两个部分去考虑 KT6368A的芯片&#xff0c;上电是否正常&#xff0c;也就是有没有跑起来&#xff0c;这个详…

【ROS学习笔记11】ROS元功能包与launch文件的使用

【ROS学习笔记11】ROS元功能包与launch文件的使用 文章目录【ROS学习笔记11】ROS元功能包与launch文件的使用前言一、ROS元功能包二、ROS节点运行管理launch文件2.1 launch文件标签之launch2.2 launch文件标签之node2.3 launch文件标签之include2.4 launch文件标签之remap2.5 l…