线程池

最近看到线程池,被里边乱七八槽的参数给搞晕了,你能不能给我讲讲呀?

对于从事后端开发的同学来说,线程是必须要使用了,因为使用它可以提升系统的性能。但是,创建线程和销毁线程都是比较耗时的操作,频繁的创建和销毁线程会浪费很多CPU的资源。此外,如果每个任务都创建一个线程去处理,这样线程会越来越多。我们知道每个线程默认情况下占1M的内存空间,如果线程非常多,内存资源将会被耗尽。这时,我们需要线程池去管理线程,不会出现内存资源被耗尽的情况,也不会出现频繁创建和销毁线程的情况,因为它内部是可以复用线程的。

并发线程之线程池

初始化线程池后,把任务丢进去,等待调度就可以了,使用起来比较方便。

JAVA中 Thread 是线程类,不建议直接使用 Thread 执行任务,在并发数量比较多的情况下,每个线程都是执行一个很短的时间就任务结束了,这样频繁创建线程会大大降低系统的效率,因为频繁的创建和销毁线程需要时间。而线程池可以复用,就是执行完一个任务,并不销毁,而是可以继续执行其它任务。

Thread的弊端

new Thread()

线程池的优点

  1. 重用存在的线程,减少对象创建,消亡的开销,性能佳,降低资源消耗。
  2. 可以控制最大并发线程数,提高系统资源利用率,避免过多资源竞争,避免阻塞,提高响应速度。
  3. 提供定时执行,定期执行,单线程,并发数控制等功能,以提高线程的可管理性。

Executors利用工厂模式向我们提供了4种线程池实现方式,但是并不推荐使用,原因是使用Executors创建线程池不会传入相关参数而使用默认值所以我们常常忽略了那些重要的参数(线程池大小、缓冲队列的类型等),而且默认使用的参数会导致资源浪费,不可取。

ThreadPoolExecutor 介绍

构造函数和参数

java.uitl.concurrent.ThreadPoolExecutor 类是线程池中最核心的一个类。

public class ThreadPoolExecutor extends AbstractExecutorService {/** 构造函数 1 */public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {}/** 构造函数 2 */public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory) {}/** 构造函数 3 */public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler) {}/** 构造函数 4 */public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {}
}

ThreadPoolExecutor类中提供了四个构造方法,在构造函数4中,参数最多,通过观察其他3个构造函数,发现前面三个构造器都是调用的第四个构造器进行的初始化工作。

构造器中各个参数的含义

corePoolSize 核心线程池的大小,在创建了线程池后,默认情况下,线程池中没有任何的线程池,而是等任务过来了再去创建线程执行任务。除非调用了预创建线程的方法,即在没有任务到来之前就创建 corePoolSize 个线程或者一个线程。当线程池中的线程数量到达 corePoolSize 后,就会把到达的任务放到缓存队列里面。

  • prestartCoreThread() : 预创建一个核心线程,使其闲置等待工作。
  • prestartAllCoreThreads() : 启动所有核心线程,导致它们空闲地等待工作。

maxnumPoolSize 线程池中最大的线程数,是一个非常重要的参数,它表示在线程池中最多能创建多少线程。

keepAliveTime表示线程在没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于 corePoolSize 时, keepAliveTime 才会起作用,即当线程池中的线程数大于 corePoolSize ,如果一个线程的空闲时间达到 keepAliveTime ,则会终止直到线程池中的线程数量不大于 corePoolSize 。但是如果调用了 allowCoreThreadTimeOut(boolean) 方法,在线程池中线程数不大于 corePoolSize 时, keepAliveTime 参数也会起作用,直到线程池中的线程数为0。

unit参数 keepAliveTime 的时间单位,有7种取值,在 TimeUnit 类中有7种静态属性。

  • TimeUnit.DAYS : 以 天 为单位 ;
  • TimeUnit.HOURS : 以 小时 为单位 ;
  • TimeUnit.MINUTES : 以 分钟 为单位 ;
  • TimeUnit.SECONDS : 以 秒 为单位 ;
  • TimeUnit.MILLISECONDS : 以 毫秒 为单位 ;
  • TimeUnit.MICROSECONDS : 以 微妙 为单位 ;
  • TimeUnit.NANOSECONDS : 以 纳秒 为单位 ;

workQueue 一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般有以下几种选择。

Integer.MAX_VALUE

threadFactory 线程工厂,主要用来创建线程。线程池最重要的一项工作,就是在满足某些条件情况下创建线程。在 ThreadPoolExecutor 线程池中,创建线程的操作时交给 ThreadFactoty 来完成。使用线程池,就必须要指定 threadFactory 。如果我们的构造器中没有指定使用 ThreadFactory ,这个时候 ThreadPoolExecutor 就会使用默认的
ThreadFactory:DefaultThreadFactory

handler在ThreadPoolExecutor线程池中还有一个重要的接口:RejectedExecutionHandler。当提交给线程池的某一个新任务无法直接被线程池中“核心线程”直接处理,又无法加入等待队列,也无法创建新的线程执行;又或者线程池已经调用shutdown()方法停止了工作;又或者线程池不是处于正常的工作状态;这时候ThreadPoolExecutor线程池会拒绝处理这个任务,触发创建ThreadPoolExecutor线程池时定义的RejectedExecutionHandler接口的实现,表示当拒绝处理任务时的策略,有以下四种取值,四种值都为其静态内部类:

  • ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常
  • ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
  • ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行新提交的任务。

ThreadPoolExecutor 执行 execute 方法分下面4种情况

  • 如果当前运行的线程少于 corePoolSize ,则创建新的线程来执行任务(执行这一步骤需要获取全局锁)
  • 如果运行的线程等于或者多于 corePoolSize ,则将任务加入到 BlockingQueue
  • 如果无法将任务加入 BlockingQueue (队列已满),则创建新的线程来处理任务(执行这一步骤需要获取全局锁)
  • 如果创建新线程将当前运行的线程超出 maxnumPoolSize ,任务被拒绝,并调用 RejectedExecutionHandler.rejectedExecution() 方法。

由于篇幅限制,就将有关并发和线程池的内容展示到这里了,希望可以对大家学习并发和线程池有所帮助,喜欢的小伙伴可以帮LZ进行转发+关注,后面也将不定时的更新干货!感谢大家!

原文链接:
https://www.tuicool.com/articles/E73yqq7

灵魂发问!Java并发和线程池,只言片语真的可以讲清楚吗?相关推荐

  1. Java 并发编程 -- 线程池源码实战

    一.概述 小编在网上看了好多的关于线程池原理.源码分析相关的文章,但是说实话,没有一篇让我觉得读完之后豁然开朗,完完全全的明白线程池,要么写的太简单,只写了一点皮毛,要么就是是晦涩难懂,看完之后几乎都 ...

  2. 灵魂发问,Java并发和线程池,只言片语真的可以讲清楚吗?

    线程池 最近看到线程池,被里边乱七八槽的参数给搞晕了,你能不能给我讲讲呀? 对于从事后端开发的同学来说,线程是必须要使用了,因为使用它可以提升系统的性能.但是,创建线程和销毁线程都是比较耗时的操作,频 ...

  3. Java并发编程——线程池的使用

    在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统 ...

  4. java workerdone_【架构】Java并发编程——线程池的使用

    前言 如果我们要使用线程的时候就去创建一个,这样虽然非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为 ...

  5. Java 并发总结——线程池

    一.线程池 在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程 (1)线程池的作用 1.降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 2.提高响应 ...

  6. Java并发教程–线程池

    Java 1.5中提供的最通用的并发增强功能之一是引入了可自定义的线程池. 这些线程池使您可以对诸如线程数,线程重用,调度和线程构造之类的东西进行大量控制. 让我们回顾一下. 首先,线程池. 让我们直 ...

  7. Java并发:线程池详解(ThreadPoolExecutor)

    前言 现在在实现异步时,基本都是使用线程池来实现,线程池在工作应用的还是比较频繁的,本文将就线程池的使用.相关原理和主要方法源码进行深入讲解学习. 线程池的基本使用 package com.joonw ...

  8. Java并发编程——线程池初步

    概述: 线程池机制是事先创建一些线程等待服务端程序的调用,这些线程保存在一个数组结构中,称为"线程池".当服务器有任务执行时,就从线程池中取出一个线程并给其分配任务,当线程任务执行 ...

  9. java并发编程——线程池的工作原理与源码解读

    2019独角兽企业重金招聘Python工程师标准>>> 线程池的简单介绍 基于多核CPU的发展,使得多线程开发日趋流行.然而线程的创建和销毁,都涉及到系统调用,比较消耗系统资源,所以 ...

最新文章

  1. python处理excel文件-使用Python进行Excel文件处理
  2. Linux下SSH远程连接断开后让程序继续运行解决办法
  3. C++之指针探究(十一):函数名的本质和函数指针
  4. https 慢_dba+开源工具:可视化分析MongoDB慢查询日志
  5. 当前最快的实例分割模型:YOLACT 和 YOLACT++
  6. HTML5 Canvas JavaScript库 Fabric.js 使用经验
  7. 川希:哪些网站百度收录快排名好,高权重网站必收藏!
  8. matlab面元法计算naca翼型的升力系数(关于攻角的曲线)
  9. springboot整合tk-mybatis框架搭建
  10. 04 高性能网络设计专栏-网络编程
  11. 10个良心的软件免费下载网站,你知道吗?
  12. 2020年8月-北京-百度度小满面试题(已offer)
  13. gb28181简单解包rtp ps流,推出rtmp(java版基于springboot):六、解包rtp ps流,推出rtmp
  14. 我真没脸写 2021年总结
  15. Qt之与游戏手柄的交互(一)
  16. 解决办法:E: 仓库 “......” 没有 Release 文件。
  17. YOLO v3详细解读
  18. 师者,传道授业解惑也
  19. 【量子万象】植物不可怕 就怕植物懂量子力学
  20. 千万级ERP项目的交付思考

热门文章

  1. 淘宝店主成十大高危职业 生存状态受关注
  2. 商业研究(9):入口思维(刚需、频次、免费、变现)
  3. c语言乐谱编辑软件怎么用的,如何优雅的编辑一份乐谱|打谱软件Lilypond(一)...
  4. 触目2006信息化之灾
  5. centos7 系统安装及开机优化
  6. 解决IDEA占用C盘空间过大的问题
  7. linux 软链接重新连接,Linux总结(十二)set_uid set_gid stic_bit 软链接 硬链接
  8. 特斯拉蛇形充电机器人_特斯拉也造出蛇形机器人,专为充电使用!
  9. 投资绩效约束下的有限套利(Shleifer,Vishny)
  10. vue读取文件夹下面的文件名称