JUC并发编程——线程池学习:基础概念及三大方法、七大参数、四大拒绝策略(基于狂神说的学习笔记)

news2025/1/14 1:04:34

线程池

池化技术的本质:事先准备好一些资源,线程复用,用完即还,方便管理

默认大小:2

最大并发数max 根据电脑去设置,CPU密集型,IO密集型

线程池的好处:

  • 降低资源的消耗
  • 提高响应的速度,无需新建和销毁
  • 方便管理

线程池学习:3大方法、7大参数、4大拒绝策略

三大方法

Executors.newSingleThreadExecutor(); // 单个线程
Executors.newFixedThreadPool(5); // 创建一个固定的线程池,此处线程池的大小为5
Executors.newCachedThreadPool();// 可变线程池

以下示例展示了开辟线程池的三个方法,以及如何用线程池的方法创建线程

package pool;

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

// 三大方法
// 使用线程池,要使用线程池来创建线程
public class Demo01 {
    public static void main(String[] args) {
        // ExecutorService threadPool = Executors.newSingleThreadExecutor(); // 单个线程
        // ExecutorService threadPool = Executors.newFixedThreadPool(5); // 创建一个固定的线程池,此处线程池的大小为5
        ExecutorService threadPool = Executors.newCachedThreadPool();// 可变线程池
        try {
            for (int i = 0; i < 10; i++) {
                // execute 是线程池的执行方法,其中传入一个线程,可以用lambda表达式写run方法
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName());
                });
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // 线程池用完,程序结束,需要关闭线程池
            threadPool.shutdown();
        }


    }
}

Executors.newSingleThreadExecutor();的执行结果如下:

在这里插入图片描述

Executors.newFixedThreadPool(5);的执行结果如下:

在这里插入图片描述

Executors.newCachedThreadPool(); 的执行结果如下:
在这里插入图片描述

七大参数

源码分析:

//Executors.newSingleThreadExecutor()源码
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

// Executors.newFixedThreadPool(5) 源码
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

// Executors.newCachedThreadPool() 源码
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

/**
 *  可以发现,三大方法中,无论哪一个方法,实际上都调用了ThreadPoolExecutor方法
 * 所以本质上:三大方法是ThreadPoolExecutor方法的不同参数结果
*/


// ThreadPoolExecutor 源码   可以发现,该方法,有7个参数
public ThreadPoolExecutor(int corePoolSize, // 核心线程池大小
                          int maximumPoolSize, // 线程池大小(最大容纳量)
                          long keepAliveTime,// 超时了,没有人用就会释放
                          TimeUnit unit, // 超时单位
                          BlockingQueue<Runnable> workQueue,// 阻塞队列
                          ThreadFactory threadFactory,// 线程工厂,创建线程的,一般不用动
                          RejectedExecutionHandler handler// 拒绝策略
                         ) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

corePoolSize:核心线程永远开着,时时刻刻看可以使用

maximumPoolSize:线程池最大容量(线程池并非时时刻刻所有线程都开启的,时时刻刻一直开启的只有核心线程),当阻塞队列已满,线程池还有未开启线程时,线程池将会开启未启动的线程

keepAliveTime:当非核心线程在一定时间内都未被使用,则非核心线程池将关闭,也就是线程池释放。(等待超时)

unit:超时单位

workQueue:阻塞队列

threadFactory:线程工厂,创建线程,一般不动

handler:拒绝策略,当线程池中所有线程都在工作,且阻塞队列已满时,再进入的获取线程的请求的处理方法

手动创建一个线程池

ExecutorService threadPool = new ThreadPoolExecutor(
        2,
        5,
        3,
        TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(3),
        Executors.defaultThreadFactory(),
        new ThreadPoolExecutor.AbortPolicy()
);
public class Demo01 {
    public static void main(String[] args) {
        // 自定义线程池!工作 ThreadPoolExecutor
        // 自定义线程池的最大承载量为: blockingQueue + max
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                5,
                3,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy()
        );
        try {
            for (int i = 0; i < 10; i++) {
                // execute 是线程池的执行方法,其中传入一个线程,可以用lambda表达式写run方法
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName());
                });
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // 线程池用完,程序结束,需要关闭线程池
            threadPool.shutdown();
        }

    }
}

在上述例子中,因为for循环开启了10个线程,大于线程池的最大承载量(5+3=8),如果线程处理速度不够快,在最大承载量到达之前又来了请求,则会触发拒绝策略,而AbortPolicy()拒绝策略则是,当超过线程池最大承载量时,则会放弃之后请求,并抛出异常。

4大拒绝策略

在这里插入图片描述

  • AbortPolicy(): 拒绝请求,并抛出异常

  • CallerRunsPolicy():当线程池达到其最大容量并且所有工作线程都在忙的情况下,新的任务将被执行。CallerRunsPolicy策略意味着当调用线程池中的execute()方法来提交新任务时,如果线程池已经关闭或者达到饱和(即没有多余的线程可以处理新任务),那么新任务将在调用execute()方法的线程中直接执行。

    请注意,如果调用线程池的线程是主线程,这可能会导致主线程阻塞,直到任务完成。

  • DiscardPolicy:拒绝请求,但不抛出异常,进程正常运行

  • discardOldestPolicy();丢弃队列中最老的任务(即最早进入队列的任务),然后新任务将被加入队列。不会抛出异常

    请注意,这种策略可能会导致一些任务被丢弃,因此在使用时要特别注意。此处说明,丢弃最老的任务是指该任务直接被放弃,不会被重新执行,因此,在该策略中,有可能导致某些任务因被打断而无法完成

小结和拓展

  • 最大线程数到底该如何定义

    • CPU密集型, 根据CPU的核数来定义,几核CPU就开几核,可以保持CPU的效率最高
      Runtime.getRuntime().availableProcessors(); // 获取当前电脑的核数
    
    • IO密集型 判断程序中IO耗时特别大的线程的数量,最大线程数大于该数量即可

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

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

相关文章

【马蹄集】—— 概率论专题

概率论专题 目录 MT2226 抽奖概率MT2227 饿饿&#xff01;饭饭&#xff01;MT2228 甜甜花的研究MT2229 赌石MT2230 square MT2226 抽奖概率 难度&#xff1a;黄金    时间限制&#xff1a;1秒    占用内存&#xff1a;128M 题目描述 小码哥正在进行抽奖&#xff0c;箱子里有…

双目项目实战---测距(获取三维坐标和深度信息)

目录 1.简介 2.模块讲解 2.1 立体校正 2.1.1 校正目的 2.1.2 校正方法 2.2 立体匹配和视差计算 2.3 深度计算 3.完整代码 1.简介 双目视觉是一种通过两个摄像机&#xff08;或者两个镜头&#xff09;同时拍摄到同一个场景&#xff0c;再通过计算机算法来获取该场景深度…

C++ - 智能指针的定制删除器

前言 在上一篇C 文章当中&#xff0c;对 智能指针的使用&#xff0c;做了很详细的介绍&#xff0c;对 C11 和 C98 库当中实现的一些常用智能指针做了很详细的介绍&#xff0c;但是智能指针的使用还有一些拓展用法。上篇文章链接&#xff1a;C - 智能指针 - auto_ptr - unique_…

Stm32_标准库_16_串口蓝牙模块_手机与蓝牙模块通信_手机传入信息能对芯片时间日期进行更改

实现了手机发送信息给蓝牙模块&#xff0c;程序对数据进行分析拆解&#xff0c;并更新自身数据 main.c: #include "stm32f10x.h" // Device header #include "Delay.h" #include "OLED.h" #include "Serial.h" #include "Ti…

无人驾驶路径规划(一)全局路径规划 - RRT算法原理及实现

前言&#xff1a;由于后续可能要做一些无人驾驶相关的项目和实验&#xff0c;所以这段时间学习一些路径规划算法并自己编写了matlab程序进行仿真。开启这个系列是对自己学习内容的一个总结&#xff0c;也希望能够和优秀的前辈们多学习经验。 一、无人驾驶路径规划 众所周知&a…

Google Authenticator 和gitlab使用的方法配置Google AuthenticatorGoogle

Google Authenticator 和gitlab使用的方法 目录概述需求&#xff1a; 设计思路实现思路分析1.配置过程&#xff1a; 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a bette…

D201126 D201129 支持以太网高级物理层(APL)

D201126 D201129 支持以太网高级物理层(APL) 全球技术和软件领导者艾默生宣布了基于其无限自动化愿景&#xff0c;并作为其下一代以软件为中心的工业自动化架构的基础。新技术的发布将超越传统的控制系统&#xff0c;创建一个更先进的自动化平台&#xff0c;为人类和塑造世界…

【网络】网络层协议:IP(待更新)

文章目录 IP 协议1. 基本概念2. IP 报头解析 &#x1f53a;IP 的 网段划分&#xff1a; IP 协议 IP 不是面向字节流的&#xff0c;而是发送接收一个个的数据包 1. 基本概念 主机&#xff1a;配有 IP 地址的设备 路由器&#xff1a;配有单个或多个 IP 地址&#xff0c;且能进行…

【1314. 矩阵区域和】

目录 一、题目描述二、算法思想三、代码实现 一、题目描述 二、算法思想 三、代码实现 class Solution { public:vector<vector<int>> matrixBlockSum(vector<vector<int>>& mat, int k) {//先预处理数组int nmat.size();//行int mmat[0].size();…

flutter开发实战-下拉刷新与上拉加载更多实现

flutter开发实战-下拉刷新与上拉加载更多实现 在开发中经常遇到列表需要下拉刷新与上拉加载更多&#xff0c;这里使用EasyRefresh&#xff0c;版本是3.3.21 一、什么是EasyRefresh EasyRefresh可以在Flutter应用程序上轻松实现下拉刷新和上拉加载。它几乎支持所有Flutter Sc…

C++指针和引用

1、引用必须初始化&#xff0c;指针不必&#xff0c;所以说引用使你更安全的指针&#xff1b; 2、在汇编代码&#xff0c;指针和引用一模一样&#xff1b; 3、引用只有一级引用&#xff0c;没有多级引用&#xff1b; 4、引用必须引用一个能取地址的变量&#xff1b; 左值&…

第三章 内存管理 五、动态分区分配算法(首次适应算法、最佳适应算法、最坏适应算法、临近适应算法)

目录 一、首次适应算法 1、算法思想&#xff1a; 2、如何实现&#xff1a; 3、两种常用的数据结构: &#xff08;1&#xff09;空闲分区表、空闲分区链 4、例子 二、最佳适应算法 1、算法思想: 2、如何实现: 3、例子&#xff1a; 三、最坏适应算法 1、算法思想&…

蓝桥杯每日一题2023.10.16

数的分解 - 蓝桥云课 (lanqiao.cn) 题目描述 题目分析 最开始想使用dfs&#xff0c;发现范围过大无法在规定时间运行 #include<bits/stdc.h> using namespace std; const int N 2e5 10; int a[N], v[N], ans; void dfs(int dep, int sum, int start) {if(sum > 20…

Linux命令行下查看实时网速

Linux命令行下&#xff0c;用ifconfig可以看到每个网卡实时的收发的数据包了字节数&#xff0c;但并不方便查看当前网卡的实时网速。 近日偶得一个软件叫nload可以方便的在命令行下查看实时网速&#xff0c;不敢独享&#xff0c;分享给大家。 1、安装 sudo apt install nload…

第三章 内存管理 六、基本分页存储管理

目录 一、定义 二、例子 三、总结 一、定义 基本分页存储管理是一种操作系统的存储管理技术。在基本分页存储管理中&#xff0c;物理内存被划分成固定大小的块&#xff0c;称为页面&#xff08;Page&#xff09;&#xff0c;而程序代码和数据被分成相同大小的块&#xff0c;…

数据结构:二叉树(1)

目录 树的概念 树的表示形式 二叉树 二叉树的性质 题目 二叉树的存储 链式存储 初始化二叉树 二叉树的遍历 前序遍历&#xff1a;根&#x1f449;左子树&#x1f449;右子树 中序遍历&#xff1a;左子树&#x1f449;根&#x1f449;右子树 后序遍历&#xff1a;左子…

二十八、【滤镜】

文章目录 滤镜库Camera Raw滤镜神经网络滤镜(Neurel Filters)液化其他滤镜 滤镜库 可以在滤镜库中选择一些常用的滤镜方式&#xff0c;主要有六大类&#xff1a; Camera Raw滤镜 Camera Raw滤镜是photoshop最重要的一个滤镜&#xff0c;他帮助我们在摄影后期去进行颜色预处…

导数、偏导数、方向导数

一、导数 导数是描述函数变化率的数学概念。 导数的定义式: 那么就有一个问题&#xff0c;为什么求函数的最大值点是要对其自变量求导&#xff0c;并使其导数等于0 比如:求L(θ)3lnθ2ln(1-θ)的最大值点 既然导数表示函数的变化率&#xff0c;那么当函数L(θ)的导数等于0&…

Go语言基础之包

包&#xff08;package&#xff09; Go语言中支持模块化的开发理念&#xff0c;在Go语言中使用包&#xff08;package&#xff09;来支持代码模块化和代码复用。一个包是由一个或多个Go源码文件&#xff08;.go结尾的文件&#xff09;组成&#xff0c;是一种高级的代码复用方案…

构建高性能物联网数据平台:EMQX和CnosDB的完整教程

CnosDB 是一款高性能、高压缩率、高易用性的开源分布式时序数据库。主要应用场景为物联网、工业互联网、车联网和IT运维。所有代码均已在GitHub开源。本文将介绍如何使用EMQX 这一MQTT 服务器 CnosDB 构建物联网数据平台&#xff0c;实现物联网数据的实时流处理。 前言 在物联…