java线程池

原文

线程池

  1. 线程池任务,线程是如何选择的 ?

​ 是阻塞队列选择一个消费者

  1. 线程空闲时,操作系统是否会调度?

​ 阻塞

线程池状态

状态转换状态转换方式
RUNNING -> SHUTDOWN当调用了线程池的shutdown方法时,或者当finalize方法被隐式调用后(该方法内部会调用shutdown方法)
RUNNING,SHUTDOWN -> STOP当调用了线程池的shutdownNow方法时
SHUTDOWN -> TIDYING在线程池与阻塞队列均变为空时
STOP -> TIDYING在线程池变为空时
TIDYING->TERMINATED在terminated方法被执行完毕时

// ctl:高三位表示线程池运行状态,低29位表示线程池线程运行数量
// 一个变量存储两个值的好处是不必费心思(比如加锁)去维护两个状态的一致性
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

// 获取线程池当前的运行状态(~:按位取反,即0变成1,1变成0。)
private static int runStateOf(int c)     { return c & ~CAPACITY; }
// 获取线程池当前运行的线程数量
private static int workerCountOf(int c)  { return c & CAPACITY; }
// 通过线程池状态和运行的线程数量获取ctl
private static int ctlOf(int rs, int wc) { return rs | wc; }

例子

public class ThreadPoolTest {
    private static void getThreadPoolState(ThreadPoolExecutor pool) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, NoSuchFieldException {
        final int COUNT_BITS = Integer.SIZE - 3;
        final int CAPACITY = (1 << COUNT_BITS) - 1;

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

        Class<?> clazz = ThreadPoolExecutor.class;
        // 使用反射获取 runState 字段
        Field runStateField = ThreadPoolExecutor.class.getDeclaredField("ctl");
        runStateField.setAccessible(true);

        // 获取 runState 的值
        AtomicInteger runState = (AtomicInteger) runStateField.get(pool);
        // 获取方法名和参数类型
        String methodName = "runStateOf";
        Class<?>[] parameterTypes = {int.class};

        // 获取方法对象
        Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
        // 设置方法可访问性为 true
        method.setAccessible(true);
        // 设置方法的参数值
        Object[] arguments = {runState.get()};

        // 调用方法
        Object result = method.invoke(pool, arguments);
        if ((int) result == RUNNING) {
            System.out.println("RUNNING");
        } else if ((int) result == SHUTDOWN) {
            System.out.println("SHUTDOWN");
        }else if ((int) result == STOP) {
            System.out.println("STOP");
        }else if ((int) result == TIDYING) {
            System.out.println("TIDYING");
        }else if ((int) result == TERMINATED) {
            System.out.println("TERMINATED");
        }
    }
}

class ThreadDemo implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(50000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(Thread.currentThread().getName());
    }
}

RUNNING

public static void main(String[] args) throws InterruptedException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 5, 1000, TimeUnit.MILLISECONDS, new SynchronousQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
        for (int i = 0; i < 3; i++) {
            pool.submit(new ThreadDemo());
        }
        getThreadPoolState(pool);
    }
// 输出
RUNNING

SHUTDOWN

public static void main(String[] args) throws InterruptedException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 5, 1000, TimeUnit.MILLISECONDS, new SynchronousQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
        for (int i = 0; i < 3; i++) {
            pool.submit(new ThreadDemo());
        }
        getThreadPoolState(pool);
    }
// 输出
SHUTDOWN

STOP

public static void main(String[] args) throws InterruptedException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 5, 1000, TimeUnit.MILLISECONDS, new SynchronousQueue<>(), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
        for (int i = 0; i < 3; i++) {
            pool.submit(new ThreadDemo());
        }
        pool.shutdownNow();
        getThreadPoolState(pool);
    }
// 输出 大部分时候都会输出TERMINATED,偶尔运行慢或者调度慢了,可以出现STOP
STOP  |   TERMINATED

TIDYING由于中间没有其他状态,且切换到TERMINATED状态太快,就不举例了

创建线程池

/*
     * @param corePoolSize 线程池中核心线程数
     * @param maximumPoolSize 在高并发时,在线程阻塞队列已满的情况下,还可额外常见线程,包括核心线程的线程总数
     * @param keepAliveTime 因阻塞队列满而创建的线程,在空闲keepAliveTime时间后,进行销毁
     * @param unit keepAliveTime 单位
     * @param workQueue 任务队列
     * @param threadFactory 创建线程的factory
     * @param handler 线程数量达到最大线程数量并且任务队列也是满的情况下,线程池的拒绝策略
*/
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;
    }

此时线程池对象只是创建了一个普通的对象,还没有任何线程。

参数说明

maximumPoolSize

当核心线程数和队列都满了时,新提交的任务仍然可以通过创建新的工作线程(叫它非核心线程),直到工作线程数达到 maximumPoolSize 为止,这样就可以缓解一时的高峰期了,而用户也不用设置过大的核心线程数。

keepAliveTime

当高峰时期过去后,核心线程与非核心线程都一直空跑着,浪费资源。我们可以给非核心线程设定一个超时时间 keepAliveTime,当这么长时间没能从队列里获取任务时,就不再等了,销毁线程。

workQueue

阻塞队列可以阻塞,当阻塞队列当队列里面没有值时,会阻塞直到有值输入。输入也一样,当队列满的时候,会阻塞,直到队列有空间。

任务队列

getTask()有一个从任务队列获取任务的步骤,不同的任务队列有不同的任务存取策略,以下介绍一下可选的任务队列:

名称描述
ArrayBlockingQueue一个用数组实现的有界阻塞队列,此队列按照先进先出(FIFO)的原则对元素进行排序,并发采用可重入锁来控制
LinkedBlockingQueue一个用链表结构组成的有界队列,此队列按照先进先出(FIFO)的原则对元素进行排序
PriorityBlockingQueue一个支持线程优先级排序的无界队列
DelayQueue一个实现PriorityBlockingQueue实现延迟获取的无界队列,在创建元素时,可以指定多久才能从队列中获取当前元素
SynchronousQueue一个不存储元素的阻塞队列,每一个put操作必须等待take操作。支持公平锁和非公平锁。Executors.newCachedThreadPool()就使用了SynchronousQueue
LinkedTransferQueue一个由链表结构组成的无界阻塞队列,相当于其它队列,LinkedTransferQueue队列多了transfer和tryTransfer方法
LinkedBlockingDeque一个由链表结构组成的双向阻塞队列
  1. 阻塞队列
  2. 阻塞队列的操作
    阻塞队列包括了非阻塞队列中的大部分方法,上面列举的5个方法在阻塞队列中都存在,但是要注意这5个方法在阻塞队列中都进行了同步措施。

除此之外,阻塞队列提供了另外4个非常有用的方法:

put(E e):用来向队尾存入元素,如果队列满,则等待;
take():用来从队首取元素,如果队列为空,则等待;
offer(E e,long timeout, TimeUnit unit):用来向队尾存入元素,如果队列满,则等待一定的时间,当时间期限达到时,如果还没有插入成功,则返回false;否则返回true;
poll(long timeout, TimeUnit unit):用来从队首取元素。如果队列空,则会等待 timeout 时间后进行一次重试,如果取不到,则返回null;否则返回取得的元素;

Executors

默认的构造方法来创建线程池,参数过多,JDK提供了工厂方法,来创建线程池

handler

如果线程达到最大线程数,救急线程也满负荷,且有界队列也满了,JDK 提供了4种拒绝策略

  • AbortPolicy: 调用者抛出RejectedExecutionException, 默认策略

  • CallerRunsPolicy: 调用者运行任务

  • DiscardPolicy: 放弃本次任务

  • DiscardOldestPolicy: 放弃队列中最早的任务,本任务取而代之

submit

线程池使用流程图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LYqr4mp2-1689146849496)(https://img.itya.xyz/picgo/java%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%B5%81%E7%A8%8B202307111128746.png)]

线程池例子

package com.zyh.java;

import java.util.concurrent.*;

public class ThreadPoolTest {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService pool = new ThreadPoolExecutor(1, 5, 1000, TimeUnit.MILLISECONDS, new SynchronousQueue<>(), Executors.defaultThreadFactory());
        for (int i = 0; i < 10; i++) {
            pool.submit(new ThreadDemo());
        }
    }
}
class ThreadDemo implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

// 输出
pool-1-thread-1
pool-1-thread-2
pool-1-thread-3
pool-1-thread-4
pool-1-thread-5
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@681a9515 rejected from java.util.concurrent.ThreadPoolExecutor@3af49f1c[Running, pool size = 5, active threads = 3, queued tasks = 0, completed tasks = 2]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
	at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
	at com.zyh.java.ThreadPoolTest.main(ThreadPoolTest.java:9)

上述代码中,由于SynchronousQueue的容量为0且提交速度较快,当提交到第六个线线程时,线程池中的所有线程均未执行,在submit第二个线程是就会创建新的线程,当第六个线程提交时,此时,线程数已经达到最大线程数,且队列已满(容量为0);

下面看一下,从submit开始都发生了那些事情:

首先查看submit的源码

    /**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }

submit注释中写了两个异常,一个是如果任务无法被调度执行时抛出 RejectedExecutionException ,另一个是task为空,抛出空指针异常。

    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }


    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }

    public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
    }


    static final class RunnableAdapter<T> implements Callable<T> {
        final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {
            task.run();
            return result;
        }
    }

从上述源码中可知,newTaskFor创建了一个FutureTask对象,并且将其状态置NEW。

execute(ftask);

    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
        * 1。如果运行的线程少于corePoolSize,请尝试
        * 以给定的命令作为第一个线程启动一个新线程
        * 任务。调用addWorker会自动检查runState和
        * workerCount,这样可以防止误报警
        * 在不应该执行线程时返回false。
        */
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        /*
        * 2。如果一个任务可以成功排队,那么我们仍然需要
        * 检查我们是否应该添加一个线程
        * (因为自上次检查以来现有的已死亡)或其他
        * 进入此方法后池关闭。所以我们
        * 重新检查状态,必要时回滚队列
        * stopped,或者在没有线程时启动一个新线程。
        *
        */
        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))
            reject(command);
    }

其中涉及到了几个方法workerCountOf()、addWorker()、isRunning()、remove()、reject()

其中workerCountOf()、isRunning()很简单只是返回线程数量和判断线程池的状态。

先看remove

remove

    public boolean remove(Runnable task) {
        boolean removed = workQueue.remove(task);
        tryTerminate(); // In case SHUTDOWN and now empty
        return removed;
    }

addWorker

/*
根据当前工作线程池的状态和给定的边界(core或maximum)检查是否可以添加新的工作线程。如果可以,worker的计数会相应地调整,会创建并启动一个新的worker,将firstTask作为它的第一个任务。如果线程池已停止或关闭,此方法返回false。如果线程工厂请求创建线程失败,它也会返回false。如果线程创建失败,无论是由于线程工厂返回null,还是由于异常(通常是thread .start()中的OutOfMemoryError),我们都会干净地回滚。
形参:
firstTask – 当firsrTask不为空时且线程数量少于于corePoolSize时,做为线程的第一个任务,或者当队列已满时,作为第一个任务创建非核心线程。
core – 如果为true,则使用corePoolSize绑定,否则使用maximumPoolSize。(这里使用布尔指示符而不是值,以确保在检查其他池状态后读取新值)。.
返回值:
true if successful
*/
private boolean addWorker(Runnable firstTask, boolean core) {
		// 做一个标记类似goto的效果
        retry:
        for (;;) {
            int c = ctl.get();
            // 运行状态
            int rs = runStateOf(c);
            // 先做一个到底应不应该创建线程的判断
            // 这个判断条件可以简化为 (rs >= SHUTDOWN && (rs != SHUTDOWN || firstTask != null || 		 			        // workQueue.isEmpty()))
            // 分为三种情况:1. rs > SHUTDOWN (线程池状态处于STOP、TIDYING、TERMINATED,添加工作线程失败)
            //             2.rs == SHUTDOWN && firstTask != null 
            //             3.rs == SHUTDOWN && workQueue.isEmpty()
            // 在这三种情况下,都不会再创建新的线程
            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
                c = ctl.get();  // Re-read ctl
                // 线程池的状态是否等于最开始的状态
                if (runStateOf(c) != rs)
                    // 不等于表示线程池有改变,需要重新执行一遍之前的操作
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
		// 新增线程
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            // 创建了一个worker对象
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                // ReentrantLock独占锁
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                     // 再次获取线程池状态
                    int rs = runStateOf(ctl.get());
					// 先做一个是否可以运行线程的判断
                    // 1.线程池状态处于运行状态
                    // 2.线程池状态处于SHUTDOWN状态但task==null,因为SHUTDOWN状态不接受新的任务
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        // 将worker添加到一个HashSet
                        workers.add(w);
                        int s = workers.size();
                        // 记录出现的最大线程数量
                        if (s > largestPoolSize)
                            largestPoolSize = s;
						// 线程添加成功
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    // 执行
                    t.start();
                    // 启动成功标志
                    workerStarted = true;
                }
            }
        } finally {
            // 启动失败标志,加入到启动失败
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

Worker类

​ Worker 是 ThreadPoolExecutor的一个内部类,主要是用来维护线程执行任务的中断控制状态,它实现了Runnable 接口同时继承了AQS,实现 Runnable 接口意味着 Worker 就是一个线程,继承 AQS 是为了实现独占锁这个功能。

    private final class Worker
      extends AbstractQueuedSynchronizer
      implements Runnable{
        /**
         * This class will never be serialized, but we provide a
         * serialVersionUID to suppress a javac warning.
         */
        private static final long serialVersionUID = 6138294804551838833L;

        /** Thread this worker is running in.  Null if factory fails. */
      	// 执行任务的线程
        final Thread thread;
        /** Initial task to run.  Possibly null. */
      	// 执行的任务
        Runnable firstTask;
        // 完成的任务数
        volatile long completedTasks;

        /**
         * Creates with given first task and thread from ThreadFactory.
         * @param firstTask the first task (null if none)
         */
        Worker(Runnable firstTask) {
          // 新建线程的时候,设置state -1 是为了防止线程还未执行时(线程只有在执行的时候才会被中断),就被					// 其它线程显式调用shutdown方法中断了,因为中断是要判断state大于等于0才会中断
          setState(-1); 
          this.firstTask = firstTask;
          // 新建了一个线程
          this.thread = getThreadFactory().newThread(this);
        }

        /** Delegates main run loop to outer runWorker  */
        public void run() {
            runWorker(this);
        }
    }

DefaultThreadFactory

Executors类中新建线程的方式有一个默认的实现

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 = "pool-" +
                          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;
        }
    }

runWorker、getTask

final void runWorker(Worker w) {
        // 获取当前线程
        Thread wt = Thread.currentThread();
        // 获取任务
        Runnable task = w.firstTask;
        // 显式将任务置为空,防止产生错乱的问题
        w.firstTask = null;
        // 将线程state置为0(创建Worker的时候state为-1),运行线程时允许线程中断
        w.unlock(); 
        boolean completedAbruptly = true;
        try {
            // 循环判断任务(firstTask或从队列中获取的task)是否为空
            while (task != null || (task = getTask()) != null) {
                w.lock();
              	// 判断线程池的状态,是否处于stop状态,或者线程是否被中断
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    // 回调,可以适当做扩展
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                      	// 执行任务
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    // 线程执行完成个数,起到一个统计的作用
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

  // 从阻塞队列中获取任务
  private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

        for (;;) {
            int c = ctl.get();
            // 获取线程池状态
            int rs = runStateOf(c);

            // 1.线程池状态是STOP,TIDYING,TERMINATED
       	    // 2.线程池shutdown并且队列是空的.
            // 满足以上两个条件之一则工作线程数wc减去1,然后直接返回null
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // allowCoreThreadTimeOut 是否允许核心工作线程超时销毁,默认是false,可以设置为true
            // 工作线程数大于核心线程数
            // 满足两个条件之一,timed为true
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
						
            // 1.(工作线程数 > maximumPoolSize) || (timed == true && timedOut == true)
            // 2.工作线程数 > 1或者队列为空
            // 一般情况下,在工作线程数 > maximumPoolSize 并且任务队列为空的情况下会触发这个条件(因为队列不为空下面的超时拉取的返回值R肯定不为null,timeOut自然不会为true)
            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                // 线程数 -1
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
              	// 如果timed为true,通过poll()方法做超时拉取,keepAliveTime时间内没有等待到有效的任务,则返回null
            	// 如果timed为false,通过take()做阻塞拉取,会阻塞到有下一个有效的任务时候再返回(一般不会是null)	
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
              	// 取不到任务的时候timedOut = true
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

processWorkerExit

// completedAbruptly:true表示用户是异常退出
private void processWorkerExit(Worker w, boolean completedAbruptly) {
  	// 如果工作线程是异常退出,那么工作线程数减1
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 统计已完成的任务数
            completedTaskCount += w.completedTasks;
            // 将工作线程数移除
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }
		// 尝试中断空闲线程
        tryTerminate();

        int c = ctl.get();
  		// 如果当前线程池状态处于RUNNING、SHUTDOWN状态
        if (runStateLessThan(c, STOP)) {
          	// 工作线程非异常
            if (!completedAbruptly) {
              	// allowCoreThreadTimeOut这个值表示是否允许核心工作线程超时销毁
              	// 如果允许,那么核心工作线程数最小为0
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
              	// 如果最小保留的核心线程数为0并且任务队列不为空,表示至少还需要一个线程将任务完成
                if (min == 0 && ! workQueue.isEmpty())
                    // 最小线程数改为1
                    min = 1;
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            // 如果当前运行的Worker数比当前需要的Worker数少的话,会调用addWorker,添加新的Worker
            addWorker(null, false);
        }
    }

tryTerminate

final void tryTerminate() {
        for (;;) {
            int c = ctl.get();
            // 1.运行状态
            // 2.TIDYING或者TERMINATED状态
            // 3.SHUTDOWN状态并且队列不为空
            if (isRunning(c) ||
                runStateAtLeast(c, TIDYING) ||
                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty())  )
                return;
            // 当前线程数量不为0
            if (workerCountOf(c) != 0) { // Eligible to terminate
                interruptIdleWorkers(ONLY_ONE);
                return;
            }

            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                // 将线程池状态设置为TIDYING,并且设置线程数量为0
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        terminated();
                    } finally {
                        // 设置线程池状态并设置线程数量
                        ctl.set(ctlOf(TERMINATED, 0));
                        // 唤醒所有等待线程池终止的线程
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }

拒绝策略

拒绝策略拒绝方式
AbortPolicy直接抛出一个运行期异常
DiscardPolicy默默地丢弃掉提交的任务,什么都不做且不抛出任何异常
DiscardOldestPolicy丢弃掉阻塞队列中存放时间最久的任务(队头元素),并且为当前所提交的任务留出一个队列中的空闲空间,以便将其放进到队列中
CallerRunsPolicy直接由提交任务的线程来运行这个提交的任务
    // 直接由提交任务的线程来运行这个提交的任务
    public static class CallerRunsPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code CallerRunsPolicy}.
         */
        public CallerRunsPolicy() { }

        /**
         * Executes task r in the caller's thread, unless the executor
         * has been shut down, in which case the task is discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }			



    // 直接抛出异常	
    public static class AbortPolicy implements RejectedExecutionHandler {
        /**
         * Creates an {@code AbortPolicy}.
         */
        public AbortPolicy() { }

        /**
         * Always throws RejectedExecutionException.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         * @throws RejectedExecutionException always
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }

    /**
     * A handler for rejected tasks that silently discards the
     * rejected task.
     */
    // 默默地丢弃掉被拒绝的任务
    public static class DiscardPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardPolicy}.
         */
        public DiscardPolicy() { }

        /**
         * Does nothing, which has the effect of discarding task r.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
      	// 这个方法什么都不做
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }

    /**
     * A handler for rejected tasks that discards the oldest unhandled
     * request and then retries {@code execute}, unless the executor
     * is shut down, in which case the task is discarded.
     */
    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardOldestPolicy} for the given executor.
         */
        public DiscardOldestPolicy() { }

        /**
         * Obtains and ignores the next task that the executor
         * would otherwise execute, if one is immediately available,
         * and then retries execution of task r, unless the executor
         * is shut down, in which case task r is instead discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
      	// 将队头元素删除掉,移除掉最老的任务
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            // 判断线程池是否已关闭
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }

CallerRunsPolicy

package com.zyh.java;

import java.util.concurrent.*;

public class ThreadPoolTest {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService pool = new ThreadPoolExecutor(1, 5, 1000, TimeUnit.MILLISECONDS, new SynchronousQueue<>(), Executors.defaultThreadFactory(),new ThreadPoolExecutor.CallerRunsPolicy());
        for (int i = 0; i < 6; i++) {
            pool.submit(new ThreadDemo());
        }
    }
}
class ThreadDemo implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

// 输出  -----CallerRunsPolicy
main
pool-1-thread-1
pool-1-thread-3
pool-1-thread-2
pool-1-thread-4
pool-1-thread-5
// 输出  -----AbortPolicy  
pool-1-thread-1
pool-1-thread-2
pool-1-thread-3
pool-1-thread-4
pool-1-thread-5
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@681a9515 rejected from java.util.concurrent.ThreadPoolExecutor@3af49f1c[Running, pool size = 5, active threads = 3, queued tasks = 0, completed tasks = 2]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
	at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
	at com.zyh.java.ThreadPoolTest.main(ThreadPoolTest.java:9)
// 输出  -----DiscardPolicy
pool-1-thread-1
pool-1-thread-2
pool-1-thread-3
pool-1-thread-4
pool-1-thread-5
 
 
public static void main(String[] args) throws InterruptedException, NoSuchFieldException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
    ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());
    for (int i = 0; i < 6; i++) {
        pool.submit(new ThreadDemo(i));
    }
}
 
@Override
public void run() {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    System.out.println(Thread.currentThread().getName() + "  " + i);
}
// 输出  -----DiscardOldestPolicy
pool-1-thread-2  3
pool-1-thread-1  0
pool-1-thread-2  4
pool-1-thread-1  5

other

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值