线程池的结构与关闭原理

线程池实现原理

在这里插入图片描述
  线程池的原理是:调用方的线程向线程池的队列中提交任务,线程池的线程从队列中取任务进行处理。

实现一个线程池需要考虑的问题

  1、队列设置多长?如果是无界队列可能会因为队列过长导致内存耗尽,如果是有界队列,队列满了该怎么处理。
  2、线程池中的线程数是固定的还是动态变化的?
  3、提交任务时,是放入队列还是创建新线程。
  4、没有任务时线程是进入睡眠还是阻塞,如果阻塞该怎么唤醒?问题4通常有3种做法:
(1)不使用阻塞队列,使用线程安全的队列,没有阻塞–唤醒机制。当队列为空时,线程睡眠一段时间后醒来查看有没有新任务,不断轮询。
(2)不使用阻塞队列,但在线程池内部实现阻塞–唤醒机制。
(3)使用阻塞队列。
做法(3)最好,即不用轮询消耗系统资源,也不用去实现轮询–唤醒机制,所以ThreadPoolExecutor和ScheduledThreadPoolThread采用了阻塞队列。

线程池的类继承体系

在这里插入图片描述

ThreadPoolExecutor

ThreadPoolExecutor的结构

public class ThreadPoolExecutor extends AbstractExecutorService {
	...
	private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); //状态变量
	private final BlockingQueue<Runnable> workQueue; // 任务阻塞队列
	private final ReentrantLock mainLock = new ReentrantLock(); // 互斥锁
	private final HashSet<Worker> workers = new HashSet<Worker>(); // 线程集合
}
private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
		final Thread thread; // Work的线程
        Runnable firstTask; // 第一个任务
        volatile long completedTasks; // 执行完的任务数
	}

核心参数

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

(1)corePoolSize:线程池中保持的线程数
(2)maxPoolSize:在corePoolSize和队列都满了的情况下,线程数能扩充的最大值
(3)keepAliveTime/TmieUnit:maxPoolSize多余的线程的存活时间和时间单位
(4)blockingQueue:线程池所用的队列
(5)threadFactory:线程创建工厂
(6)RejectedExecutionHandler:maxPoolSize满了时的拒绝策略。

线程池的生命周期与关闭

  线程池的状态变量ctl分为两部分:高三位用来表示线程池的状态,后29位表示线程数量。

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

    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,rs是runState,ws是workState

  线程池的状态有五个,只能从小的向大的转移。
在这里插入图片描述

  有两个方法可以关闭线程,shutdown()和shutdownNow()。

public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess(); // 检测是否有关闭线程池的权限
        advanceRunState(SHUTDOWN); // 设置线程池状态
        interruptIdleWorkers(); // 中断空闲线程
        onShutdown(); // 空的钩子函数
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
}

public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        advanceRunState(STOP);
        interruptWorkers(); // 中断所有的线程
        tasks = drainQueue(); // 清空队列
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
    return tasks;
}

  两个方法里中断的线程类型不同

private void interruptIdleWorkers(boolean onlyOne) {
    final ReentrantLock mainLock = this.mainLock;
     mainLock.lock();
     try {
          for (Worker w : workers) {
              Thread t = w.thread;
              if (!t.isInterrupted() && w.tryLock()) { // tryLock()成功说明该线程空闲,才中断该线程
                  try {
                      t.interrupt();
                  } catch (SecurityException ignore) {
                  } finally {
                      w.unlock();
                  }
              }
              if (onlyOne)
                  break;
         }
    } finally {
         mainLock.unlock();
    }
}

private void interruptWorkers() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
         for (Worker w : workers)
              w.interruptIfStarted(); //直接中断线程
    } finally {
         mainLock.unlock();
    }
}

  shutdown()和shutdownNow()都调用了tryTerminate()。

final void tryTerminate() {
    for (;;) {
        int c = ctl.get();
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;
        if (workerCountOf(c) != 0) { // Eligible to terminate
            interruptIdleWorkers(ONLY_ONE);
            return;
        }

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
             if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) { // 切换线程状态
                 try {
                      terminated(); // 调用空实现的钩子函数
                     } finally {
                      ctl.set(ctlOf(TERMINATED, 0)); // 修改线程状态
                      termination.signalAll();       // 唤醒因为termination阻塞的线程
                     }
                    return;
             }
         } finally {
                mainLock.unlock();
         }
            // else retry on failed CAS
    }
}

线程池关闭的步骤

在这里插入图片描述

  awaitTermination的实现:

public boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException {
        long nanos = unit.toNanos(timeout);
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (;;) {
                if (runStateAtLeast(ctl.get(), TERMINATED)) // 判断是否是TERMINATED状态,如果是直接返回
                    return true;
                if (nanos <= 0)
                    return false;
                nanos = termination.awaitNanos(nanos); // 如果不是TERMINATED状态,则睡眠指定的时间后再次判断
            }
        } finally {
            mainLock.unlock();
        }
    }

  这里的睡眠与前面的tryTerminate()里的termination.signalAll()相对应。


参考资料:《Java并发实现原理:JDK源码剖析》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值