线程池解析第二章-线程池源码问题总结

线程池解析第一章-源码解析
线程池解析第二章-线程池源码问题总结

上篇文章分析了关于线程池在源码层面对提交任务的处理方式,但是光光去看源码,有些值得思考的地方可能会被忽略,但是这些点可能是对线程池理解至关重要,理解了才能对线程池有更为整体的认识,本篇文章主要是对阅读源码的一个总结,把一些问题拿出来进行一个总结

Q1:为什么要使用线程池
A:当创建一个线程和销毁一个线程所需要的时间大于这个线程的执行时间,那么这就是一个资源上的浪费,当线程创建过多了以后,线程间的切换则会消耗大量的内存和资源,线程池中保存了空闲的线程,可以利用空闲的线程,避免创建销毁的资源浪费

Q1-0:线程和操作系统及CPU的关系
A:线程实际上是操作系统的概念,java本身并不能创建线程,而是调用操作系统提供的接口,实现线程的创建,控制,销毁,实际创建的是操作系统线程,在经由操作系统分配到空闲的CPU上

  • 上面两个问题是对于线程最基本的概念,只有理解了线程的由来,才能对多线程有更完整的认识

Q2:线程池中的核心线程是如何循环利用的
A:其实这个问题在阅读完源码后就很好理解了,当执行runWorker()方法的时候,首先会去获取任务,然后有一个while语句去判断当前任务是否为空,或者调用getTask()方法去判断结果是否为空而对应的getTask方法则是去循环获取workqueue阻塞队列中的任务,此处实现了核心线程的循环利用,只不过此处需要注意对有,核心线程在默认情况下会一直存在,当核心线程在被allowCoreThreadTimeOut为true后,也是可以被销毁的,但是非核心线程在keepalivetime过期后如果没有获取到任务将会自动被销毁

Q3:在线程池中,如果线程没有全部执行任务,为什么不是利用闲置的而是创建新的线程呢?
A:这是我之前代码没读完的时候产生的一个问题,看完代码后这个问题就很简单了,对于核心线程来说,如果队列任务为空,那么这些核心线程就是属于空闲状态,所以核心线程是否处于空闲状态一个很关键的所在就是工作队列中是否有任务,如果想要利用空闲线程,那么任务队列就必须有任务,但如果此刻线程池线程数还没有达到核心线程数,这时候则会创建核心线程,但是当线程数量大于核心线,则会加入到工作队列当中,这时候就成功利用闲置的核心线程,但是不会增加新的线程

Q4:Set类型的workers又是做什么的,为什么worker会加入到workers当中
A:workers是当前线程池中所有线程的集合,当有新的线程被创建后,都会被加入到这个集合当中,对于workers的操作,只有在拿到mainLock的时候才能进行访问,在shutdown()等关闭方法中,被用作检测以确保呼叫者可以中断workers集合中的每一个工作线程,并对所有workers中的工作线程进行中断

Q5:在addWorker方法中,当任务加入任务队列中且线程池中可用线程数量为0时,调用addWorker(null, false)是什么意思,当无法再向任务队列中添加任务时,调用addWorker(command, false)的作用是什么,他和addWorker(command, true)方法有什么区别
A: 调用addWorker(null, false)的作用,addWorker是为了创建线程处理传递的任务,此处传递的task为空,说明此处创建了一个任务为空的worker对象,目的只有一个,就是处理之前被加入到任务队列中的task。
addWorker(command, false)和addWorker(command, true)有什么区别,在addWorker方法中,只是简单的做了一个线程数量的判断,但是在getTask方法中,如果是非核心线程,在keepAliveTime内没有获取到任务,将会销毁非核心线程

  • Q2~5主要说的是线程池实现逻辑上的问题,如有不对的地方欢迎指正

Q6:在线程池当中,submit()/execute()之间关系及区别
A:线程池的执行入口通常为submit()/execute(),而submit()方法可以返回线程执行的结果,使用execute()方法则不需要返回执行的结果,submit()方法实际是调用了ThreadPoolExecutor父类AbstractExecutorService的submit方法,该方法可以接收两个类型的参数,一个是Runnable对象,一个是callable对象,但是在submit()方法中会调用newTaskFor()返回一个...
FutureTask对象,在构造FutureTask对象的时候,如果传入的是Runnable类型,也会被转换成Callable类型

Q7:在线程池当中,runnable和callable的关系及区别
A:线程池在接受任务的时候,往往接受两种类型,一种是runnable一种是callable类型,runnable类型需要实现run方法,而callable类型则需要实现call方法,在线程池进行提交任务的操作中,通过submit提交是可以事先获取一个futureTask对象的返回值,说明提交到submit中的对象是实现了call方法的,但在源码中submit是可以接受runable对象,这是因为submit在接受到了runnable对象后,会将runnable转换成callable对象,我前面说了,callable对象是需要实现call方法的,但是被转换的runnbale只有run方法,这一步实际上源码的转换类帮助我们重写了call方法,在call方法中嵌套了run方法

Q8:线程池执行任务类,如果是通过submit方法提交的,那么如何将计算的结果放入futureTask对象当中的
A:在进行submit方法进行提交任务的时候,实际返回的是一个 RunnableFuture对象,在线程池调用run方法的时候,实际调用的是RunnableFuture接口,对应的实现类是futureTask,在futureTask对应接口RunnableFuture的run方法的实现方法中,则是调用了任务类的call方法,并将获取到的结果存入futureTask对象当中,对于futureTask中的实现逻辑不是很了解的同志可以参考我之前的文章
Future三重奏第二章:FutureTask源码解析

  • Q6,Q7,Q8这三个模块的问题需要放在一起理解,他不是单独的孤零零的问题,而是综合在一起的,彼此紧密关联的问题点,主要说明的是对于线程池中不同提交方式带来的两者之间的差别和实现结果上的不同,且其中涉及到futureTask类的理解,如果对futureTask不是很清楚,那么对于线程池的实现,在理解上就不能说是特别的通透,建议有兴趣的朋友可以看看我之前写的文章

Q9:内部类Worker是继承实现了AQS的,目的是什么,体现在什么地方
A:主要从Worker对创建以及使用上来阐述这个问题,分为以下几点
1:当线程池创建Worker对象的时候,对state对默认赋值为-1,此处对目的是为了防止线程在执行前被标记中断
2:在线程池调用关闭操作的时候,首先会获取线程集,依次取出当中每一个线程,当线程还没有执行任务and xxxx 的时候,将会被标记打断,此处注意,如果线程对state为-1,无法被标记为中断
3:在线程池中执行runWorker方法的时候,首先需要调用w.unlock()方法,调用此方法将当前线程的state置为0,目的是为了防止线程在被调用前就被标记中断,调用此方法后,线程就可以被置为中断状态

Q10:interrupt,interrupted,isinterrupted的关系和作用
A:在这里提出这个问题是因为在上面的问题中,当线程加锁后,需要判断当前线程是否需要被中断,在一系列当判断后,将会对线程进行中断操作,所以此处单独提出来看
1:interrupt的作用是对当前线程进行中断,只能作用在当前线程
2:interrupted的作用是返回当前线程的中断状态,并清除中断位
3:isInterrupted的作用就是返回当前线程的中断状态,不做任何操作

Q11:对于线程池当中执行拒绝策略的解析
A:当线程池中任务队列数量已满且线程数量超过线程池最大数量的时候,将会执行拒绝策略,拒绝策略有四类,具体执行何种拒绝策略需要视创建线程池时选择的拒绝策略而定,四种拒绝策略会采用四种不同的处理方式,且都为ThreadPoolExecutor内部类,实现了接口RejectedExecutionHandler中的执行方法,建议此处查看相关源码
1:AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
2:DiscardPolicy:也是丢弃任务,但是不抛出异常。
3:DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程),通过e.getQueue().poll()实现拒绝策略
4:CallerRunsPolicy:由调用线程处理该任务,相关代码:r.run();直接调用线程处理

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