线程池ThreadPool,线程池底层ThreadPoolExecutor方法七大参数,拒绝策略,以及实际开发中高并发下用到哪个线程池?

为什么要用线程池

在这里插入图片描述

基本的三个线程池的底层就是ThreadPoolExecutor类

ExecutorService threadPool = Executors.newFixedThreadPool(int);//固定线程数的线程池,,执行长期的任务,性能好
ExecutorService threadPool = Executors.newSingleThreadExecutor(); //单线程的线程池,,一个任务一个任务执行
ExecutorService threadPool = Executors.newCachedThreadPool(); //一池N线程,,,执行很多短期异步的任务

Executors是工具类,类似Arrays、Collections
在这里插入图片描述

底层ThreadPoolExecutor的重要参数:7大参数(面试一般问前5个)

在这里插入图片描述
在这里插入图片描述

  • int corePoolSize, 线程池中的常驻核心线程数
  • int maximumPoolSize, 线程池能够容纳同时执行的最大线程数,此值必须大于等于1(当核心线程数满了并且阻塞队列的线程数也满了,那么就会进行扩容,最大值是maximumPoolSize)
  • long keepAliveTime, 多余的空闲线程的存活时间,当前线程池数量超过corePoolSize时,
    当空闲时间达到keepAliveTime值时,多余空闲线程会被销毁直到只剩corePoolSize个线程为止。
  • TimeUnit unit, keepAliveTime的单位
  • BlockingQueue workQueue, 任务队列,被提交但尚未被执行的任务。(候客区)
  • ThreadFactory threadFactory, 表示生成线程池中的工作线程的线程工厂,用于创建线程一般用默认的即可
  • RejectedExecutionHandler handler 拒绝策略,表示当前队列满了并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时如何来拒绝请求执行的runnable的策略
    在这里插入图片描述

当空闲线程空闲的时间超过keepAliveTime,就会被销毁,但是最少会存在corePoolsize数个线程,如下

在这里插入图片描述

线程池的底层工作原理(七大参数如何互动?)

在这里插入图片描述
在这里插入图片描述

文字讲解

  1. 在创建线程池后,等待提交过来的任务请求。
  2. 当调用execute()方法添加一个请求任务时,线程池会做如下判断:
    2.2 如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务。
    2.2 如果正在运行的线程数量大于corePoolSize,那么将这个任务加入阻塞队列
    2.3 如果这时候阻塞队列满了且正在运行的线程数量小于maximumPoolSize,那么还是要创建非核心线程立刻执行这个任务。
    2.4 如果阻塞队列满了且正在运行的线程数大于或等于maximumPoolSize,那么线程池会启动饱和拒绝策略(RejectedExecutionHandler)来执行。
  3. 当一个线程完成任务时,他会从阻塞队列中取出下一个任务执行。
  4. 当一个线程无事可做超过keepAliveTime时,线程池会判断:
    当运行的线程数大于corePoolSize,那么这个线程就被叫停。
    所以线程池的所有任务完成后它的线程数最终会收缩到corePoolSize的数量。
package JUC;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** 线程池*/
public class MyThreadPoolDemo {public static void main(String []args){//System.out.println(Runtime.getRuntime().availableProcessors());//查看cup核数//线程池的底层就是ThreadPoolExecutor类//Executors是工具类//newScheduledThreadPool带时间的//java获得线程的方法有4种,继承Thread类、实现Runable(没有返回值,不会抛异常,重新run()方法)、实现Callable(有返回值,会抛异常,重新call()方法)、线程池(ThreadPoolExecutor)//池化不用newExecutorService threadPool = Executors.newFixedThreadPool(5);//固定线程数的线程池,,执行长期的任务,性能好//ExecutorService threadPool = Executors.newSingleThreadExecutor(); //单线程的线程池,,一个任务一个任务执行//ExecutorService threadPool = Executors.newCachedThreadPool(); //一池N线程,,,执行很多短期异步的任务//模拟10用户来办理业务,每个用户就是一个外部的请求线程,线程池里的线程是工作人员try{for (int i = 0; i < 10 ; i++) {threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t办理业务");});//TimeUnit.MILLISECONDS.sleep(200);//在Cache线程池里,如果每次暂停0.2秒那么一个线程就可以处理过了,所以每次都是同一个线程,去掉延时就不是一个线程了}}catch (Exception e){e.printStackTrace();}finally {threadPool.shutdown();}}
}

线程池的拒绝策略RejectedExecutionHandler(四种)

  1. AbortPolicy(默认):直接抛出RejectedExecutionException异常阻止系统正常运行
  2. CallerRunsPolicy:“调用者运行”一种调节机制,该策略既不会抛出任务,也不会抛出异常,而是将某些任务回退到调用调用者,从而降低新的任务流量。()
  3. DiscardOldestPolicy:抛出队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务
  4. DiscardPolicy:直接丢弃任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种方案。

那么实际的高并发下使用哪个线程池?(面试题)

在这里插入图片描述

以上三种高并发下都不会使用:(阿里java开发手册)

在这里插入图片描述
1)第一个图片可以看到newFixedThreadPool和SingleThreadPool的阻塞队列用的是LinkedBlockingQueue,Linked底层是链表,Integer.MAX_VALUE接近21亿,请求可以一直加到阻塞队列里,那么太多就会OOM。
2)CachedThreadPool和ScheduledThreadPool的第二个参数也就是最大线程数是Integer.MAX_VALUE,可能创建大量线程,导致OOM

接下来继续测试下每个拒绝策略:(自定义线程池后)

这是自定义的线程池:可以看到核心线程数为2,最大线程数为5,阻塞队列为3,那么允许请求的最大线程数为5+3=8个

// 自定义线程池ExecutorService threadPool = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());

1.AbortPolicy():直接抛出RejectedExecutionException异常阻止系统正常运行

public class MyThreadPoolDemo {public static void main(String []args){// 自定义线程池ExecutorService threadPool = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());try{for (int i = 1; i <= 10 ; i++) {threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t办理业务");});//TimeUnit.MILLISECONDS.sleep(200);//在Cache线程池里,如果每次暂停0.2秒那么一个线程就可以处理过了,所以每次都是同一个线程,去掉延时就不是一个线程了}}catch (Exception e){e.printStackTrace();}finally {threadPool.shutdown();}}

结果:可以看到会抛异常。
在这里插入图片描述
2.CallerRunsPolicy():“调用者运行”一种调节机制,该策略既不会抛出任务,也不会抛出异常,而是将某些任务回退到调用调用者,从而降低新的任务流量。()

public class MyThreadPoolDemo {public static void main(String []args){// 自定义线程池ExecutorService threadPool = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());try{for (int i = 1; i <= 9 ; i++) {threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t办理业务");});//TimeUnit.MILLISECONDS.sleep(200);//在Cache线程池里,如果每次暂停0.2秒那么一个线程就可以处理过了,所以每次都是同一个线程,去掉延时就不是一个线程了}}catch (Exception e){e.printStackTrace();}finally {threadPool.shutdown();}}

结果:可以看到多出来的会回退给main线程,(这里可能出现1个main或者没有main,因为线程执行的太快,阻塞队列的已经被执行到了,所以可能有偏差)
在这里插入图片描述
3.DiscardOldestPolicy() :抛出队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交当前任务

public static void main(String []args){// 自定义线程池ExecutorService threadPool = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardOldestPolicy());try{for (int i = 1; i <= 10 ; i++) {threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t办理业务");});//TimeUnit.MILLISECONDS.sleep(200);//在Cache线程池里,如果每次暂停0.2秒那么一个线程就可以处理过了,所以每次都是同一个线程,去掉延时就不是一个线程了}}catch (Exception e){e.printStackTrace();}finally {threadPool.shutdown();}}

在这里插入图片描述
4.DiscardPolicy() :直接丢弃任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种方案。

    public static void main(String []args){// 自定义线程池ExecutorService threadPool = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.DiscardPolicy());try{for (int i = 1; i <= 10 ; i++) {threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t办理业务");});//TimeUnit.MILLISECONDS.sleep(200);//在Cache线程池里,如果每次暂停0.2秒那么一个线程就可以处理过了,所以每次都是同一个线程,去掉延时就不是一个线程了}}catch (Exception e){e.printStackTrace();}finally {threadPool.shutdown();}}

在这里插入图片描述

那么实际生产中,如何配置自定义线程池的参数呢?

在这里插入图片描述

1.CUP密集型:

在这里插入图片描述

2.IO密集型

2.1. 在这里插入图片描述
2.2
在这里插入图片描述

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

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

相关文章

【转】2.1.1 购买阿里云服务器(Ubuntu系统)

购买阿里云服务器 优惠购买链接 戳我购买 Cpu和内存 M2对服务器配置要求比较高&#xff0c; cpu要大于等于1, 内存要大于等于2 选择Ubuntu镜像 最好用官方提供的公共镜像&#xff0c;不要用第三方的。 其他的配置 其他的配置按你自己的需求来选择。 控制台 购买完成后…

死锁编码及定位分析(故障排查)

什么是死锁&#xff1f; 在Java中使用多线程&#xff0c;就会有可能导致死锁问题。死锁会让程序一直卡住&#xff0c;不再程序往下执行。我们只能通过中止并重启的方式来让程序重新执行。 造成死锁的原因&#xff1a; 当前线程拥有其他线程需要的资源当前线程等待其他线程已…

【转】在win10接双显示器(扩展模式)怎么把鼠标游标切换到第二台显示器上?

作者&#xff1a;朱宁 链接&#xff1a;https://www.zhihu.com/question/50002939/answer/120465673 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 使用软件 DisplayFusion Pro 这个软件体量比较大&#xff0c;蓝…

java单例模式(饿汉式和懒汉式的几种不同写法)

1.饿汉式&#xff08;直接创建&#xff09;三种创建方法代码里面都有 第三种静态代码块方式&#xff0c;需要创建个properties文件 package java2;import java.io.IOException; import java.util.Properties;/*** 单例模式设计步骤&#xff1a;* 1.构造器私有化* 2.内部创…

【转】一键将Web应用发布到云-Azure Web App!

我们现在越来越多的传统应用&#xff0c;逐步向云端迁移&#xff0c;原先私有云的部署模式&#xff0c;逐步向云端PaaS IaaS转变。例如&#xff1a; 我们在云端Azure中申请VM虚拟机&#xff0c;将我们的Web应用部署到VM的IIS中&#xff0c;同时做云服务的高可用性集和NLB&…

jvm详解、GC、堆内存参数调优

一些常见面试题&#xff1a; JVM的位置&#xff08;运行在操作系统上&#xff0c;与硬件没有直接的交互&#xff09; 一、jvm体系结构&#xff08;记住背下来&#xff09; 运行时数据区&#xff1a;有亮色的有灰色的&#xff0c;灰色的就是占得内存非常小&#xff0c;几乎不存…

【转】!Dynamics 365 Online通过OAuth 2 Client Credential授权(Server-to-Server Authentication)后调用Web API

微软动态CRM专家罗勇 &#xff0c;回复332或者20190505可方便获取本文&#xff0c;同时可以在第一间得到我发布的最新博文信息&#xff0c;follow me&#xff01; 本文很多内容来自 John Towgood 撰写的Dynamics 365 Online Authenticate with Client Credentials &#xff0c…

JMM(java内存模型)

这篇文章写得挺好的&#xff1a;https://blog.csdn.net/javazejian/article/details/72772461 在多线程环境下&#xff0c;线程之间的要通信,就不得不提JMM(java内存模型) 在JVM内部使用的java内存模型(JMM)将线程堆栈和堆之间的内存分开 jmm的承诺&#xff1a; 1.原子性 2.可…

【转】Postman 生成接口文档

引言 几个朋友想做一个前后端分离的项目&#xff0c;接口文档的重要性那是不言而喻的。生成接口文档的方法真的太多了&#xff0c;Yapi、Swagger等等。但是想公网上访问接口文档并修改的话&#xff0c;还得购买服务器&#xff0c;部署上去。穷码农&#xff0c;哪有钱购买服务器…

JVM的进阶学习(GC Roots、JVM调优与参数配置、)

1. GC Roots&#xff0c;可达性分析 从GC roots的对象作为起始点&#xff0c;从GC Roots对象开始向下搜索&#xff0c;如果一个对象到GCRoots没有任何引用链相连&#xff0c;则说明对象不可用。即给定一个集合的引用作为根出发&#xff0c;通过引用关系遍历对象图&#xff0c;能…

【转】图解phpstorm常用快捷键

转载自 https://segmentfault.com/a/1190000004225643 查询快捷键 CTRLN 查找类 CTRLSHIFTN 全局搜索文件 ,优先文件名匹配的文件 CTRLSHIFTALTN 查找php类名/变量名 ,js方法名/变量名, css 选择器 CIRLB 找变量的来源&#xff0c;跳到变量申明处 (CTRL 鼠标单击 也可以) CTRL…

HQL写topN、Spark写topN

HQL写topN用窗口函数rank() 、row_number()、dense_rank() 1、rank(),跳跃排序&#xff0c;假如第一第二相同&#xff0c;那么第三个就是3 select * from( select id, cn, score, rank() over(partition by id order by score desc)as ranks from top N ) A where ranks&…

【转】Dynamics 365 CRM 开发架构简介

目录 概览 名词解释连接到Dynamics 365 CRM Web APIOrganization service选择 - Web API vs. Organization service扩展服务端扩展应用端正文 Dynamics 365 CRM提供了多种编程模型&#xff0c;你可以灵活地按需选用最佳模式。 本文是对Dynamics 365 CRM编程模型的综述。 回…

查找算法-(顺序查找、二分查找、插值查找、斐波那契查找)

1&#xff09;顺序查找或叫线性查找 就是顺序遍历匹配 2&#xff09;二分查找 package search;public class BinarySearch {/*** 二分查找数组必须有序*//**** param arr 数组* param left 左边索引* param right 右边索引* param findVal 要查找的值* return 找到就返回&…

数据结构 - 哈希表(用数组+链表实现存储员工信息,添加增删查功能)

package hashtab;import java.util.Scanner;public class HashTabDemo {public static void main(String[] args) {//创建一个hashTabHashTab hashTab new HashTab(7);//写一个简单菜单来测试String key "";Scanner sc new Scanner(System.in);while (true){Syste…

数据结构 - 树(二叉树的 前序、中序、后序 遍历)

二叉树遍历&#xff08;前序中序后序&#xff0c;主要是看父节点的输出顺序&#xff09; package tree;public class BinaryTreeDemo {public static void main(String[] args) {//先需要创建一颗二叉树BinaryTree binaryTree new BinaryTree();//创建需要的节点HeroNode root…

【转】c# 操作webservice(经典入门教程+MSDN必胜)(有自己修改的部分)

Web Service基本概念 Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求&#xff0c;轻量级的独立的通讯技术。是:通过SOAP在Web上提供的软件&#xff08;服务&#xff09;&#xff0c;使用WSDL文件进行&#xff0…

数据结构 - 二叉树(前序中序后序查找)

public static int i 1, j 1, k 1;//编写前序查找方法public HeroNode preOrderSearch(int no){System.out.println("前序遍历"(i)"次");if (this.no no){return this;}HeroNode heroNode null;if (this.left ! null){heroNode this.left.preOrderSea…

数据结构 - 二叉树(删除节点)

因为二叉树是单向的&#xff0c;所以要判断当前节点的子节点(左或右)是否是被删除的节点 //递归删除节点//规定&#xff1a;如果是叶子节点就删除节点&#xff0c;如果非叶子节点就删除子树public void delNode(int no){if (this.left !null && this.left.no no){this…

【转】OData – the best way to REST–实例讲解ASP.NET WebAPI OData (V4) Service Client

一、概念介绍 1.1&#xff0c;什么是OData&#xff1f; 还是看OData官网的简单说明&#xff1a; An open protocol to allow the creation and consumption of queryable and interoperable RESTful APIs in a simple and standard way. 这是一个开放的数据查询和服务协议&…