java 线程池相关

1、线程池的状态

线程池总共存在5种状态,定义在ThreadPoolExecutor类中,具体代码如下:

public class ThreadPoolExecutor extends AbstractExecutorService {
    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;
}

线程池的5种状态具体如下:

  • RUNNING:线程池创建之后的初始状态,这种状态下可以执行任务。
  • SHUTDOWN:该状态下线程池不再接受新任务,但是会将工作队列中的任务执行完毕。
  • STOP:该状态下线程池不再接受新任务,也不会处理工作队列中的剩余任务,并且将会中断所有工作线程。
  • TIDYING:该状态下所有任务都已终止或者处理完成,将会执行terminated()钩子方法。
  • TERMINATED:执行完terminated()钩子方法之后的状态。terminated钩子方法在Executor终止时调用,默认实现不执行任何操作

状态流转如下:
在这里插入图片描述

2、线程池任务分配方式

具体线程的分配方式
当一个任务被添加到线程池:

  • 如果此时线程池中的数量 < corePoolSize,即使线程池中的线程都处于空闲状态,也要创建新的线程来处理被添加的任务。
  • 如果此时线程池中的数量 = corePoolSize,但是缓冲队列 workQueue 未满,那么任务被放入缓冲队列。
  • 如果此时线程池中的数量 > corePoolSize
    • 缓冲队列 workQueue 满,并且线程池中的数量 < maximumPoolSize,建新的线程来处理被添加的任务。
    • 缓冲队列 workQueue 满,并且线程池中的数量 = maximumPoolSize,那么通过 handler 所指定的策略来处理此任务。也就是:处理任务的优先级为:核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。
  • 线程空闲时间 > keepAliveTime,线程将被终止

图解线程池实现原理
在这里插入图片描述

execute()方法和 submit()方法的区别是什么呢?
  • execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否;
  • submit()方法用于提交需要返回值的任务。线程池会返回一个 Future 类型的对象,通过这个 Future对象可以判断任务是否执行成功,并且可以通过 Future 的 get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用get(long timeout,TimeUnit unit)方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。

3、线程池中的ctl是什么

ctl是线程池中一个属性,本质就是int类型的数值

  • 高3位:描述 线程池 的状态
  • 低29位 :描述 工作线程 的数量
public class ThreadPoolExecutor extends AbstractExecutorService {

    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    private static final int COUNT_BITS = Integer.SIZE - 3;
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

    // runState is stored in the high-order bits
    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;

    // Packing and unpacking ctl
    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?

线程池在执行任务时,需要多次判断线程池状态,来确实任务是否需要执行(以哪种方式执行)

什么时候会修改工作线程数量?

execute()——>addWorker()——>compareAndIncrementWorkerCount()

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    else if (!addWorker(command, false))
        reject(command);
}

private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get();  // Re-read ctl
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
        }
    }
    // 省略
}

private boolean compareAndIncrementWorkerCount(int expect) {
    return ctl.compareAndSet(expect, expect + 1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值