Java -- 线程池 ThreadPoolExecutor

1、核心线程数、最大线程数

添加任务时,判断线程数量,来决定加入队列还是直接执行,或者拒绝

如果线程池关闭,那么添加新的任务时, addWorker 中会直接返回 false,就会进入拒绝策略

public void execute(Runnable command) {
    int c = ctl.get();
    //1、线程数量小于核心数量,添加新的线程
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    //2、线程数量大于核心数量,添加到队列
    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、线程数量大于核心数量,添加到队列,队列已满,继续添加新的线程
    else if (!addWorker(command, false))
    //4、超过最大线程,采取拒绝策略
        reject(command);
}

2、创建新的线程

创建新的 Thread,在线程池关闭的情况下,就不创建了,除非出现以下的特殊情况

//一般情况:
//处于 SHUTDOWN  状态以上,直接不再创建新的线程;
//处于 SHUTDOWN  状态,传入的任务不为 null,直接不再创建新的线程;

//特殊情况:
//处于 SHUTDOWN  状态,传入的任务为 null,是由于在成功加入队列之后,发现此时的线程数量为0,需要再创建一个新的线程去完成这个任务
if (rs >= SHUTDOWN && ! (rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()))
return false;

//...省略
Worker w = new Worker(firstTask);
mainLock.lock();
//和上面分析的情况一致,属于特殊情况
if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
    workers.add(w);
}
mainLock.unlock();
//...省略

3、执行任务

首次创建线程的时候,会直接执行任务;其余情况会阻塞的从队列中获取任务

如果线程池关闭了,那么直接使用中断关闭退出

//1、获取任务
while (task != null || (task = getTask()) != null) {
    //2、如果线程池处于 SHUTDOWN 状态以上,并且还未中断,直接中断线程
    if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted()){
        wt.interrupt();
    }
    //3、执行任务
}

4、获取任务

在获取任务时,如果设置了存活时间,那么超过指定的时间没有获取到任务的线程会自动关闭退出

//1、线程池关闭了,如果处于 SHUTDOWN 而且队列为空
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
    //2、减少线程数量
    decrementWorkerCount();
    //3、当前线程自动关闭退出
    return null;
}

//4、线程数量大于核心线程,默认启用了存活时间
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

//5、线程数量大于核心线程、时间到了,关闭当前线程
if ((wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())) {
    if (compareAndDecrementWorkerCount(c))
        return null;
    continue;
}

//6、阻塞获取任务
Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();
if (r != null)
    return r;
timedOut = true;

5、Executors

1、newFixedThreadPool

创建固定线程数量的线程池,超出的任务,全部加入到队列中,最多存放 int 的最大值

return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());

2、newSingleThreadExecutor

静态线程池,使用包装类,屏蔽了一些方法,实现了真正的单线程串行执行任务

return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));

3、newCachedThreadPool

return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());

6、示例测试 -- keepalive

package com.sample.modules.test;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class ThreadTest {

    static class Task implements Runnable{

        private int taskId;
        private String taskName;

        public Task(int taskId, String taskName) {
            this.taskId = taskId;
            this.taskName = taskName;
        }

        public int getTaskId() {
            return taskId;
        }

        public void setTaskId(int taskId) {
            this.taskId = taskId;
        }

        public String getTaskName() {
            return taskName;
        }

        public void setTaskName(String taskName) {
            this.taskName = taskName;
        }

        @Override
        public void run() {
            try {
                System.out.println("taskId = "+this.taskId+" taskName = "+this.taskName);
                TimeUnit.SECONDS.sleep(3);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception{
        //1、设置队列为0,这样就强制开启到了最大线程数量
        BlockingQueue queue = new ArrayBlockingQueue(1);
        //2、核心线程为1,最大线程为2,超时时间为3s
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 3, TimeUnit.SECONDS, queue);

        Task task1 = new Task(1, "任务1");
        Task task2 = new Task(2, "任务2");
        Task task3 = new Task(3, "任务3");

        //3、单独开启线程记录状态变化
        new Thread(()->{
            while (true){
                try {
                    System.out.println("线程总数:"+executor.getPoolSize()+"  活跃总数:"+executor.getActiveCount()+"  队列数量:"+executor.getQueue().size());
                    TimeUnit.SECONDS.sleep(1);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }).start();

        //4、添加3个任务
        executor.submit(task1);
        executor.submit(task2);
        executor.submit(task3);
    }
}


打印结果:
线程总数:0  活跃总数:0  队列数量:0

//1.线程数量到达最大值, 两个线程都在执行任务, 队列中有一个任务
线程总数:2  活跃总数:2  队列数量:1
线程总数:2  活跃总数:2  队列数量:1
线程总数:2  活跃总数:2  队列数量:1

//2.两个线程当前任务执行完毕, 其中一个线程获取到队列任务, 另一个阻塞等待
//2.此时线程总数依旧为2, 但是活跃的只剩下一个
线程总数:2  活跃总数:1  队列数量:0
线程总数:2  活跃总数:1  队列数量:0
线程总数:2  活跃总数:1  队列数量:0

//3.没有获取到任务的线程, 阻塞 3s 之后, 还没有获取到任务, 关闭退出
//3.此时线程总数为1, 另一个线程也执行完了数据, 所以活跃总数变为0
线程总数:1  活跃总数:0  队列数量:0
线程总数:1  活跃总数:0  队列数量:0
线程总数:1  活跃总数:0  队列数量:0

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值