java线程池详解(源码)

  1. 为什么推荐用ThreadPoolExecutor创建线程池,而不用默认提供的四种线程池
FixedThreadPool 和 SingleThreadPool:

允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。

CachedThreadPool 和 ScheduledThreadPool:

允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

所以建议用ThreadPoolExecutor创建线程池,用好线程数与队列长度这两个参数
3. 常用的四种线程池

  • newFixedThreadPool 定长线程池
    一个有指定的线程数的线程池,有核心的线程,里面有固定的线程数量,响应的速度快。正规的并发线程,多用于服务器。固定的线程数由系统资源设置。核心线程是没有超时机制的,队列大小没有限制,除非线程池关闭了核心线程才会被回收。
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
  • newCachedThreadPool 可缓冲线程池
    只有非核心线程,最大线程数很大,每新来一个任务,当没有空余线程的时候就会重新创建一个线程,这边有一个超时机制,当空闲的线程超过60s内没有用到的话,就会被回收,它可以一定程序减少频繁创建/销毁线程,减少系统开销,适用于执行时间短并且数量多的任务场景。
 public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
  • ScheduledThreadPool 周期线程池
    创建一个定长线程池,支持定时及周期性任务执行,通过过schedule方法可以设置任务的周期执行
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
  • newSingleThreadExecutor 单任务线程池
    创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行,每次任务到来后都会进入阻塞队列,然后按指定顺序执行。
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
  1. 线程池的参数及作用
    当一个任务提交到线程池,执行过程
    线程池的执行过程

提交任务
1 达到核心线程数,判断任务队列是否满了
1.1 队列满了,则判断当前线程数是否满足最大线程数
1.1.1 到达了最大线程数,则根据拒绝策略处理任务
1.1.2 未到达则创建线程执行任务
1.2 没有满,则将任务放入队列中等待任务执行
2 未达到核心线程数,则创建线程完成任务

    /**
     * @param corePoolSize    除非设置了{@code allowCoreThreadTimeOut},即使它们处于空闲状态也要保留在池中的线​​程数。
     * @param maximumPoolSize 池中允许的最大线程数
     * @param keepAliveTime   当线程数大于内核数时,这是多余的空闲线程将在终止之前等待新任务的最长时间。
     * @param unit            {@code keepAliveTime}参数的时间单位
     * @param workQueue       在执行任务之前用于保留任务的队列。此队列将仅保存由{@code execute}方法提交的{@code Runnable}任务。
     * @param threadFactory   执行程序创建新线程时要使用的工厂
     * @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.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

allowCoreThreadTimeOut 翻译过来就是 允许核心线程数超时
当 allowCoreThreadTimeOut 为true的时候,线程池最后销毁数量为0
当allowCoreThreadTimeOut 为false的时候,当前线程数大于核心线程数,且timeout超时才会销毁

核心线程数:提交一个任务到线程池的时候,线程池会创建一个线程来执行任务,当任务数量超过核心线程数的时候就不会再创建线程了,还有一种情况是执行了 方法,创建线程池的时候默认创建核心线程数数量的线程
最大线程数:当任务超过核心线程数处理的范围,队列也满了就会根据最大线程数创建线程
工作队列:用于保存等待执行的任务的阻塞队列,队列有以下几种

  • ArrayBlockingQueue:规定大小的BlockingQueue,其构造必须指定大小。由数组支持的有界阻塞队列,保持先进先出的原则
  • LinkedBlockingQueue:大小不固定的BlockingQueue,若其构造时指定大小,生成的BlockingQueue有大小限制,不指定大小,其大小有Integer.MAX_VALUE来决定。基于列表实现,在队列的尾部插入元素,头部获取元素,也是先进先出
  • PriorityBlockingQueue:是一个支持优先级的无界阻塞队列,默认是自然的排序,也可以指定元素进行排序
  • SynchronizedQueue:从字面理解也就是安全的队列,只能进行某一个操作。

线程工厂:用于设置创建线程的工厂,在我们平常编程中一般不会操作,可通过线程工厂设置每个线程的名字
拒绝策略:当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常,策略有以下几种:

  • AbortPolicy
    线程池默认的拒绝策略,在任务不能再提交的时候,抛出异常,及时反馈程序运行状态。如果是比较关键的业务,推荐使用此拒绝策略,这样子在系统不能承载更大的并发量的时候,能够及时的通过异常发现。
 public static class AbortPolicy implements RejectedExecutionHandler {
        public AbortPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }
  • DiscardPolicy
    丢弃任务,但是不抛出异常。如果线程队列已满,则后续提交的任务都会被丢弃,且是静默丢弃。(一般不建议使用)
  public static class DiscardPolicy implements RejectedExecutionHandler {
        public DiscardPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }
  • DiscardOldestPolicy
    丢弃队列最前面的任务,然后重新提交被拒绝的任务
 public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        public DiscardOldestPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }
  • CallerRunsPolicy
    如果任务被拒绝了,则由调用线程(提交任务的线程)直接执行此任务,其实也就是主线程执行
public static class CallerRunsPolicy implements RejectedExecutionHandler {
        public CallerRunsPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }

超时时间单位:TimeUnit:DAYS,HOURS,MINUTES,MILLISECONDS,MICROSECONDS,NANOSECONDS
等待最长时间:线程池的工作线程空闲后,保持存活的时间

  • 线程池的状态
    Running、ShutDown、Stop、Tidying、Terminated。
    线程池运行状态

  • Running
    线程池处于当前状态下可以接受并处理任务,线程池创建后状态就变为了running

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
  • ShutDown
    线程池处于当前状态的时候,不接受任务,但可以处理已接受的任务
    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            advanceRunState(SHUTDOWN);
            interruptIdleWorkers();
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
    }
  • Stop
    线程池处于当前状态下,不接受,不处理,还随时中断当前执行的任务
 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;
    }
  • Tidying与Terminated
    Terminated 线程池彻底终止
    Tidying 当所有的任务已终止,ctl记录的”任务数量”为0,线程池会变为TIDYING状态。
    当成为tidying后悔马上执行terminated()方法 但是此方法默认为空,所以会直接进入Terminated 状态
    private static int ctlOf(int rs, int wc) { return rs | wc; }
 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();
                    }
                    return;
                }
            } finally {
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值