线程池相关理论

什么是线程池

线程池是一种利用池化技术思想来实现的线程管理技术,主要是为了复用线程、便利地管理线程和任务、并将线程的创建和任务的执行解耦开来。我们可以创建线程池来复用已经创建的线程来降低频繁创建和销毁线程所带来的资源消耗。在JAVA中主要是使用ThreadPoolExecutor类来创建线程池,并且JDK中也提供了Executors工厂类来创建线程池(不推荐使用) 

 线程池的优势

  • 线程和任务分离,提升线程重用性
  • 控制线程并发数量,降低服务器压力,统一管理所有线程
  • 提升系统响应速度,假如创建线程的时间为T1,执行任务用的时间T2,销毁线程用的时间T3,那么使用线程池就免去T1和T3的时间

 应用场景

  • 网购商品秒杀
  • 云盘文件上传和下载
  • 12306网上购票系统等

 ThreadPoolExecutor

ThreadPoolExecutor源码中构造方法:


public ThreadPoolExecutor(int corePoolSize, //核心线程数量int maximumPoolSize,//     最大线程数long keepAliveTime, //       最大空闲时间TimeUnit unit,         //        时间单位BlockingQueue<Runnable> workQueue,   //   任务队列ThreadFactory threadFactory,    // 线程工厂RejectedExecutionHandler handler  //  饱和处理机制) 
{ ... }

线程池工作流程图

 

 线程池参数设置原则

核心线程数量:核心线程数的设计需要依据任务的处理时间和每秒产生的任务数量来确定,例如:执行一个任务需要0.1,系统百分之80的时间每秒都会产生100个任务,那么要想在1秒内处理完这100个任务,就需要10个线程,此时我们就可以设计核心线程数为10;

任务队列:任务队列长度一般设计为:核心线程数/单个任务执行时间*2即可;例如上面的场景中,核心线程数设计为10,单个任务执行时间为0.1,则队列长度可以设计为200;

最大线程数:最大线程数的设计除了需要参照核心线程数的条件外,还需要参照系统每秒产生的最大任务数决定:例如:上述环境中,如果系统每秒最大产生的任务是1000,那么,最大线程数=(最大任务数-任务队列长度)*单个任务执行时间;: 最大线程数=(1000-200)*0.1=80;

 ExecutorService

常用方法

 void shutdown()   启动一次顺序关闭,执行以前提交的任务,但不接受新任务。 List<Runnable> shutdownNow() 停止所有正在执行的任务,暂停处理正在等待的任务,并返回等待执行的任务列表。 
<T> Future<T> submit(Callable<T> task)  执行带返回值的任务,返回一个Future对象。 Future<?> submit(Runnable task)  执行 Runnable 任务,并返回一个表示该任务的 Future。 
<T> Future<T> submit(Runnable task, T result)  执行 Runnable 任务,并返回一个表示该任务的 Future。 

 ExecutorService获取

获取ExecutorService可以利用JDK中的Executors 类中的静态方法

static ExecutorService newCachedThreadPool() 创建一个默认的线程池对象,里面的线程可重用,且在第一次使用时才创建 
static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) 线程池中的所有线程都使用ThreadFactory来创建,这样的线程无需手动启动,自动执行; 
static ExecutorService newFixedThreadPool(int nThreads)   创建一个可重用固定线程数的线程池 
static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) 创建一个可重用固定线程数的线程池且线程池中的所有线程都使用ThreadFactory来创建。 
static ExecutorService newSingleThreadExecutor() 创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。 
static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) 创建一个使用单个 worker 线程的 Executor,且线程池中的所有线程都使用ThreadFactory来创建。 

shutdown()和 shutdownNow()的区别

 void shutdown()   启动一次顺序关闭,执行以前提交的任务,但不接受新任务。

 List<Runnable> shutdownNow() 停止所有正在执行的任务,暂停处理正在等待的任务,并返回等待执行的任务列表

submit()和execute()的区别

submit:参数可以是Runnable或Callable,有返回值Future

execute:参数是Runnable,无返回值

ScheduledExecutorService 

ScheduledExecutorService是ExecutorService的子接口,具备了延迟运行定期执行任务的能力

static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
创建一个可重用固定线程数的线程池且允许延迟运行或定期执行任务;
static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)
创建一个可重用固定线程数的线程池且线程池中的所有线程都使用ThreadFactory来创建,且允许延迟运行或定期执行任务; 
static ScheduledExecutorService newSingleThreadScheduledExecutor() 
创建一个单线程执行程序,它允许在给定延迟后运行命令或者定期地执行。 
static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) 
创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。 
<V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) 
延迟时间单位是unit,数量是delay的时间后执行callable。 ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) 
延迟时间单位是unit,数量是delay的时间后执行command。  ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) 
延迟时间单位是unit,数量是initialDelay的时间后,每间隔period时间重复执行一次command。 ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) 
创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟。 

 Future异步计算结果

常用方法

boolean cancel(boolean mayInterruptIfRunning) 
试图取消对此任务的执行。 V get() 
如有必要,等待计算完成,然后获取其结果。 V get(long timeout, TimeUnit unit) 如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)。 boolean isCancelled() 
如果在任务正常完成前将其取消,则返回 true。 boolean isDone() 
如果任务已完成,则返回 true。 
package cn.ting.demo04;import java.util.concurrent.*;/*练习异步计算结果*/
public class FutureDemo {public static void main(String[] args) throws Exception {//1:获取线程池对象ExecutorService es = Executors.newCachedThreadPool();//2:创建Callable类型的任务对象Future<Integer> f = es.submit(new MyCall(1, 1));//3:判断任务是否已经完成test1(f);
//        boolean b = f.cancel(true);//System.out.println("取消任务执行的结果:"+b);//Integer v = f.get(1, TimeUnit.SECONDS);//由于等待时间过短,任务来不及执行完成,会报异常//System.out.println("任务执行的结果是:"+v);}//正常测试流程private static void test1(Future<Integer> f) throws InterruptedException, ExecutionException {boolean done = f.isDone();System.out.println("第一次判断任务是否完成:"+done);boolean cancelled = f.isCancelled();System.out.println("第一次判断任务是否取消:"+cancelled);Integer v = f.get();//一直等待任务的执行,直到完成为止System.out.println("任务执行的结果是:"+v);boolean done2 = f.isDone();System.out.println("第二次判断任务是否完成:"+done2);boolean cancelled2 = f.isCancelled();System.out.println("第二次判断任务是否取消:"+cancelled2);}
}
class MyCall implements Callable<Integer>{private int a;private int b;//通过构造方法传递两个参数public MyCall(int a, int b) {this.a = a;this.b = b;}public Integer call() throws Exception {String name = Thread.currentThread().getName();System.out.println(name+"准备开始计算...");Thread.sleep(2000);System.out.println(name+"计算完成...");return a+b;}
}

案列一:商品秒杀

案例介绍

假如某网上商城推出活动,新上架10部新手机免费送客户体验,要求所有参与活动的人员在规定的时间同时参与秒杀挣抢,假如有20人同时参与了该活动,请使用线程池模拟这个场景,保证前10人秒杀成功,后10人秒杀失败;

案例要求

使用线程池创建线

解决线程安全问题

package cn.ting.demo05;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ShopSekill {public static void main(String[] args) {seckill();}public static  void seckill(){ExecutorService executorService = Executors.newFixedThreadPool(10);//20个人参加秒杀for (int i = 1; i <= 20; i++) {executorService.submit(new MyTask("用户"+i));}executorService.shutdown();}
}
class MyTask implements Runnable{//十部手机private static int i=10;//20个人private String username;public MyTask(String username) {this.username = username;}public  void run() {String name = Thread.currentThread().getName();
//        System.out.println(username+"开始使用"+name+"秒杀商品啦~~~~~~");synchronized(ShopSekill.class){if (i>0) {System.out.println(username+"开始使用"+name+"秒杀商品"+i--+"成功了!!");}else {System.out.println(username+"开始使用"+name+"秒杀商品失败了!!");}}}
}

案例二:取款业务

案列介绍

设计一个程序,使用两个线程模拟在两个地点同时从一个账号中取钱,假如卡中一共有1000元,每个线程取800元,要求演示结果一个线程取款成功,剩余200元,另一个线程取款失败,余额不足; 

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class GetMoney {public static void main(String[] args) {seckill();}public static  void seckill(){ExecutorService executorService = Executors.newFixedThreadPool(2);//20个人参加秒杀for (int i = 1; i <= 2; i++) {executorService.submit(new MyTask());}executorService.shutdown();}
}
class MyTask implements Runnable{private static int money=1000;private static int qvMoney=800;public void run() {String name = Thread.currentThread().getName();synchronized (MyTask.class){if (money>800){System.out.println("线程"+name+"取了"+qvMoney+",还剩"+(money-=qvMoney));}else {System.out.println("线程"+name+"来取钱了,还剩"+money+",余额不足!");}}}
}

补充:核心工作线程是否会被回收?

线程池中有个allowCoreThreadTimeOut字段能够描述是否回收核心工作线程,线程池默认是false表示不回收核心线程,我们可以使用allowCoreThreadTimeOut(true)方法来设置线程池回收核心线程

四大拒绝策略

线程池中有哪些阻塞队列

 

 

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

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

相关文章

谐波失真(HD)

某一固定信号经过电子元器件后会出现谐波信号&#xff0c;在现实世界中&#xff0c;渴望都是线性的系统。比如&#xff1a;某个信号经过运算放大器放大&#xff0c;理想情况下不应该出现其他谐波信号&#xff0c;但实际上有谐波信号出现&#xff0c;HD(harmonic distortion)在一…

LNMP搭建

LNMP LNMP是目前成熟的企业网站的应用模式之一&#xff0c;指的是一套协同工作的系统和相关软件&#xff0c;能够提供静态页面服务&#xff0c;也可以提供动态Web服务。 LNMP四个字母分别代表的意思&#xff1a; L&#xff1a;Linux系统&#xff0c;操作系统 N&#xff1a;…

jenkins gitlab多分支构建发布

内容背景介绍 这个是新手教程,普及概念为主 公司现在还使用单分支发布测试环境和生产,多人协同开发同一个项目导致测试环境占用等待等情况 测试环境占用等待问题 测试环境代码直接合并到 master,容易导致误发布到生产的情况 避免多版本同时发布测试不完善的情况出现 中间件…

17. Spring 事务

目录 1. 事务定义 2. MySQL 中的事务使用 3. 没有事务时的插入 4. Spring 编程式事务 5. Spring 声明式事务 5.1 Transactional 作用范围 5.2 Transactional 参数说明 5.3 Transactional 工作原理 1. 事务定义 将⼀组操作封装成一个执行单元&#xff08;封装到一起…

Java基础面试题1

Java基础面试题 一、面向对象和集合专题 1. 面向对象和面向过程的区别 面向过程&#xff1a;是分析解决问题的步骤&#xff0c;然后用函数把这些步骤一步一步地实现&#xff0c;然后在使用的时候一一调用则可。性能较高&#xff0c;所以单片机、嵌入式开发等一般采用面向过程…

【C++】开源:matplotlib-cpp静态图表库配置与使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍matplotlib-cpp图表库配置与使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&…

AI 绘画Stable Diffusion 研究(五)sd文生图功能详解(下)

大家好&#xff0c;我是风雨无阻。 上一篇文章详细介绍了sd文生图的功能及使用注意事项&#xff0c;感兴趣的朋友可以前往查看&#xff1a;AI 绘画Stable Diffusion 研究&#xff08;四&#xff09;sd文生图功能详解&#xff08;上&#xff09; 。 那今天这篇文章&#xff0c;我…

一文学透设计模式

设计模式是什么&#xff1f; 设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案&#xff0c;代表了解决一些问题的最佳实践。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。 说白了&#xff0c;设计模式对于软件开发人员来说就…

VSCode和QT联合开发

提示&#xff1a;本文为学习记录&#xff0c;若有错误&#xff0c;请联系作者&#xff0c;谦虚受教。 文章目录 前言一、VSCODE下载二、使用步骤1.下载扩展 二、新建工程1.新建文件夹2.新建工程3.UI界面文件操作4.效果 总结 前言 一、VSCODE下载 下载地址 二、使用步骤 1.下…

【Web开发指南】如何用MyEclipse进行JavaScript开发?

由于MyEclipse中有高级语法高亮显示、智能内容辅助和准确验证等特性&#xff0c;进行JavaScript编码不再是一项繁琐的任务。 MyEclipse v2023.1.2离线版下载 JavaScript项目 在MyEclipse 2021及以后的版本中&#xff0c;大多数JavaScript支持都是开箱即用的JavaScript源代码…

瑞吉外卖实战-笔记

软件开发的流程 角色分工 软件环境 开发环境的搭建 数据库环境 maven环境 1.创建完成后&#xff0c;需要检查一下编码、maven仓库、jdk等 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</a…

牛客网Verilog刷题——VL42

牛客网Verilog刷题——VL42 题目答案 题目 请设计一个可以实现任意小数分频的时钟分频器&#xff0c;比如说8.7分频的时钟信号&#xff0c;注意rst为低电平复位。提示&#xff1a;其实本质上是一个简单的数学问题&#xff0c;即如何使用最小公倍数得到时钟周期的分别频比。设小…

Redis系列二:Clion+MAC+Redis环境搭建

1. ClionMACRedis-3.0-annotated环境搭建 参考&#xff1a; https://github.com/huangz1990/redis-3.0-annotated https://gitee.com/dumpcao/redis-3.0-annotated-cmake-in-clion https://tool.4xseo.com/a/12910.html 1.1 下载并导入Clion git clone https://gitee.com/dum…

链表的总体涵盖以及无哨兵位单链表实现——【数据结构】

&#x1f60a;W…Y&#xff1a;个人主页 在学习之前看一下美丽的夕阳&#xff0c;也是很不错的。 如果觉得博主的美景不错&#xff0c;博客也不错的话&#xff0c;关注一下博主吧&#x1f495; 在上一期中&#xff0c;我们说完了顺序表&#xff0c;并且提出顺序表中的问题 1. 中…

腾讯云TencentOS Server镜像系统常见问题解答

腾讯云TencentOS Server镜像是腾讯云推出的Linux操作系统&#xff0c;完全兼容CentOS生态和操作方式&#xff0c;TencentOS Server操作系统为云上运行的应用程序提供稳定、安全和高性能的执行环境&#xff0c;TencentOS可以运行在腾讯云CVM全规格实例上&#xff0c;包括黑石物理…

[golang gin框架] 40.Gin商城项目-微服务实战之Captcha验证码微服务

本次内容需要 gin框架基础知识, golang微服务基础知识才能更好理解 一.Captcha验证码功能引入 在前面,讲解了微服务的架构等,这里,来讲解前面商城项目的 Captcha验证码 微服务 ,captcha验证码功能在前台,后端 都要用到 ,可以把它 抽离出来 ,做成微服务功能 编辑 这个验证码功能…

echars力引导关系图

效果图 力引导关系图 力引导布局是模拟弹簧电荷模型在每两个节点之间添加一个斥力&#xff0c;每条边的两个节点之间添加一个引力&#xff0c;每次迭代节点会在各个斥力和引力的作用下移动位置&#xff0c;多次迭代后节点会静止在一个受力平衡的位置&#xff0c;达到整个模型…

IO进程线程day6(2023.8.3)

一、Xmind整理&#xff1a; 进程与线程关系&#xff1a; 二、课上练习&#xff1a; 练习1&#xff1a;pthread_create 功能&#xff1a;创建一个线程 原型&#xff1a; #include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, vo…

分布式框架dubbo

1.分布式系统相关概念 1.1基本概念 1.2 集群和分布式 1.3 架构演进 A是一个微服务。ADB是一个组件。A可以java&#xff0c;B可以python实现。 2 dubbo 2.1 概述 2.2 dubbo代码 2.2.1 服务提供者的改造-将项目service层对外发布到dubbo 通过dubbo中的service注解&#xff…

2023年华数杯选题人数发布!!

该选题人数&#xff0c;主要基于根据各个平台开赛后12小时各项数据统计&#xff0c;进行评估&#xff08;方法见注释&#xff09;&#xff0c;最终得出2023年华数杯选选题人数&#xff0c;大致为 题号选题人数A120B159C420 注释&#xff1a;选题人数来源&#xff1a;源自各个平…