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

线程池

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

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

并发线程之线程池

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

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

Thread的弊端

new Thread()

线程池的优点

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

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

ThreadPoolExecutor 介绍

构造函数和参数

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

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个构造函数,发现前面三个构造器都是调用的第四个构造器进行的初始化工作。

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

构造器中各个参数的含义

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进行转发+关注,后面也将不定时的更新干货!感谢大家!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容