从源码对线程池ThreadPoolExecutor分析

一、 ThreadPoolExecutor中的线程池运行状态

​ ThreadPoolExecutor中控制线程池状态是由一个AtomicInteger对象ctl来表示的,取前3位来表示状态。

    //ThreadPoolExecutor中的部分代码
	private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));//表示线程池状态和线程数量
    private static final int COUNT_BITS = Integer.SIZE - 3;		//aka 29
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;//aka (2^29)-1
    private static final int RUNNING    = -1 << COUNT_BITS;		//最高三位为111
    private static final int SHUTDOWN   =  0 << COUNT_BITS;		//......  000
    private static final int STOP       =  1 << COUNT_BITS;		//        001
    private static final int TIDYING    =  2 << COUNT_BITS;		//        010
    private static final int TERMINATED =  3 << COUNT_BITS;		//        011

​ 也就是说,ThreadPoolExecutor的线程池最大容量即(2^29-1)。

    private static int runStateOf(int c)     {
    return c & ~CAPACITY; }
    private static int workerCountOf(int c)  {
    return c & CAPACITY; }
	private static int ctlOf(int rs, int wc) {
    return rs | wc; }

​ 以上三个方法是使用了位运算来分别获得:线程池运行状态、线程数量以及ctl的值。

​ 与运算的特点就是同为1的情况下结果才为1,其余为0;或运算则是有一个为1的情况下就为1,当同为0的时候结果才是0。

​ 第一个方法runStateOf是将c跟默认的CAPACITY取反后再做与运算,CAPACITY是低29位都为1的一个数,取反之后就只有前三位为1了,再结合第一段分析的状态表示,即可知道这个方法是用来获取线程池运行状态。

​ 第二个方法workerCountOf是将c跟默认的CAPACITY做与运算,那么就可以获得低29位的情况,也就是默认情况下线程池中的线程数量。

​ 第三个方法ctlOf就是将workerCountrunningState合并成ctl

而线程池的状态具体意义如下

RUNNING:处于RUNNING状态的线程池能够接受新任务,以及对新添加的任务进行处理。

SHUTDOWN:处于SHUTDOWN状态的线程池不可以接受新任务,但是可以对已添加的任务进行处理。

STOP:处于STOP状态的线程池不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。

TIDYING:当所有的任务已终止,ctl记录的"任务数量"为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。

TERMINATED:线程池彻底终止的状态。

以上就是线程池状态的简要分析了,在java源码中能看到很多地方使用位运算来压缩状态的体积,比如说在读写锁ReentrantReadWriteLock中也是用了一个整型变量来表示读锁和写锁的状态,其中高16位表示读状态而低16位则表示写状态。

二、 ThreadPoolExecutor中的构造器
	public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
   
    	//...
        this.acc = System.getSecurityManager() == null ? null : AccessController.getContext();
        //acc为AccessControlContext对象,具体只在ThreadPoolExecutor的finalize方法中用到。
        //而这一个类我根据注释翻译了一下,是用于根据压缩的context来决定使用哪一个系统资源;具体的还希望有大佬来解释解释。
		//...
    }

ThreadPoolExecutor最终执行的构造器如上所示,一共有7个参数。

参数名 参数类型 参数具体作用
corePoolSize int 线程池中核心池的大小,也就是说核心池中的线程最大数量。核心池中的线程即使没有任何的任务去工作,这些线程也不会被销毁,除非设置了allowCoreThreadTimeOut
maximumPoolSize int 线程池的线程最大数量
keepAliveTime long 线程池中非核心池线程或设置了allowCoreThreadTimeOut时,线程根据这个值检查活性,一旦超时则销毁线程,也就是说如果设置了allowCoreThreadTimeOut,那么就没有核心线程这一概念了
unit TimeUnit 线程keepAliveTime的时间单位
workQueue BlockingQueue 线程的等待队列
threadFactory ThreadFactory 用于构造线程
handler RejectedExecutionHandler 拒绝执行线程的处理器

​ 使用线程池的时候,最好不要使用默认的实现(指的是直接使用Executors里面的一些静态方法生成的线程池)而是自己new一个,因为在这些默认的实现中workQueue使用了new LinkedBlockingQueue<Runnable>()来创建线程的等待队列,点进去可以看到他的最大容量是Integer.MAX_VALUE。一旦线程等待的数量非常大,就会产生OutOfMemoryException。因此最好是自己主动new一个线程池。

    /**
     * Creates a {@code LinkedBlockingQueue} with a capacity of
     * {@link Integer#MAX_VALUE}.
     */
    public LinkedBlockingQueue() {
   
        this(Integer.MAX_VALUE);
    }

​ 为了验证这一个问题,使用-Xmx1m将jvm运行内存设置为 1mb,测试代码如下:

    public class OomTest 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值