【多线程】线程池总结带你详细了解线程池

news2024/11/27 23:43:05

文章目录

  • 线程池
  • 标准库中的线程池
    • Executors 创建线程池的几种方式
    • ThreadPoolExecutor创建线程池
  • 模拟实现线程池

线程池

线程池是一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。线程池最大的好处是减少了每次创建销毁线程的开销。

标准库中的线程池

Executors 创建线程池的几种方式

① 使用 Executors.newFixedThreadPool(5) 能创建出固定包含 5个线程的线程池
返回值类型为 ExecutorService
通过 ExecutorService.submit 可以注册一个任务到线程池中

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

public class ThreadPool01 {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 20; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
    }
}

② 使用 Executors.newCachedThreadPool()创建出的线程池对象的特点是线程池数目能够动态适应,随着往线程池里添加任务,这个线程池里的线程数量会根据需要自动被创建,创建之后也不会着急销毁,会在线程池里存在一段时间以备随时使用。

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

public class ThreadPool2 {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newCachedThreadPool();
        for (int i = 0; i < 20; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
    }
}

③使用 Executors.newSingleThreadExecutor(): 创建只包含单个线程的线程池(一般用的不多)

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

public class ThreadPool3 {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 20; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
    }
}

④使用 Executors.newScheduledThreadPool():相当于是定时器 设定 延迟时间后执行命令,或者定期执行命令

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

public class TheadPool4 {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newScheduledThreadPool(5);
        for (int i = 0; i < 20; i++) {
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            });
        }
    }
}

Executors 本质上是 ThreadPoolExecutor 类的封装,ThreadPoolExecutor 提供了更多的可选参数, 可以进一步细化线程池行为的设定。

ThreadPoolExecutor创建线程池

在这里插入图片描述

最后一个构造方法可以涵盖上面其他三个,所以我们重点来看最后一个构造方法。

在这里插入图片描述

参数详解:

corePoolSize:核心线程数------>我们如果把线程池理解成一个公司,核心线程数就相当于正式员工数量

maximumPoolSize:最大线程数------>正式员工 + 实习生

keepAliveTime:空余线程等待新任务的最大时间------>允许实习生摸鱼的最大时间(如果说正式员工可以摸鱼并且不会被开除,实习生不允许摸鱼)

unit:keepAliveTime的时间单位

workQueue:阻塞队列,用来存放线程池中的任务,可以根据需要来设置这里的队列是啥比如:如果需要优先级则可以设置为PriorityBlockingQueue 如果不需要优先级线程数目是恒定的则可以使用ArrayBlockingQueue 如果任务变动较大可以使用LinkedBlockingQueue

threadFactory:工厂模式的体现,这里使用threadFactory作为工厂类,由这个类负责创建线程,使用工厂类创建线程主要是为了在创建过程中可以很方便对线程的属性进行设置

handler:线程池的拒绝策略,一个线程池能够容纳的任务数量有上限,当持续向线程池中添加任务,一旦达到上限,不同的拒绝策略有不同的效果

拒绝策略:↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

在这里插入图片描述

问题讨论:使用线程池,设置多少线程数目合适呢???

解释:一个线程执行的代码主要有两类:①CPU密集型:代码主要是进行算数运算/逻辑判断 ②IO密集型:代码主要进行的是IO操作

假设一个线程的所有代码都是CPU密集型代码,这时线程池数量不应该超过N(CPU逻辑核心数),即使超过N也无法提高效率,CPU占满了增加线程反而会增加调度的开销。

假设一个线程的所有代码都是IO密集型,这时不占CPU,此时设置线程数就可以超过N,一个核心可以通过调度来并发执行。

但是纯CPU密集型和纯IO密集型代码一般工作中不会出现,所以线程池的线程数量应该对程序进行测试。

模拟实现线程池

模拟实现线程池我们需要知道线程池里有什么:

1、线程池管理器(ThreadPoolManager):用于创建并管理线程池

2、工作线程(WorkThread): 线程池中线程

3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行

4、任务队列:用于存放没有处理的任务。提供一种缓冲机制

核心操作为 submit, 将任务加入线程池中,使用一个 BlockingQueue 组织所有的任务 。

模拟实现一个简单版的线程池👇👇👇

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

//模拟实现线程池
public class MyThreadPool {
    //定义一个任务队列
    private BlockingQueue<Runnable> deque = new ArrayBlockingQueue<>(1000);

    //把任务添加到队列中
    public void submit(Runnable runnable) throws InterruptedException {
        deque.put(runnable);
    }

    public MyThreadPool(int n) {
        //创建出n个线程负责上述队列中的任务
        for (int i = 0; i < n; i++) {
            Thread t = new Thread(() -> {
                //让线程消费任务并执行
                try {
                    Runnable runnable = deque.take();
                    runnable.run();

                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            });
            t.start();
        }
    }
}

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

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

相关文章

基于单片机的自动感应门设计

博主主页&#xff1a;单片机辅导设计 博主简介&#xff1a;专注单片机技术领域和毕业设计项目。 主要内容&#xff1a;毕业设计、简历模板、学习资料、技术咨询。 文章目录 主要介绍一、自动感应门设计的功能概述二、系统总体方案2.1系统的总体计划2.2元器件的介绍2.2.1单片机的…

全局安装 vue-cli 报错 Error: EPERM: operation not permitted, open

原因&#xff1a;没有权限 解决方法&#xff1a;CMD 点击右键 以管理员身份运行。

IDEA创建Springboot多模块项目

一、创建父模块 File --> New --> Project &#xff0c;选择 “ Spring Initalizr ” &#xff0c;点击 Next Next Next --> Finish 二、创建子模块 右键根目录&#xff0c;New --> Module 选择 “ Spring Initializr ”&#xff0c;点击Next 此处注意T…

ubuntu20.04配置解压版mysql5.7

目录 1.创建mysql 用户组和用户2.下载 MySQL 5.7 解压版3.解压 MySQL 文件4.将 MySQL 移动到适当的目录5.更改mysql目录所属的用户组和用户&#xff0c;以及权限6.进入mysql/bin/目录&#xff0c;安装初始化7.编辑/etc/mysql/my.cnf配置文件8.启动 MySQL 服务&#xff1a;9.建立…

【Linux】基本指令-入门级文件操作(三)

目录 基本指令 14 head指令 15 tail指令 管道 16 find指令 17 grep指令 18 zip&#xff06;unzip指令 19 tar指令 20 su指令 总结 基本指令 14 head指令 功能&#xff1a;在屏幕上显示文件的内容&#xff0c;默认显示前10行&#xff0c;如果加上选项-n&#xff0c;则…

go测试库之apitest

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

万宾科技管网水位监测预警,管网水位的特点有哪些?

以往如果要了解城市地下排水管网的水位变化&#xff0c;需要依靠人工巡检或者排查的方式&#xff0c;这不仅加大了人员的工作量&#xff0c;而且也为市政府带来了更多的工作难题。比如人员监管监测不到位或无法远程监控等情况&#xff0c;都会降低市政府对排水管网的管理能力&a…

react_11

MobX 介绍 需求&#xff0c;组件0 改变了数据&#xff0c;其它组件也想获得改变后的数据&#xff0c;如图所示 这种多个组件之间要共享状态数据&#xff0c;useState 就不够用了&#xff0c;useContext 也不好用了 能够和 react 配合使用的状态管理库有 MobX Redux 其中…

Mac下使用nvm,执行微信小程序自定义处理命令失败

环境 系统&#xff1a;Mac OS 终端&#xff1a;zsh CPU&#xff1a;M1/ARM架构 node环境&#xff1a;nvm&#xff0c;node20 node目录&#xff1a;/Users/laoxu/.nvm/versions/node/v20.1.0/bin/ 问题 在使用微信小程序的自定义处理命令时&#xff0c;启动失败 提示找不…

【算法挑战】常数时间插入、删除和获取随机元素(含解析、源码)

380.常数时间插入、删除和获取随机元素 https://leetcode-cn.com/problems/insert-delete-getrandom-o1/ 题目描述 设计一个支持在平均 时间复杂度 O(1) 下&#xff0c;执行以下操作的数据结构。insert(val)&#xff1a;当元素 val 不存在时&#xff0c;向集合中插入该项。 …

【快速解决】Android Button页面跳转功能

目录 让我们直接开始 第一步&#xff1a;先建立一个新的activity ​编辑 第二步&#xff1a;打开第一个页面的Java文件MainActivity 方法一&#xff1a;直接跳转功能如下&#xff1a; 方法二&#xff1a;输入密码才能进行跳转功能如下&#xff1a; 需要注意的地方 结语 让…

音视频报警可视对讲15.6寸管理机

音视频报警可视对讲15.6寸管理机 一、管理机技术指标&#xff1a; 1、15.6寸原装京东方工业液晶触摸屏&#xff0c;分辨率1920 (H) x 1080 (V)&#xff1b; 2、1000M/100M自适应双网口&#xff1b; 4、按键设置&#xff1a;报警/呼叫按键&#xff0c;通话/挂机按键&#xff…

RabbitMQ 消息应答与发布

目录 一、消息应答 1、自动应答&#xff08;默认&#xff09; 2、手动消息应答的方法 ​编辑 3、消息重新入队 4、手动应答案列与效果演示 二、RabbitMQ持久化 1、队列持久化 2、消息持久化 三、不公平分发&#xff08;能者多劳&#xff0c;弱者少劳&#xff09; 1、…

人工智能师求职面试笔试题及答案汇总

人工智能师求职面试笔试题及答案汇总 1.如何在Python中实现一个生成器&#xff1f; 答&#xff1a;在Python中&#xff0c;生成器是一种特殊类型的迭代器。生成器允许你在需要时才生成值&#xff0c;从而节省内存。生成器函数在Python中是通过关键字yield来实现的。例如&…

Linux 安装node并全局可用

前言 基于&#xff1a;操作系统 CentOS 7.6 工具&#xff1a;Xshell7、Xftp7 1.下载 根目录创建一个 node 文件夹并进入 mkdir /node && cd /node下载压缩包 wget https://nodejs.org/download/release/v16.18.0/node-v16.18.0-linux-x64.tar.gz2.解压并重命名 …

AI:53-基于机器学习的字母识别

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…

字节测试开发面试分享,太难了...

一面 首先&#xff0c;自我介绍&#xff0c;我介绍了自己的技术栈和项目。 技术栈提到过Spring、Redis、Kafka、Docker、K8s、大数据。 项目提到过接口和UI自动化。 我有个大数据平台项目&#xff0c;问了比较多&#xff0c;聊着聊着&#xff0c;提到自己研究过Selenium、T…

MongoDB设置密码

关于为什么要设置密码 公司的测试服务器MongoDB服务对外网开放的&#xff0c;结果这几天发现数据库被每天晚上被人清空的了&#xff0c;还新建了个数据库&#xff0c;说是要支付比特币。查了日志看到有个境外的IP登录且删除了所有的集合。所以为了安全起见&#xff0c;我们给m…

centos9 stream 下 rabbitmq高可用集群搭建及使用

RabbitMQ是一种常用的消息队列系统&#xff0c;可以快速搭建一个高可用的集群环境&#xff0c;以提高系统的弹性和可靠性。下面是搭建RabbitMQ集群的步骤&#xff1a; 基于centos9 stream系统 1. 安装Erlang和RabbitMQ 首先需要在所有节点上安装Erlang和RabbitMQ。建议使用官…