线程池--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.mzph.cn/news/640349.shtml

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

相关文章

华而有实,维乐Prevail Glide带你领略风景线,成为风景线~

大家都知道呢&#xff01;骑行&#xff0c;不仅是一种运动&#xff0c;更是一种生活态度。在骑行装备的世界里&#xff0c;一个好的坐垫对于骑行的舒适度和安全性至关重要。那今天&#xff0c;我要为大家推荐一款备受赞誉的坐垫——维乐坐垫美学系列-Prevail Glide。    为…

基于springboot+vue的甘肃非物质文化网站(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 研究背景…

pycharm创建vue项目idealTree:npm: sill idealTree buildDeps,换taobao源后还不好使?那就再换一个

心血来潮打算写个小项目&#xff0c;前后端分离&#xff0c;flask/fastapivue&#xff08;具体用哪个后端还没想好&#xff09;&#xff0c;里面的功能大概就是目前所有热门的应用的合集&#xff0c;一键出结果的那种&#xff0c;然后跟随着科技趋势&#xff0c;不断去更新维护…

CSGO搬砖项目还能火多久?

最近放假回到老家&#xff0c;见了不少亲戚朋友&#xff0c;大家不约而同都在感叹今年大环境不好&#xff0c;工作不顺&#xff0c;生意效益不好&#xff0c;公司状况不佳&#xff0c;反问我们生意如何&#xff1f;为了让他们心里好受一点&#xff0c;我也假装附和道:也不咋地&…

组件中写选项的顺序(vue的问题)

为什么选项要有统一的书写顺序呢&#xff1f;很简单&#xff0c;就是要将选择和认知成本最小化。 副作用 (触发组件外的影响) el全局感知 (要求组件以外的知识) nameparent组件类型 (更改组件的类型) functional模板修改器 (改变模板的编译方式) delimiterscomments模板依赖 (…

JavaScript DOM表单相关操作之表单相关事件

1、焦点事件 焦点事件就是鼠标的光标事件&#xff0c;点到输入框中&#xff0c;叫做获得焦点事件&#xff0c;当鼠标离开这个输入框时叫做失去焦点事件。 <!DOCTYPE html> <html> <head><meta charset"UTF-8"><title>知数SEO_专注搜…

Rust 程序设计语言学习——基础语法

Rust 语言是一种高效、可靠的通用高级语言。其高效不仅限于开发效率&#xff0c;它的执行效率也是令人称赞的&#xff0c;是一种少有的兼顾开发效率和执行效率的语言。 Rust 语言由 Mozilla 开发&#xff0c;最早发布于 2014 年 9 月。Rust 的编译器是在 MIT License 和 Apach…

Beego之Beego参数配置

1、beego参数配置 配置模块是基础模块之一&#xff0c;对不同类型的配置文件提供了一种抽象。 beego目前支持INI、XML、JSON、YAML格式的配置文件解析&#xff0c;但是默认采用了INI格式解析&#xff0c;用户可以通过简 单的配置就可以获得很大的灵活性。同时也支持以 etcd …

qml中的信号槽的几种方式

1、信号处理器 当对应的信号发射时&#xff0c;信号处理器(就是QtWidgets中的槽函数)会被qml引擎自动调用。 在qml的对象定义中添加一个信号&#xff0c;则自动在对象定义中添加一个相应的对象处理器&#xff0c;只不过没有具体的代码实现。 如下所示&#xff0c;在Rectangle类…

C++之void*指针

先看一个例子 #ifndef _Aspect_Handle_HeaderFile#define _Aspect_Handle_HeaderFile​#ifdef _WIN32 typedef void* HANDLE; typedef HANDLE Aspect_Handle;#else typedef unsigned long Aspect_Handle;#endif /* _WIN32 */​#endif /* _Aspect_Handle_Header…

基于SpringBoot+vue的在线视频教育平台的设计与实现,附源码,数据库

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

【文件处理】spring boot 文件处理

接收文件 PostMappingpublic result<String> add(MultipartFile file) throws IOException {// 得到目标文件夹File directory new File("file");//如果文件夹不存在就创建if(!directory.exists()){directory.mkdirs();}//文件名称String fileName file.getO…

性能进阶:使用JMeter进行websocket测试【建议收藏】

本次测试案例主要是分享如何使用JMeter进行websocket协议下的聊天接口性能测试。 包含websocket插件的下载安装、线程组及sampler的设置、csv参数化和组建分布式测试的方法、如何通过调整参数来获得发压机的最大并发数以及对测试过程的总结。 整篇文章只侧重介绍进行websocke…

Linux中的软件包管理器yum

目录 1.什么是软件包 2.关于 rzsz 3.查看软件包 4.如何安装软件 5.如何卸载软件 1.什么是软件包 ● 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序. ● 但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理…

阿里云优惠券领取入口、使用教程,2024优惠券更新

阿里云优惠代金券领取入口&#xff0c;阿里云服务器优惠代金券、域名代金券&#xff0c;在领券中心可以领取当前最新可用的满减代金券&#xff0c;阿里云百科aliyunbaike.com分享阿里云服务器代金券、领券中心、域名代金券领取、代金券查询及使用方法&#xff1a; 阿里云优惠券…

C语言_存储结构实现_线性表

#include <stdio.h> #include <stdlib.h>#define MAX_SIZE 100 // 定义线性表的最大长度typedef struct {int data[MAX_SIZE]; // 用数组存储数据元素int length; // 线性表的当前长度 } SqList;// 函数声明 void initList(SqList *list); // 初始化线性表 int ins…

Linux下修改系统的运行级别

借助命令ll /etc/system/system/default.target可以查看当前的系统运行的级别&#xff1a;以下图为例运行级别就是3 但如果系统运行的级别默认为图形时&#xff0c;要将图形级别改为文本级别&#xff0c;可以按照下边两种方法运行&#xff1a; 1、重新设置链接文件 这个方法需…

wy的leetcode刷题记录_Day74

wy的leetcode刷题记录_Day74 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间&#xff1a;2024-1-22 前言 目录 wy的leetcode刷题记录_Day74声明前言670. 最大交换题目介绍思路代码收获 670. 最大交换 今天的每日一题是&#xff1a;670. 最大交换 …

03-常用编程概念

上一篇&#xff1a;02-编程猜谜游戏 本章介绍几乎所有编程语言中都会出现的概念&#xff0c;以及它们在 Rust 中的工作原理。许多编程语言的核心都有许多共同点。本章介绍的概念都不是 Rust 独有的&#xff0c;但我们会在 Rust 的上下文中讨论这些概念&#xff0c;并解释使用这…

Pymol-电子密度图展示方法-PDB数据库已发表结构和自己晶体解析得到的结构密度图

简单来说&#xff0c;想要用PyMol展示电子密度图可以归为以下两种&#xff1a; 一是展示PDB数据库中已发表数据的结构和Map的方式 以6sps.pdb为例&#xff0c;在pymol中导入该数据密度图时&#xff0c;可以无需下载对应的密度文件&#xff0c;直接用fetch即可&#xff1a; Py…