Java面试题之线程池应用及原理

一、线程是不是越多越好

  1. 线程在java中是一个对象,更是操作系统的资源,线程创建、销毁需要时间。如果创建时间 + 销毁时间大于执行时间就很不合算。

  2. java对象占用堆内存,操作系统线程占用系统内存,根据jvm规范,Linux/x64操作系统一个线程默认最大栈大小为1m。

  3. 操作系统需要频繁切换线程上下文(大家都想被运行),影响性能。

备注:各平台默认线程栈大小如下,具体请参考:Java虚拟机相关参数说明

image.png




二、线程池API

1、接口定义和实现类

image.png

2、方法定义

image.png
image.png

3、ThreadPoolExecutor构造器参数详解

我们先看下线程池执行器的全参构造器具体有哪些参数,下面是该构造器的定义:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {}
  • corePoolSize:核心线程数,即使任务队列中没有任务,处于空闲状态也不会被回收的线程数,除非指定allowCoreThreadTimeOut参数为true。
  • maximumPoolSize:线程池可创建的最大线程数,超过改值会出发拒绝策略处理器逻辑。
  • keepAliveTime:当线程池的线程数量大于corePoolSize,多余的空闲线程等待新任务的最长存活时间,如果没有新任务,大于corePoolSize的空闲线程将会被回收。
  • BlockingQueue:任务队列,这个队列只会保存通过execute方法提交的任务。
  • ThreadFactory :线程创建工厂,可以自定义线程名称前缀等。
  • RejectedExecutionHandler :拒绝执行策略,当任务队列已满且池中的线程数超过maximumPoolSize,将会触发拒绝执行。

常见的RejectedExecutionHandler 如下,

  • DiscardPolicy:直接放弃执行。
  • DiscardOldestPolicy:丢弃任务队列头部的任务,再调用execute方法执行当前提交的任务。
  • AbortPolicy:直接抛出RejectedExecutionException异常,该异常为运行时异常。
  • CallerRunsPolicy:直接由主线程执行。

4、Executors工具类

Executors工具类可用来创建各种线程池,常用方法如下:

  • newFixedThreadPool(int nThreads)创建一个固定大小、任务队列容量无界的线程池。其核心线程数=最大线程数,任务队列为无界队列(LinkedBlockingQueue),无超时时长。
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(
        nThreads, 
        nThreads,
        0L, 
        TimeUnit.MILLISECONDS, 
        new LinkedBlockingQueue<Runnable>());
    }
  • newCachedThreadPool()创建的是一个大小无界的缓冲线程池。它的任务队列是一个同步队列(SynchronousQueue)。任务加入到池中,如果池中有空闲线程,则用空闲线程执行,如无则创建新线程执行。池中的线程空超过60秒,将被销毁释放。线程数随任务的多少变化。适用于执行耗时较小的异步任务。池的核心线程数=0,最大线程数=Integer.MAX_VALUE。
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, 
        Integer.MAX_VALUE,
        60L, 
        TimeUnit.SECONDS,
        new SynchronousQueue<Runnable>());
    }

  • newSingleThreadExecutor()创建的是只有一个线程来执行无界队列任务的单一线程池。该线程池确保任务按加入的顺序一个个依次执行。当唯一的线程因任务异常中支时,将创建一个新的线程来继续执行后续的任务。与newFixedThreadPool(1)的区别在于,单一线程池的池大小在方法中是硬编码的,不能再改变的。




三、线程池原理

1、线程池组成

  • 线程池管理器:用于创建并管理线程池,包括创建线程池,销毁线程池,添加新任务。
  • 工作线程:线程池中线程,在没有任务时处于等待状态,可以循环执行任务。
  • 任务接口:每个任务必须实现的接口,供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等。
  • 任务队列:用于存放没有处理的任务,提供一种缓冲机制。

2、线程池中的概念

  • workerCount:池中允许启动且不允许停止的线程数量。
  • runState:线程池状态,是否运行或者停止,主要有下面几个值:
  1. RUNNING:接收新任务并且处理入队任务。
  2. SHUTDOWN:不接受新任务,但处理入队任务。
  3. STOP:即不接受新任务,又不处理入队任务,并且会中断运行中的任务。
  4. TIDYING:所有任务已经终结,workerCount为0,转变成TYDING状态的线程将会调用terminated()方法。
  5. TERMINATED:terminated()方法执行完成。
  • 线程池状态转变过程
  1. RUNNING -> SHUTDOWN:shutdown()方法调用,或者隐式调用finalize()。
  2. (RUNNING or SHUTDOWN) -> STOP:shutdownNow()方法调用。
  3. SHUTDOWN -> TIDYING:队列和线程池都为空。
  4. STOP -> TYDING:线程池为空。
  5. TYDING -> TERMINATED:terminated()方法执行完成。

3、线程池任务执行过程

  1. 是否达到核心线程数量? 没达到,创建一个工作线程来执行任务。
  2. 工作队列是否已满?没满,则将新提交的任务存储在工作队列中。
  3. 是否达到线程池最大数量?没达到,则创建一个新的工作线程来执行任务。
  4. 最后,执行拒绝策略来处理这个任务。


    image.png

四、如何确定合适的线程数量

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

推荐阅读更多精彩内容