线程池底层原理

线程池执行流程及原理解析

线程模型

用户线程(UTL):由应用去管理线程,不需要用户态-内核态切换。

内核线程(KTL):创建线程在任务管理器中可见,java创建的线程由操作系统管理,操作系统对应一个内核空间线程,线程和内核线程一一对应。

java的线程是KTL内核线程模型。关键代码,Thread类中创建线程,是由本地方法库中的start0方法创建线程。

线程状态:

private final AtomicInteger ctl = new AtomicInteger(RUNNING);
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY   = (1 << COUNT_BITS) - 1; // 2^29

// runState is stored in the high-order bits
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

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; }

// 运算结果(高3位为状态、低29位为数量)
COUNT_BITS:29
CAPACITY  :000 11111111111111111111111111111
RUNNING   :111 00000000000000000000000000000
SHUTDOWN  :000 00000000000000000000000000000
STOP      :001 00000000000000000000000000000
TIDYING   :010 00000000000000000000000000000
TERMINATED:011 00000000000000000000000000000

ctl:记录活动线程的数量(低29位)、线程池的状态(高3位)【Integer.SIZE共32位】

CAPACITY=0 :初始容量

COUNT_BITS:29 =(Integer.SIZE=32)-3,

RUNNING(111):接受新任务、可以处理已添加的任务。

SHUTDOWN(000):不接受新任务、可以处理已添加的任务。

STOP(001):不接受新任务、不处理已添加的任务、并且中断正在处理的任务。

TIDYING(010):所有的任务已经终止,ctl数=0。

TERMINATED(011):线程池终止

构造函数解析

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.acc = System.getSecurityManager() == null ?
        null :
    AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}
  • acc : 获取调用上下文
  • corePoolSize: 核心线程数量,规定线程池有几个线程(worker)在运行。
  • maximumPoolSize: 最大的线程数量。当workQueue满了,不能添加任务的时候,这个参数才会生效。规定线程池中最多有多少个线程(worker)在执行
  • workQueue:存放任务的队列。
  • unit: 生存时间的单位
  • keepAliveTime:超出corePoolSize大小的那些线程的生存时间,这些线程如果长时间没有执行任务并且超过了keepAliveTime设定的时间,就会消亡。
  • threadFactory: 创建线程的工厂,在这个地方可以统一处理创建的线程的属性。
  • handler:当workQueue已经满了,并且线程池线程数已经达到maximumPoolSize,将执行拒绝策略。

线程池执行流程

// 执行任务方法
public void execute(Runnable command) {
	// 1、小于核心线程数,直接创建线程执行任务addWorker(command, true)
    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    // 2、大于核心线程数,尝试加入队列,进行双重检测线程池运行状态
    // 创建非核心线程执行任务addWorker(null, false)
    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);
    }
    // 3、尝试入队失败,addWorker(command, false)在自旋时状态检测返回false,未创建Worker对象
    // 则执行拒绝策略
    else if (!addWorker(command, false))
        reject(command);
}
// 添加worker对象到workers集合中
private boolean addWorker(Runnable firstTask, boolean core) {
    // 
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
		// 1、检测线程池的状态,如果关闭了则不再添加worker,直接返回false
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        // 2、自旋的方式对活动的线程数workercount+1
        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;
        }
    }

    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        // 3、封装worker对象,内部创建了新的线程,w.thread即可获取该线程
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            // 4、通过线程池的重入锁机制,将worker加入workers集合中,等待workers执行。
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                int rs = runStateOf(ctl.get());

                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            // 5、加入成功后,调用该线程执行。
            if (workerAdded) {
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        // 加入线程池失败,则内部通过自旋的方式,将活动线程数workerCount-1
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}
Worker(Runnable firstTask) {
    setState(-1); 
    this.firstTask = firstTask;
    this.thread = getThreadFactory().newThread(this);	// 1、此处将worker对象本身加入线程
}
public void run() {	// 2、由于worker对象实现Runnable,由1处的thread执行start时,会调用该方法
    runWorker(this);	// 3、该runWorker方法为线程池的runWorker方法。
}

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
	// 4、此处只留下了关键代码,如果firstTask==null,则通过getTask方法从队列中获取任务。
    while (task != null || (task = getTask()) != null) {
        // 5、执行任务
        task.run();
    }
}

线程集合:HashSet:workers :不断的从workQueue队列中获取线程,执行任务

阻塞队列:BlockingQueue:workQueue:存放线程任务的队列,FIFO一端入队一端出队

流程原理:

1、用户向线程池中提交线程任务,执行execute方法。

2、如果当前线程池中的线程数量workerCount小于核心线程数corepoolsize

2.1、通过自旋的方式对workerCount数量做CAS进行+1,如果当前活动线程>corepoolsize或者maxinumpoolsize,则自旋失败,返回false,如果成功,则开始封装Worker对象

2.2、通过线程任务封装Worker对象时,先获取线程池的重入锁,获取锁后判断当前线程池的状态,如果为001、010、011状态,则操作失败,会对workerCount数量CAS做-1,同时停止线程池,返回false。

2.3、线程池将该线程封装成Worker对象,添加到workers执行。

3、如果当前线程池中的线程数量workerCount达到了corepoolsize,则将任务加入workQueue队列中。

4、如果队列已经满,但未达到maxinumpoolsize数量,新建(非核心)线程执行任务。

4.1、由addWorker(command, false),添加的firstTask为null,所以封装的Worker对象的firstTask为null,

4.2、由Worker对象执行线程,由于firstTask==null,所以不断循环的从workQueue队列中获取任务步骤3加入的任务执行。

4.3、执行完成后对该任务标记completedTaskCount已完成数量。同时移除该任务。

5、如果队列已经满,总线程数达到了maxinumpoolsize数量,会由RejectedExecutionHandler执行拒绝策略。

在这里插入图片描述

默认线程池:

newFixedThreadPool:指定线程的线程池,核心数=最大数,不会释放线程

newCachedThreadPool:可缓存60秒线程的线程池,核心数=0,最大数=Integer.MAX会自动释放线程

newSingleThreadExecutor:只有一个线程,核心数=最大数=1,可以保证线程的任务顺序执行

newScheduledThreadPool:可以指定时间、周期性执行提交的任务线程

默认任务队列:

1、ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务;
2、LinkedBlockingQuene:基于链表结构的阻塞队列,按FIFO排序任务,吞吐量通常要高于ArrayBlockingQuene;
3、SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene;
4、PriorityBlockingQuene:具有优先级的无界阻塞队列;

默认拒绝策略:

1、AbortPolicy:直接抛出异常,默认策略;
2、CallerRunsPolicy:用调用者所在的线程来执行任务;
3、DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;
4、DiscardPolicy:直接丢弃任务;
当然也可以根据应用场景实现RejectedExecutionHandler接口,自定义饱和策略,如记录日志或持久化存储不能处理的任务。

posted @ 2021-05-10 23:54  彼时岸边  阅读(353)  评论(0编辑  收藏  举报