【Java并发】聊聊创建线程池的几种方式以及实际生产如何应用

上一篇文章,主要讲述了如果通过线程池进行执行任务,以及相关的核心流程,线程执行框架本身提供了一系列的类,封装了线程创建、关闭、执行、管理等跟业务逻辑无关的代码逻辑,一方面将业务和非业务逻辑进行解耦合,另一方面也可以达到复用。

Executor、ExecutorService、Executors

Executor和 ExecutorService都是接口,前者定义了execute方法,后者添加了一些基础的线程关闭提交等方法。Executors是一个工具类。用来创建执行器。

public interface Executor {
    void execute(Runnable command);
}

在这里插入图片描述

newFixedThreadPool

newFixedThreadPool 是一个创建固定线程池的,核心线程和最大都是nThreads,可以看出都是核心线程池,所以线程都不会销毁。但是工作队列 LinkedBlockingQueue 却是一个无界队列,默认是 Integer.MAX_VALUE。所以如果是使用这种方式,虽然工作线程是固定的数量,但是任务队列是无界的,如果人多比较多,那么处理慢的话,队列可能快速挤压,撑爆内存OOM。永远不会执行拒绝策略。

    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }

newSingleThreadExecutor

创建一个单线程进行处理,核心线程就是1,最大线程数也是1。但是任务队列也是Integer的最大值。

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

newCachedThreadPool

核心线程是0,最大线程是Integer的最大值,超过60S就会销毁。但是任务队列是长度为0的阻塞队列,不存储任何的等待执行的任务,如果线程池有空闲线程,那么空闲线程进行处理,没有的话,就会创建新的线程进行处理。

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

newScheduledThreadPool

newScheduledThreadPool 定时或者周期性的执行任务,线程池的核心线程大小为corePoolSize ,最大线程池大小为 Integer.MAX_VALUE

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }

    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

在阿里的手册中,也标记的有 1.要使用线程池进行处理任务,2.不要使用Executors去创建任务。Fixed 和single的任务队列是Integer的最大值,有大量请求的时候可能OOM, cache的最大线程池是Integer.MaxValue值,会频繁创建线程。
在这里插入图片描述

在这里插入图片描述
上述的方式其实就有问题,没有定义任务队列的大小,如果任务过多的时候,其实会撑爆内存,OOM。

OOM问题

执行之后,会循环1亿次,然后因为使用的是cached所以会不断的创建线程处理任务。最终

Exception in thread “pool-1-thread-63” java.lang.OutOfMemoryError: Java heap space

	private void oom1() throws InterruptedException {
        ExecutorService threadPool = Executors.newCachedThreadPool();

        for (int i = 0; i < 100000000; i++) {
            threadPool.execute(() -> {
                String payload = IntStream.rangeClosed(1, 1000000)
                        .mapToObj(__ -> "a")
                        .collect(Collectors.joining("")) + UUID.randomUUID().toString();
                try {
                    TimeUnit.HOURS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(payload);
            });
        }
        threadPool.shutdown();
        threadPool.awaitTermination(1, TimeUnit.HOURS);
    }

实际应用

所以在实际的开发中,如果需要使用多线程进行处理任务,那么一定不要使用juc内置的方法,而要根据自己业务的QPS 衡量下 应该设置的核心、最大、回收策略、工作队列的类型等。一般都需要设置有届的工作队列和可控的线程数,
1.手动创建 2.定义自定义的线程名

    public static MdcThreadPoolExecutor newCustomThreadPool(int corePoolSize, int maximumPoolSize, int capacity, String featureOfGroup) {
        return new MdcThreadPoolExecutor(corePoolSize, maximumPoolSize,
                0L, new LinkedBlockingQueue<>(capacity), featureOfGroup);
    }

    private MdcThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
                                  long keepAliveTime, BlockingQueue<Runnable> workQueue, String featureOfGroup) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, workQueue,
                new NamedThreadFactory(featureOfGroup));
        this.featureOfGroup = featureOfGroup;
    }

  ExecutorService service = MdcThreadPoolExecutor.newCustomThreadPool(6, 6, 50, "xxxx");


 public class NamedThreadFactory implements ThreadFactory {

    private final String namePrefix;
    private final AtomicInteger nextId = new AtomicInteger(1);

    public NamedThreadFactory(String featureOfGroup) {
        namePrefix = "NamedThreadFactory's " + featureOfGroup + "-Worker-";
    }
    
    @Override
    public Thread newThread(Runnable task) {
        String name = namePrefix + nextId.getAndDecrement();
        Thread thread = new Thread(null, task, name, 0);
        if (thread.isDaemon()) {
            thread.setDaemon(false);
        }
        if (thread.getPriority() != Thread.NORM_PRIORITY) {
            thread.setPriority(Thread.NORM_PRIORITY);
        }
        return thread;
    }
}

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

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

相关文章

Docker简介与安装

Docker简介 1.什么是docker docker是解决了运行环境和配置问题的软件容器。是一种方便做持续集成并有助于整体发布的容器虚拟化技术。docker官网&#xff1a;http://www.docker.com 2.与传统虚拟技术的区别 传统虚拟机技术是虚拟出一套硬件后&#xff0c;在其上运行一个完整…

关于pytorch以及相关包的安装教程

一.查看自己电脑的配置 首先查看自己电脑的cuda的版本&#xff0c;WinR,敲入cmd打开终端 输入nvidia-smi&#xff0c;查看自己电脑的显卡等配置 这里要说明一下关于这个CUDA,它具有向后兼容性&#xff0c;这意味着支持较低版本的 CUDA 的应用程序通常也可以在较高版本的 CUD…

简单介绍一下js中的构造函数、原型对象prototype、对象原型__proto__、原型链

构造函数 function Star (uname, age){this.uname unamethis.age agethis.sing function(){ log(唱歌~) }}let xzq new Star(薛之谦, 30)let ldh new Star(刘德华, 20)log(ldh) // { uname: 刘德华, age: 20, sing: f }ldh.sing() // 唱歌~log(ldh.sing xzq.sing) // fal…

2023年c语言程序设计大赛

7-1 这是一道送分题 为了让更多的同学参与程序设计中来&#xff0c;这里给同学们一个送分题&#xff0c;让各位感受一下程序设计的魅力&#xff0c;并祝贺各位同学在本次比赛中取得好成绩。 注&#xff1a;各位同学只需将输入样例里的代码复制到右侧编译器&#xff0c;然后直…

【2023传智杯】第六届传智杯程序设计挑战赛AB组-ABC题解题分析详解【JavaPythonC++解题笔记】

本文仅为第六届传智杯程序设计挑战赛-题目解题分析详解的解题个人笔记,个人解题分析记录。 本文包含:第六届传智杯程序设计挑战赛题目、解题思路分析、解题代码、解题代码详解 文章目录 一.前言二.比赛题目(AB俩组)A题题目B题题目C题题目三.解题代码A题解题思路解题代码【J…

Qt 串口编程-从入门到实战

1. Qt 串口通信流程解析 1.1 串行通信和并行通信对比 并行通信适合距离较短的通信&#xff0c;且信号容易受干扰&#xff0c;成本高串口通讯-设备&#xff08;蓝牙&#xff0c; wifi&#xff0c; gprs&#xff0c; gps&#xff09; 1.2 Qt 串口通信具体流程 1. 创建 QSerial…

redis运维(二十一)redis 的扩展应用 lua(三)

一 redis 的扩展应用 lua redis加载lua脚本文件 ① 调试lua脚本 redis-cli 通过管道 --pipe 快速导入数据到redis中 ② 预加载方式 1、错误方式 2、正确方式 "案例讲解" ③ 一次性加载 执行命令&#xff1a; redis-cli -a 密码 --eval Lua脚本路径 key …

从程序员到解决方案工程师:一次跨界的职场冒险

在科技行业里&#xff0c;程序员和解决方案工程师是两个非常常见的职业。虽然这两个职业都需要一定的行业理解和问题解决能力&#xff0c;但它们的工作内容和职责却有很大的不同。 那么&#xff0c;如果一名程序员决定转行做一名解决方案工程师&#xff0c;他会经历怎样的体验…

03 _ 系统设计目标(一):如何提升系统性能?

提到互联网系统设计&#xff0c;可能听到最多的词就是“三高”&#xff0c;也就是“高并发”“高性能”“高可用”&#xff0c;它们是互联网系统架构设计永恒的主题。这里将整体探讨下高并发系统设计的目标&#xff0c;然后在此基础上&#xff0c;探讨下&#xff1a;如何提升系…

如何使用 WordPress搭建一个博客?详细搭建教程

域名服务器环境WordPress程序个人博客或企业官网等 前言&#xff1a;域名服务器是需要一些费用域名是一年服务器需要租赁3个月以上的才有备案码推荐购买一年,WordPress主题和插件有免费和付费的看自己需求 一、环境已经安装好了已经在运营项目咋就跳过从建站开始 二、进入根目录…

曲线拟合:走进数据建模中的艺术与科学

在现代科学和工程领域&#xff0c;曲线拟合是一项重要的数据分析技术&#xff0c;它可以通过数学模型来近似描述实际数据中的复杂关系。本文将详细介绍曲线拟合的基本概念、方法和应用领域&#xff0c;并探究其在数据建模中的艺术与科学。 第一节&#xff1a;曲线拟合的基本概…

IBM X3650M4安装ESXI6.5卡在/lsl_mr3.v00

环境&#xff1a;IBM X3650M4服务器双盘配置raid1&#xff0c;通过rufus制作启动U盘&#xff0c;安装VMware Vsphere 5.5系统 问题&#xff1a;卡在/lsi_mr3.v00界面无法往下运行&#xff08;两台配置一样的机器遇到同样的问题&#xff09; 解决方案&#xff1a; 直接在U盘根…

远程安全访问JumpServer:使用cpolar内网穿透搭建固定公网地址

文章目录 前言1. 安装Jump server2. 本地访问jump server3. 安装 cpolar内网穿透软件4. 配置Jump server公网访问地址5. 公网远程访问Jump server6. 固定Jump server公网地址 前言 JumpServer 是广受欢迎的开源堡垒机&#xff0c;是符合 4A 规范的专业运维安全审计系统。JumpS…

pop链反序列化 [MRCTF2020]Ezpop1

打开题目 网站源码为 Welcome to index.php <?php //flag is in flag.php //WTF IS THIS? //Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95 //And Crack It! class Modifier {protected …

【问题思考总结】多维随机变量函数的分布的两种情况的计算方法【离连/连连】

问题 今天做李六第一套的时候发现&#xff0c;有的时候&#xff0c;面对这种第二问的题&#xff0c;很自然地就想到了Fz&#xff08;z&#xff09;&#xff0c;然后进行化简&#xff0c;但是有的时候&#xff0c;像这道题&#xff0c;就突然发现P{XY<z}是一个非常复杂的形式…

【java】-D参数使用

在开发过程中我们使用开源工具经常会用到在启动命令时候加入一个 -Dxxx 类型的参数。到底-Dxxx是干什么用的了。 官方文档 地址&#xff1a;文档地址 java命令使用 下面是来源于官方文档&#xff1a; java [options] classname [args] java [options] -jar filename [args…

VUE留言板

效果预览图 完整代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>作业</title><styl…

Element-UI Upload 手动上传文件的实现与优化

文章目录 引言第一部分&#xff1a;Element-UI Upload 基本用法1.1 安装 Element-UI1.2 使用 <el-upload> 组件 第二部分&#xff1a;手动上传文件2.1 手动触发上传2.2 手动上传时的文件处理 第三部分&#xff1a;性能优化3.1 并发上传3.2 文件上传限制 结语 &#x1f38…

【Linux】常见指令及周边知识(一)

【Linux】常见指令及周边知识&#xff08;一&#xff09; 一、初始Linux操作系统1.Linux背景2.如何使用Linux 二、学习Linux之前的预备周边知识&#xff08;重点&#xff09;&#xff1a;1.什么叫做文件&#xff1f;2. Linux下的路径分隔符3.在Linux中为什么会存在路径&#xf…

了解抽象思维的应用与实践

目录 一、快速了解抽象思维 &#xff08;一&#xff09;抽象思维的本质理解 &#xff08;二&#xff09;系统架构中的重要性 &#xff08;三&#xff09;软件开发中抽象的基本过程思考 意识和手段 抽象的方式 抽象层次的权衡 二、业务中的应用实践 &#xff08;一&…