代码demo再谈Java线程池

本文详细探讨了Java线程池的工作原理,通过一个代码demo展示了线程池的配置和任务执行过程。当工作线程数小于核心线程数时,新创建线程;等于核心线程数时,任务入队;队列满且线程数小于最大线程数时,创建非核心线程;队列和线程池都满时,应用拒绝策略。在案例中,拒绝策略导致第五个任务被标记为error。文章还解析了`ThreadPoolExecutor`的源码,解释了任务调度的流程和条件。
摘要由CSDN通过智能技术生成

代码demo再谈Java线程池

上代码


import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class ThreadPool {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 3, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1), new DefaultThreadFactory());
        for (int i = 0; i < 5; i++) {
            final int data = i;
            try {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread() + ":" + data);
                    }
                });

            } catch (Exception e) {
                System.out.println(data + ":error");
            }

        }
        executor.shutdown();
    }

    static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                    Thread.currentThread().getThreadGroup();
            namePrefix = "MYPOOL-" +
                    poolNumber.getAndIncrement() +
                    "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                    namePrefix + threadNumber.getAndIncrement(),
                    0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }
}
结果如下

4:error
Thread[MYPOOL-1-thread-3,5,main]:3
Thread[MYPOOL-1-thread-2,5,main]:1
Thread[MYPOOL-1-thread-1,5,main]:0
Disconnected from the target VM, address: '127.0.0.1:54382', transport: 'socket'
Thread[MYPOOL-1-thread-3,5,main]:2

结果发现运行成功的只有4个线程,(为什么会是4个而不是3个 因为队列的容量为1 ,最大线程数为3 ) 拒绝策略我用的直接抛出异常第5个任务捕捉到异常error,

大致流程步骤

1.当工作线程数 < corePoolSize 时,新创建一个新线程执行新提交任务,即使此时线程池中存在空闲线程;
2.当工作线程数 == corePoolSize 时,新提交任务将被放入 workQueue 中;
3.当 workQueue 已满,且工作线程数 < maximumPoolSize 时,新提交任务会创建新的非核心线程执行任务;
4.当 workQueue 已满,且 工作线程数==maximumPoolSize 时,新提交任务由 RejectedExecutionHandler 处理

流程图

java并发编程艺术

在这里插入图片描述

public void execute(Runnable command) {
        // 提交任务不能为 null
        if (command == null)
            throw new NullPointerException();

        // 获取控制位 ctl 的值
        int c = ctl.get();
        // work 线程数 < 核心线程数
        if (workerCountOf(c) < corePoolSize) {
            // 直接创建核心线程,执行任务
            if (addWorker(command, true))
                return;

            /*
                因为没有使用锁,可能会出现并发创建核心线程;
                走到这里,说明核心线程已经创建满了,此时,重新获取控制位 ctl 的值
              */
            c = ctl.get();
        }

        // 如果线程池还是 RUNNING 状态,并且任务成功提交到阻塞队列中
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            // double-check,再检查一次线程池状态
            // 如果线程池变成非 RUNNING 状态,则回滚刚才新加的任务
            if (! isRunning(recheck) && remove(command))
                // 从阻塞队列中移除任务成功,使用拒绝策略执行任务
                reject(command);

            // 如果工作线程数==0,则添加一个线程
            // 主要是兼容核心线程数==0 的情况
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }

        /*
            到达这里,则说明核心线程数已满,且阻塞队列已满
            尝试创建非核心线程执行任务
        */
        else if (!addWorker(command, false))
            // 非核心线程创建失败了,说明是线程数以达到 maximumPoolSize,此时执行拒绝策略
            reject(command);


    }

private boolean addWorker(Runnable firstTask, boolean core) {
        // 定义了一个 retry 标签
        retry:
        for (;;) {
            // 获取控制位
            int c = ctl.get();
            // 获取运行状态
            int rs = runStateOf(c);

            /**
             * rs >= SHUTDOWN:即非 RUNNING 状态,只有 RUNNING < SHUTDOWN
             * ! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())
             *      等价于 非 SHUTDOWN 态 ||  firstTask != null || workQueue.isEmpty()
             *      非 SHUTDOWN 态 == true:SHUTDOWN 态之后的状态,都不允许再添加 worker 线程了,直接返回 false;
             *      非 SHUTDOWN 态 == false || (firstTask != null) == true:SHUTDOWN 状态下,不允许再添加任务了,返回 false;
             *      非 SHUTDOWN 态 == false || (firstTask != null) == false || workQueue.isEmpty() == true:SHUTDOWN 状态,没提交新任务,阻塞队列又是空的,没必要再添加线程了
             */
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            // CAS 创建 worker 线程
            for (;;) {
                // 获取线程数
                int wc = workerCountOf(c);
                /*
                当前线程数大于最大值
                    或
                当前创建的是核心线程,但线程数量已经>=核心线程数
                    或
                当前创建非核心线程,但线程数量已经>=maximumPoolSize
                */
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    // 不创建,直接返回 false
                    return false;

                // cas 修改 ctl 中的线程数,线程数+1
                if (compareAndIncrementWorkerCount(c))
                    // cas 修改成功,break goto 结束循环(不会再进入标签下的循环)
                    break retry;

                // 达到这里,说明 cas 增加线程数 1 失败了,此时进行尝试
                c = ctl.get();
                // 先判断一下线程池状态有没有改变,如果改变了,则 continue goto(会再进入标签下的循环)
                // 跳转到最外层的循环,重新检测线程池的状态值
                if (runStateOf(c) != rs)
                    continue retry;
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            // 创建 worker 对象
            w = new Worker(firstTask);
            // 获取 worker 的线程
            final Thread t = w.thread;
            if (t != null) {
                // 加锁
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // 获取线程池状态
                    int rs = runStateOf(ctl.get());

                    /*
                     线程池是 RUNNING 状态
                        或
                     SHUTDOWN 态 且 firstTask == null(这种情况是需要创建线程,消费队列中剩余的任务)
                      */
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        // 线程是活动状态,则不合法,因为线程是刚创建的,应该是 NEW 状态
                        if (t.isAlive())
                            throw new IllegalThreadStateException();

                        // 将 worker 添加到 list 中
                        workers.add(w);
                        // largestPoolSize 记录该线程池使用过程中,达到最大的线程数
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        // worker 添加成功,workerAdded 置为 true
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }

                // worker 添加成功,此时就可以启动线程
                if (workerAdded) {
                    t.start();
                    // 启动线程成功,workerStarted 置为 true
                    workerStarted = true;
                }
            }
        } finally {
            // 如果 worker 启动失败,则移除它
            if (! workerStarted)
                // workers 移除新加的 worker,并在 ctl 中将 work 线程数量-1
                addWorkerFailed(w);
        }
        return workerStarted;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值