java线程池正确使用姿势

有哪些常见线程池类型

以使用工具类 Executors 进行创建线程池为参照

// FixedThreadPool 固定线程数池
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
// SingleThread 单线程池
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
// CachedThreadPool 缓存线程效果的线程池
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
// ScheduledThreadPool 可延迟或定期执行的线程池
public static ScheduledExecutorService newScheduledThreadPool(
            int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }
// 线程可以窃取其他线程的队列任务进行执行
public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }
// 不可配置的线程池
public static ExecutorService unconfigurableExecutorService(ExecutorService executor) {
        if (executor == null)
            throw new NullPointerException();
        return new DelegatedExecutorService(executor);
    }

FixedThreadPool、SingleThread、CachedThreadPool、ScheduledThreadPool 底层均是 ThreadPoolExecutor 类创建的对象。

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);// 线程保活时间,可设置 allowCoreThreadTimeOut 状态,使其对核心线程也进行回收。
        this.threadFactory = threadFactory;//创建线程的工厂
        this.handler = handler;//拒绝服务策略
    }

构造器方法,说明线程池刚创建时,不创建线程对象,等到执行任务时才创建线程。

进入到执行任务的核心方法 execute:

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /*
         * Proceed in 3 steps: 分三步处理
         *
         * 1. If fewer than corePoolSize threads are running, try to
         * start a new thread with the given command as its first 如果运行的线程少于corePoolSize,那么尝试使用给定命令作为第一个任务启动一个新线程。
         * task.  The call to addWorker atomically checks runState and
         * workerCount, and so prevents false alarms that would add
         * threads when it shouldn't, by returning false. 对addWorker的调用会自动检查runState和workerCount,从而通过返回false防止在不应该添加线程的情况下添加线程的错误警报。
         *
         * 2. If a task can be successfully queued, then we still need
         * to double-check whether we should have added a thread
         * (because existing ones died since last checking) or that  如果任务能成功排队,
         * the pool shut down since entry into this method. So we
         * recheck state and if necessary roll back the enqueuing if
         * stopped, or start a new thread if there are none.
         *
         * 3. If we cannot queue task, then we try to add a new   如果不能排队成功,则尝试添加一个新的线程,如果失败说明线程关闭或线程池耗尽,拒绝任务
         * thread.  If it fails, we know we are shut down or saturated  
         * and so reject the task.
         */
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {//工作线程数量小于核心线程
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) { //将执行任务添加到工作队列中
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)//工作线程数量为0
                addWorker(null, false);
        }
        else if (!addWorker(command, false)) //核心线程耗尽且队列满了才进行创建新的非核心线程
            reject(command);//创建失败,走拒绝策略
    }

先创建核心线程 -> 核心线程数满了则放到工作队列中 -> 工作队列也满了则创建非核心线程。

核心线程数满了,工作队列满了,非核心线程满了,则走拒绝策略。有如下几种拒绝策略。

// 丢弃并抛出异常,此为默认的拒绝策略。
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());
        }
    }
// 丢弃并吞掉异常,一般不建议吞掉异常,除非你确定这个异常不需要抛出
public static class DiscardPolicy implements RejectedExecutionHandler {
        public DiscardPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }
// 使用执行该拒绝策略的线程进行任务的执行,前提是线程池没有被关闭
public static class CallerRunsPolicy implements RejectedExecutionHandler {
        public CallerRunsPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }
// 线程池未关闭时,丢弃队列的头节点任务后继续使用该线程池执行该任务
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        public DiscardOldestPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {//执行器关闭,直接丢弃任务,否则丢弃等待队列中的头节点,等待时间最长的节点,然后执行该任务
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }
使用线程池时注意哪些问题

最早在阿里 Java 编码规范见不建议使用 Executors 创建线程池,这里分析为什么?

这里主要集中分析 FixedThreadPool、SingleThread、CachedThreadPool、ScheduledThreadPool 这几个创建线程池的参数。

// FixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
/**
 * 链表本身是没有容量大小的,不像数组结构需要连续的内存空间,链表本身的容量限制于其描述他元素数量和容量边界的值
 * FixedThreadPool 创建了容量边界为 Integer.MAX_VALUE 的阻塞队列,会导致该队列消耗巨大的资源,无法触发拒绝策略。
 * 该阻塞队列将不停的放入任务会消耗巨大的资源,直至OOM
 */
public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }
// SingleThread 与 FixedThreadPool 问题一样
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
// 核心线程数为 0 ,最大线程数为 Integer.MAX_VALUE,线程 60 秒闲置将会被回收。
// 假设一个线程消耗 100k 那么需要以2的32方 (4294967296 * 100) / 1024 / 1024 / 1024 = 400T 的内存大小才能装下这么多线程,否则就会内存溢出
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
// 同上分析,一个线程池中,线程数量资源和队列消耗的资源需要特别注意,如果能确保执行的任务数量和线程数量在正常范围内,则是安全的
public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }

这几个线程池底层都是 ThreadPoolExecutor ,只不过通过线程数量和 BlockingQueue workQueue 构建出不同效果的线程池。

总结,一个线程池中,线程数量资源和队列消耗的资源需要特别注意,如果能确保执行的任务数量和线程数量在正常范围内,则是安全的。

线程池的工作流程是怎么样的?
// 从添加核心线程开始
private boolean addWorker(Runnable firstTask, boolean core) {
    // ....
    try {
            w = new Worker(firstTask); // 创建一个工作
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    int rs = runStateOf(ctl.get());

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        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;
}
// t.start() 实际执行了 Worker 中的 run() 方法
private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
{
     	final Thread thread;
        /** Initial task to run.  Possibly null. */
        Runnable firstTask;
        /** Per-thread task counter */
        volatile long completedTasks;//已完成任务的数量

        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker 在runWorker之前禁止中断
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this); // 将当前的 worker 放到新创建的 Thread 中去
        }

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

// runWorker() 方法,getTask() 方法是从队列中获取任务,如果获取的任务为 null 则会导致线程进入退出操作
final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;//清空任务
        w.unlock(); // allow interrupts 允许中断,刚创建是 -1 设置为 0;
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {//如果返回的task为null,就会导致线程被销毁
                w.lock();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                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);
        }
    }
// 从队列中获取去执行的任务(Runnable)
private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            int wc = workerCountOf(c);

            // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; // 如果不允许

            if ((wc > maximumPoolSize || (timed && timedOut))//线程数大于最大线程数或者((允许销毁核心线程数或线程数大于核心线程数)且获取任务超时)
                && (wc > 1 || workQueue.isEmpty())) {//且(线程数量大于0或者任务队列为空)
                if (compareAndDecrementWorkerCount(c))
                    return null;//减少一个工作线程
                continue;
            }

            try {
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : // 工作线程超过保活时间未获取到值则返回null
                    workQueue.take();//阻塞工作线程获取任务
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }
什么时候关闭空闲线程?
// 1.打破线程中的轮询既 getTask() 返回值为null即可,线程自己运行完结束。线程释放前执行 finally 中定义的方法如下。
private void processWorkerExit(Worker w, boolean completedAbruptly) {
        if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
            decrementWorkerCount();

        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            completedTaskCount += w.completedTasks; // 将 worker 中完成的任务数量加到 completedTaskCount 中
            workers.remove(w); // 将当前线程从 workers 集合中去除
        } finally {
            mainLock.unlock();
        }

        tryTerminate(); //

        int c = ctl.get();
        if (runStateLessThan(c, STOP)) {
            if (!completedAbruptly) {
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && ! workQueue.isEmpty())
                    min = 1;
                if (workerCountOf(c) >= min)
                    return; // replacement not needed
            }
            addWorker(null, false); // 如果线程数量大于等于最小值则不创建线程,否则创建一个新的非核心线程
        }
    }

// 2.从1的操作中,最终还会尝试触发释放闲置线程,此时 onlyOne 为false
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()) {//线程未被中断且未执行任务,则进行释放
                    try {
                        t.interrupt();//通过中断来释放线程
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                if (onlyOne)
                    break;
            }
        } finally {
            mainLock.unlock();
        }
    }
newScheduledThreadPool 线程池的时间调度咋处理的?
// 存放任务的队列使用小顶堆结构,以执行任务的 compareTo() 方法进行排序
 static class DelayedWorkQueue extends AbstractQueue<Runnable>
        implements BlockingQueue<Runnable> {
     public RunnableScheduledFuture<?> take() throws InterruptedException {
            final ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            try {
                for (;;) {
                    RunnableScheduledFuture<?> first = queue[0];//取出队列中第一个任务
                    if (first == null)
                        available.await();//队列中没有任务,则阻塞到可用条件等待队列中
                    else {
                        long delay = first.getDelay(NANOSECONDS);
                        if (delay <= 0)
                            return finishPoll(first);//已过触发时间
                        first = null; // don't retain ref while waiting
                        if (leader != null)//有没有其他线程正在获取任务
                            available.await();//如果有该线程直接阻塞
                        else {//没有则将当前线程设置为leader,
                            Thread thisThread = Thread.currentThread();
                            leader = thisThread;
                            try {
                                available.awaitNanos(delay);//阻塞一段时间
                            } finally {
                                if (leader == thisThread)
                                    leader = null;
                            }
                        }
                    }
                }
            } finally {
                if (leader == null && queue[0] != null)
                    available.signal();
                lock.unlock();
            }
        }
 } 
// 任务执行完成后判断是否再放到执行队列中
private class ScheduledFutureTask<V>
            extends FutureTask<V> implements RunnableScheduledFuture<V> {
    /** Sequence number to break ties FIFO */
        private final long sequenceNumber;
    /** The time the task is enabled to execute in nanoTime units */
        private long time;
    	private final long period;
    
    public void run() {
            boolean periodic = isPeriodic(); // 是否是周期性的
            if (!canRunInCurrentRunState(periodic))
                cancel(false);
            else if (!periodic)
                ScheduledFutureTask.super.run();
            else if (ScheduledFutureTask.super.runAndReset()) {
                setNextRunTime(); // 重新设置 time 
                reExecutePeriodic(outerTask); 
            }
        }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值