线程池--JAVA

虽然线程是轻量级进程,但是如果当创建和销毁的的频率非常之高,那么它也就会消耗很多的资源。

而线程池就是用来优化线程频繁创建和销毁的场景,减少线程创建、销毁的频率。

ExecutorService

JAVA标准库为我们实现了线程池,ExecutorService是一个接口,线程池的创建并不像平常的接口实现那样直接new,而是使用了“工厂模式”。

public static void main(String[] args) {//创建有4个线程的线程池ExecutorService service = Executors.newFixedThreadPool(4);//创建一个可以根据任务数量 来自行调整线程数量 的线程池ExecutorService service1 = Executors.newCachedThreadPool();//创建含有一个线程的线程池ExecutorService service2 = Executors.newSingleThreadExecutor();//创建一个含有3个线程的线程池,该线程池可以调度命令在给定时间后延迟运行ScheduledExecutorService service3 = Executors.newScheduledThreadPool(3);
}

创建好了之后可以利用submit()方法来给里面添加任务

public static void main(String[] args) {//创建有4个线程的线程池ExecutorService service = Executors.newFixedThreadPool(4);//添加5个任务for (int i = 0; i < 5; i++) {int a = i;service.submit(()->{System.out.println(a);});}
}

但是第四种创建线程池的方法有点特殊如果你想要实现延时执行任务就需要使用schedule

()方法。

public static void main(String[] args) {// 创建一个定时执行任务的线程池,设置核心线程数为3ScheduledExecutorService service = Executors.newScheduledThreadPool(3);//打印当前时间System.out.println(System.currentTimeMillis());// 定时执行任务,延迟2秒后开始执行service.schedule(() -> {// 执行的任务逻辑System.out.println("任务执行时间:" + System.currentTimeMillis());}, 2, TimeUnit.SECONDS);
}

上述这几个创建线程池的方法本质上都是将ThreadPoolExecutor进行了封装。

ThreadPoolExecutor

这个类有4中构造方法,可是仔细看就会发现前三种还是调用的的四种,所以本质上是只有一种。

各个参数的含义

corePoolSize

当前线程池中的核心线程数即当前线程池在空闲时含有的线程数量,也就是当前线程池包含的线程最少数量。

maximumPoolSize

当前线程池中允许存在的最大线程数。

keepAliveTime

当实际线程数大于核心线程数时,多余的空闲线程能够存活的最长时间。

unit

存活时间的单位。

NANOSECONDS:千分之一微秒;

MICROSECONDS:千分之一毫秒;

MILLISECONDS:千分之一秒;

SECONDS:秒;

MINUTES:分钟;

HOURS:小时;

DAYS:天;

workQueue

用于保存待执行任务的队列。

threadFactory

创建新线程时所用的工厂类。

handler

当线程池中的任务满了之后所使用的拒绝策略。

ThreadPoolExecutor.AbortPolicy:直接抛出异常;

ThreadPoolExecutor.CallerRunsPolicy:新添加的任务,由添加任务的线程执行;

ThreadPoolExecutor.DiscardOldestPolicy :丢弃队列中最老的任务,再将新任务添加进任务队列;

ThreadPoolExecutor.DiscardPolicy:丢弃新添加的任务。

线程池的关闭

想要关闭线程池需要使用shutdown()方法

public static void main(String[] args) {// 创建一个定时执行任务的线程池,设置核心线程数为3ScheduledExecutorService service = Executors.newScheduledThreadPool(3);//打印当前时间System.out.println(System.currentTimeMillis());// 定时执行任务,延迟2秒后开始执行service.schedule(() -> {// 执行的任务逻辑System.out.println("任务执行时间:" + System.currentTimeMillis());}, 2, TimeUnit.SECONDS);
}

可以看出任务执行完后程序并没有退出。

public static void main(String[] args) {// 创建一个定时执行任务的线程池,设置核心线程数为3ScheduledExecutorService service = Executors.newScheduledThreadPool(3);//打印当前时间System.out.println(System.currentTimeMillis());// 定时执行任务,延迟2秒后开始执行service.schedule(() -> {// 执行的任务逻辑System.out.println("任务执行时间:" + System.currentTimeMillis());}, 2, TimeUnit.SECONDS);//主线程休眠一段时间try {Thread.sleep(2000); // 休眠2秒} catch (InterruptedException e) {e.printStackTrace();}// 关闭线程池service.shutdown();
}

接下来为了更好的理解线程池,下面是模拟实现一个含有固定线程数的线程池。

模拟实现

先创建一个类名为MyThreadPool里面含有一个属性,类型为BlockingQueue。

public class MyThreadPool {//队列大小为5private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(5);
}

写一个只有一个参数的有参构造方法,参数为线程池的线程数。

利用循环创建n个线程,每个线程都不断地从队列中拿任务。

public MyThreadPool(Integer n) {for (int i = 0; i < n; i++) {Thread t = new Thread(()->{while(true) {try {Runnable runnable = queue.take();runnable.run();} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();}
}

写一个submit()方法可以给队列中添加任务。

public void submit(Runnable runnable) {try {this.queue.put(runnable);} catch (InterruptedException e) {throw new RuntimeException(e);}
}

此时一个简单的线程池就完成了,下面来进行一下简单的测试:

public static void main(String[] args) {MyThreadPool myThreadPool = new MyThreadPool(5);for (int i = 0; i < 40; i++) {int a = i;myThreadPool.submit(()->{System.out.println(a);});}
}

完整代码

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;//线程池
public class MyThreadPool {private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(5);public MyThreadPool(Integer n) {for (int i = 0; i < n; i++) {Thread t = new Thread(()->{while(true) {try {Runnable runnable = queue.take();runnable.run();} catch (InterruptedException e) {throw new RuntimeException(e);}}});t.start();}}public void submit(Runnable runnable) {try {this.queue.put(runnable);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Rocky Linux 8.9 安装图解

风险告知 本人及本篇博文不为任何人及任何行为的任何风险承担责任&#xff0c;图解仅供参考&#xff0c;请悉知&#xff01;本次安装图解是在一个全新的演示环境下进行的&#xff0c;演示环境中没有任何有价值的数据&#xff0c;但这并不代表摆在你面前的环境也是如此。生产环境…

【JavaEE进阶】 Spring Boot⽇志

文章目录 &#x1f38b;关于日志&#x1f6a9;为什么要学习⽇志&#x1f6a9;⽇志的⽤途&#x1f6a9;日志的简单使用 &#x1f384;打印⽇志&#x1f6a9;程序中得到⽇志对象&#x1f6a9;使⽤⽇志对象打印⽇志 &#x1f38d;⽇志格式的说明&#x1f6a9;⽇志级别的作用&#…

八股文学习日常第一期(20240121)

零、前言 1、目的 帮助掌握面试题&#xff0c;就八股文相关内容展开进行学习和整理&#xff0c;也方便之后的复习和巩固。 2、八股文内容来源 ①https://blog.csdn.net/w20001118/article/details/125724647 一、具体内容分析 1、类的完整书写方式 1.1、类 [Access Mod…

【Linux对磁盘进行清理、重建、配置文件系统和挂载,进行系统存储管理调整存储结构】

Linux 调整存储结构 前言一、查看磁盘和分区列表二、创建 ext4 文件系统&#xff0c;即&#xff1a;格式化分区为ext4文件系统。1.使用命令 mkfs.ext4 (make file system)报错如下&#xff1a;解决办法1&#xff1a;&#xff08;经测试&#xff0c;不采用&#xff09;X解决办法…

vue3源码(一)搭建开发环境

Monorepo:是管理项目代码的一个方式&#xff0c;指在一个项目仓库(repo)中管理多个模块/包(package) vue3源码采用Monorepo管理项目 vue3项目架构 搭建Monorepo环境 1.全局安装pnpm npm install pnpm -g # 全局安装pnpm pnpm init -y # 初始化配置文件创建.npmrc文件&#x…

基于 Redis 实现高性能、低延迟的延时消息的方案演进

&#x1f389;欢迎来系统设计专栏&#xff1a;基于 Redis 实现高性能、低延迟的延时消息的方案演进 &#x1f4dc;其他专栏&#xff1a;java面试 数据结构 源码解读 故障分析 &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是小徐&#x1f947;☁️博客首页&#xff1…

C++--入门(命名空间缺省参数函数重载)

目录 0.前言 1. C关键字(C98) 2. 命名空间 3. C输入&输出 4. 缺省&#xff08;默认&#xff09;参数 5. 函数重载 6.C支持函数重载的原理--名字修饰(name Mangling) 0.前言 C语言是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&#xff0c…

I2C接口简介

一、简介 11I2C&#xff08;Inter&#xff0d;IntegratedCircuit&#xff09;总线是由PHILIPS公司开发的两线式串行通信总线&#xff0c;使用多主从架构&#xff0c;用于连接微控制器及其外围低速设备。是微电子通信控制领域广泛采用的一种总线标准。它是同步通信的一种特殊形…

了解森林消防灭火泵:为何它是森林安全的关键

在森林火灾中&#xff0c;火势蔓延速度极快&#xff0c;一旦发生火灾&#xff0c;很难及时控制和扑灭。传统的灭火方法主要是利用水扑救&#xff0c;这种方法具有经济、简单、有效等优点。然而&#xff0c;在我国森林火灾中&#xff0c;水资源一直没有得到充分的利用。至今&…

【C++】string的基本使用二

我们接着上一篇的迭代器说起&#xff0c;迭代器不只有正向的&#xff0c;还有反向的&#xff0c;就是我们下边的这两个 它的迭代器类型也是不同的 rbegin就是末尾&#xff0c;rend就是开头&#xff0c;这样我们想遍历一个string对象的话就可以这样做 int main() {string s1(…

CC工具箱使用指南:【检查现状规划用地变化】

一、简介 在规划工作中&#xff0c;有一个普遍性的需求&#xff0c;就是需要检查规划前后在用地上究竟发生了哪些变化。 这一点很重要&#xff0c;不仅是要展示给别人看&#xff0c;自己也要十分注意。 规划方案完成后&#xff0c;一定要进行用地变化的检查&#xff0c;曾经…

从一到无穷大 #21 从基于多数据模型分析负载的Benchmark讨论多模数据库的发展方向

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 文章目录 引言M2Bench测试结果从Lindorm看待多模的发展方向总结 引言 《M2Bench: A Database …