Java线程池架构原理和源码解析Thr

苏孜阿甫 http://baidianfeng.39.net/bdfby/yqyy/

在前面介绍JUC的文章中,提到了关于线程池Excotors的创建介绍,在文章:《java之JUC系列-外部Tools》中第一部分有详细的说明,请参阅;

文章中其实说明了外部的使用方式,但是没有说内部是如何实现的,为了加深对实现的理解,在使用中可以放心,我们这里将做源码解析以及反馈到原理上,Excutors工具可以创建普通的线程池以及schdul调度任务的调度池,其实两者实现上还是有一些区别,但是理解了ThradPoolExcutor,在看SchduldThradPoolExcutor就非常轻松了,后面的文章中也会专门介绍这块,但是需要先看这篇文章。

使用Excutors最常用的莫过于是使用:Excutors.nwFixdThradPool(int)这个方法,因为它既可以限制数量,而且线程用完后不会一直被cach住;那么就通过它来看看源码,回过头来再看其他构造方法的区别:

在《java之JUC系列-外部Tools》文章中提到了构造方法,为了和本文对接,再贴下代码:

publicstaticExcutorSrvicnwFixdThradPool(intnThrads){

rturnnwThradPoolExcutor(nThrads,nThrads,

0L,TimUnit.MILLISECONDS,

nwLinkdBlockingQuuRunnabl());

}

其实你可以自己nw一个ThradPoolExcutor,来达到自己的参数可控的程度,例如,可以将LinkdBlockingQuu换成其它的(如:SynchronousQuu),只是可读性会降低,这里只是使用了一种设计模式。

我们现在来看看ThradPoolExcutor的源码是怎么样的,也许你刚开始看他的源码会很痛苦,因为你不知道作者为什么是这样设计的,所以本文就我看到的思想会给你做一个介绍,此时也许你通过知道了一些作者的思想,你也许就知道应该该如何去操作了。

这里来看下构造方法中对那些属性做了赋值:

源码段1:

publicThradPoolExcutor(intcorPoolSiz,

intmaximumPoolSiz,

longkpAlivTim,

TimUnitunit,

BlockingQuuRunnablworkQuu,

ThradFactorythradFactory,

RjctdExcutionHandlrhandlr){

if(corPoolSiz0

maximumPoolSiz=0

maximumPoolSizcorPoolSiz

kpAlivTim0)

thrownwIllgalArgumntExcption();

if(workQuu==null

thradFactory==null

handlr==null)

thrownwNullPointrExcption();

this.corPoolSiz=corPoolSiz;

this.maximumPoolSiz=maximumPoolSiz;

this.workQuu=workQuu;

this.kpAlivTim=unit.toNanos(kpAlivTim);

this.thradFactory=thradFactory;

this.handlr=handlr;

}

这里你可以看到最终赋值的过程,可以先大概知道下参数的意思:

corPoolSiz:核心运行的poolSiz,也就是当超过这个范围的时候,就需要将新的Thrad放入到等待队列中了;

maximumPoolSiz:一般你用不到,当大于了这个值就会将Thrad由一个丢弃处理机制来处理,但是当你发生:nwFixdThradPool的时候,corPoolSiz和maximumPoolSiz是一样的,而corPoolSiz是先执行的,所以他会先被放入等待队列,而不会执行到下面的丢弃处理中,看了后面的代码你就知道了。

workQuu:等待队列,当达到corPoolSiz的时候,就向该等待队列放入线程信息(默认为一个LinkdBlockingQuu),运行中的队列属性为:workrs,为一个HashSt;内部被包装了一层,后面会看到这部分代码。

kpAlivTim:默认都是0,当线程没有任务处理后,保持多长时间,cachdPoolSiz是默认60s,不推荐使用。

thradFactory:是构造Thrad的方法,你可以自己去包装和传递,主要实现nwThrad方法即可;

handlr:也就是参数maximumPoolSiz达到后丢弃处理的方法,java提供了5种丢弃处理的方法,当然你也可以自己弄,主要是要实现接口:RjctdExcutionHandlr中的方法:

publicvoidrjctdExcution(Runnablr,ThradPoolExcutor)

java默认的是使用:AbortPolicy,他的作用是当出现这中情况的时候会抛出一个异常;其余的还包含:

1、CallrRunsPolicy:如果发现线程池还在运行,就直接运行这个线程

2、DiscardOldstPolicy:在线程池的等待队列中,将头取出一个抛弃,然后将当前线程放进去。

3、DiscardPolicy:什么也不做

4、AbortPolicy:java默认,抛出一个异常:RjctdExcutionExcption。

通常你得到线程池后,会调用其中的:submit方法或xcut方法去操作;其实你会发现,submit方法最终会调用xcut方法来进行操作,只是他提供了一个Futur来托管返回值的处理而已,当你调用需要有返回值的信息时,你用它来处理是比较好的;这个Futur会包装对Callabl信息,并定义一个Sync对象(),当你发生读取返回值的操作的时候,会通过Sync对象进入锁,直到有返回值的数据通知,具体细节先不要看太多,继续向下:

来看看xcut最为核心的方法吧:

源码段2:

publicvoidxcut(Runnabl


转载请注明:http://www.92nongye.com/xxmb/xxmb/204623972.html

  • 上一篇文章:
  •   
  • 下一篇文章: