首页 > 编程语言 >java线程池原理浅析

java线程池原理浅析

时间:2024-03-28 11:12:45浏览次数:22  
标签:java 队列 创建 任务 线程 TimeUnit 执行 浅析

 

问题:

查询大数据量的时候,例如一次返回50w数据量的包,循环去查询发现读取会超时。

解决方案:

经过思考采用多线程去分页查询。使用线程池创建多个线程去查询分页后的数据最后汇总一下,解决了一次查询大量数据返回超时的问题。

一次查询现状:

 


 

多线程分页查询改造图:

 


 

效果:使用多线程去查询查询时间由原来的10s减少到现在的300ms。

线程池是什么?

线程池(Thread Pool)是一种基于池化思想管理线程的工具,经常出现在多线程服务器中,如MySQL,clickhouse等数据库。

线程池好处:

1.降低资源消耗:通过池化技术重复利用已创建的线程,降低线程创建和销毁造成的损耗。

2.提高响应速度:任务到达时,无需等待线程创建即可立即执行。

3.提高线程的可管理性:线程是稀缺资源,如果无限制创建,不仅会消耗系统资源,还会因为线程的不合理分布导致资源调度失衡,降低系统的稳定性。

4.使用线程池可以进行统一的分配、调优和监控。提供更多更强大的功能:线程池具备可拓展性,允许开发人员向其中增加更多的功能。比如延时定时线程池ScheduledThreadPoolExecutor,就允许任务延期执行或定期执行。

线程池解决的问题是什么:

1.频繁申请/销毁资源和调度资源,将带来额外的消耗,可能会非常巨大。

2.对资源无限申请缺少抑制手段,易引发系统资源耗尽的风险。

3.系统无法合理管理内部的资源分布,会降低系统的稳定性。

Java线程池参数解析:

Java 提供的线程池相关的工具类中,最核心的是 ThreadPoolExecutor,完备的构造函数如下:

ThreadPoolExecutor(
 int corePoolSize,
 int maximumPoolSize,
 long keepAliveTime,
 TimeUnit unit,
 BlockingQueue<Runnable> workQueue,
 ThreadFactory threadFactory,
 RejectedExecutionHandler handler) 

参数说明:

corePoolSize:线程池的核心线程数

备注:默认情况下,线程池创建后的初始线程数为 0,当有任务到来就会创建一个线程去执行任务,当线程池中的线程数目达到 corePoolSize,就会把到达的任务放到缓存队列当中。

maximumPoolSize:线程池的最大线程数

备注:核心线程忙不过来且任务存储队列满了的情况下,还有新任务进来的话就会继续开辟线程,但是也不是任意的开辟线程数量,线程数(包含核心线程)达到maximumPoolSize后就不会产生新线程了,就会执行拒绝策略。

keepAliveTime:当活跃线程数大于核心线程数时,空闲的多余线程最大存活时间

备注:默认情况下,当线程池中的线程数大于 corePoolSize 时,如果一个线程空闲的时间达到keepAliveTime,则该线程会终止,直到线程池中的线程数不超过 corePoolSize。但是如果调用了 allowCoreThreadTimeOut(true) 方法,此时就算线程池中的线程数不大于corePoolSize ,keepAliveTime 参数也会起作用,直到线程池中的线程数为 0。

unit:参数 keepAliveTime 的时间单位。

取值:

TimeUnit.DAYS;               //天
TimeUnit.HOURS;             //小时 
TimeUnit.MINUTES;           //分钟 
TimeUnit.SECONDS;           //秒
TimeUnit.MILLISECONDS;      //毫秒 
TimeUnit.MICROSECONDS;      //微妙
TimeUnit.NANOSECONDS;       //纳秒 

workQueue:任务阻塞队列,用来存储等待执行的任务。

备注:

核心线程数满了后还有任务继续提交到线程池的话,就先进入workQueue。

workQueue通常情况下有如下选择:

LinkedBlockingQueue:无界队列,意味着无限制,其实是有限制,大小是int的最大值。也可以自定义大小。

ArrayBlockingQueue:有界队列,可以自定义大小,到了阈值就开启新线程(不会超过maximumPoolSize)。

SynchronousQueue:Executors.newCachedThreadPool();默认使用的队列。也不算是个队列,他不没有存储元素的能力。

一般都采取LinkedBlockingQueue,因为他也可以设置大小,可以取代ArrayBlockingQueue有界队列。

threadFactory:用于创建新线程的线程工厂。

备注:默认采用的是DefaultThreadFactory,主要负责创建线程。newThread()方法。创建出来的线程都在同一个线程组且优先级也是一样的。

handler:拒绝策略,任务量超出线程池的配置限制或执行shutdown还在继续提交任务的话,会执行handler的逻辑。

备注:

如果线程池中所有的线程都在忙碌,并且工作队列也满了(前提是工作队列是有界队列),那么此时提交任务,线程池就会拒绝接收。拒绝策略可以通过 handler 参数来指定。

ThreadPoolExecutor 提供了以下4种拒绝策略:

CallerRunsPolicy:提交任务的线程自己去执行该任务。

AbortPolicy:默认的拒绝策略,会 throws RejectedExecutionException。

DiscardPolicy:直接丢弃任务,没有任何异常抛出。

DiscardOldestPolicy:丢弃最老的任务,就是把最早进入工作队列的任务丢弃,然后把新任务加入到工作队列。

线程池工作原理:

 


 

 

java提供的常用线程池:

1.newCachedThreadPool:用来创建一个可以无限扩大的线程池,适用于负载较轻的场景,执行短期异步任务。(可以使任务快速得到执行,因为任务时间执行短,可以很快结束,也不会造成cpu过度切换)

2.newFixedThreadPool:创建一个固定大小的线程池,因为采用无界的阻塞队列,所以实际线程数量永远不会变化,适用于负载较重的场景,对当前线程数量进行限制。(保证线程数可控,不会造成线程过多,导致系统负载更为严重)

3.newSingleThreadExecutor:创建一个单线程的线程池,适用于需要保证顺序执行各个任务。

4.newScheduledThreadPool:适用于执行延时或者周期性任务。

标签:java,队列,创建,任务,线程,TimeUnit,执行,浅析
From: https://www.cnblogs.com/Jcloud/p/18101130

相关文章

  • 线程池的介绍与实现(多线程代码案例)
    目录概念:ThreadPoolExecutorintcorePoolSizeintmaximumPoolsizelongkeepAliveTimeTimeUnitunitBlockingQueuewokrQueueThreadthreadFactoryRejectedExecutionHandlerhandler1.ThreadPoolExecutor.Abortpolicy2.ThreadPoolExecutor.CallerRunsPolicy3.Thre......
  • Java零基础-集合:Java 8新增的集合操作
    哈喽,各位小伙伴们,你们好呀,我是喵手。  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把......
  • Java零基础-集合:集合框架中的工具类
    哈喽,各位小伙伴们,你们好呀,我是喵手。  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把......
  • Java零基础-集合:集合的常用方法
    哈喽,各位小伙伴们,你们好呀,我是喵手。  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把......
  • On Java8读书笔记
    ObjectsEveryWhere使用Reference掌控对象掌控一个对象有两种不同的方式:直接掌控变量本身or间接掌控一个"通道",通过"通道"可以掌控对象在Java中,我们通过间接的方式掌控对象,而这个"通道"就是ReferenceReference不同于对象本身,对象本身往往是"臃肿的"(对象内包括字段和......
  • 华为OD机试 - 最多购买宝石数目(Java & JS & Python & C & C++)
    须知哈喽,本题库完全免费,收费是为了防止被爬,大家订阅专栏后可以私信联系退款。感谢支持文章目录须知题目描述输入描述输出描述解题思路:题目描述橱窗里有一排宝石,不同的宝石对应不同的价格,宝石的价格标记为gems[i]0≤i<nn=gems.length宝石可同时......
  • 【Flutter 面试题】 Dart 是不是单线程模型?是如何运行的?
    【Flutter面试题】Dart是不是单线程模型?是如何运行的?文章目录写在前面口述回答补充说明示例:异步编程示例:使用Isolates处理计算密集型任务总结写在前面......
  • JavaWeb——HttpServletRequest获取请求头信息和请求中的参数信息用法
    HttpServletRequest接口提供了访问HTTP请求信息的方法,包括请求行和请求头。下面是一些常用的HttpServletRequest方法,用于获取请求行和请求头信息。StringgetMethod():返回请求的HTTP方法,如GET、POST等。StringgetRequestURI():返回请求的URI,不包括查询字符串。String......
  • JAVA------基础篇
    java基础1.JDKJDK:javadevelopmentkitJRE:javaruntimeenvironmentJDK包含JREjava跨平台:因为java程序运行依赖虚拟机,虚拟机需要有对应操作系统的版本,而jre中有虚拟机。当你想要在Linux系统下运行,则需要安装对应的虚拟机,及对应的jdk版本,而对应的jdk版本中的jre有对......
  • JavaScript变量/数组
    变量1、var:全局变量(作用域范围大,且允许重复声明)2、let:局部变量(作用域仅在代码块内,且不允许重复声明)3、const:常量(一旦声明,常量的值不能改变)数组特点:长度可变,类型可变for和foreach的区别:1、for遍历数组中的所有元素2、foreach遍历数组中有值的元素,并调用一次传入的函......