• ThreadPoolExecutor——线程销毁


    面试官:知道线程池吗

    我:知道啊,然后准备回答,线程池原理及实现流程

    面试官打断:最近面试人挺多的,基本都知道原理,你给我讲讲keepAliveTime具体是怎样实现非核心线程过期回收的。

    我:.....(黑人问号)

    面试完,迫不及待的打开源码后,发现之前看源码已经看过线程过期后怎样销毁的,但主要是想弄懂线程复用的原理,所以没有注意。

    前文源码学习:Java并发包中的线程池ThreadPoolExecutor

    一、线程过期销毁

     1、Worker.run():线程池线程复用的原理

        final void runWorker(Worker w) {
            Thread wt = Thread.currentThread();
            Runnable task = w.firstTask;
            w.firstTask = null;
            w.unlock(); //将state设置为0,允许中断 allow interrupts
            boolean completedAbruptly = true;
            try {
                //这里就是线程复用的实质,线程执行完提交的任务后,会不停从阻塞队列workerQueue中获取任务再执行
    //跳出这里的循环,线程就不会复用,执行完runWorker方法后会被销毁
    while (task != null || (task = getTask()) != null) { w.lock();//worker不可重入独占锁 // 如果线程池正在停止Stopping,确保线程中断 // 如果没有,确保线程没有被中断 // 第二种情况需要复查处理 // 清除中断时立即停止比赛 if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted()) wt.interrupt(); try { //执行任务前操作--空方法预留扩展 beforeExecute(wt, task); Throwable thrown = null; try { //实际的任务运行command.run() 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 { //执行清理工作, //将当前线程完成任务数累加到总任务数上 //从workerSet中删除当前工作线程 //尝试终止线程池 //如果当前线程个数小于核心个数,创建线程 processWorkerExit(w, completedAbruptly); } }

    2、线程过期销毁

        final void runWorker(Worker w) {
            Thread wt = Thread.currentThread();
            //开始执行前会将work.firstTask = null,核心线程、非核心线程都是
            Runnable task = w.firstTask;
            w.firstTask = null;
            w.unlock(); // allow interrupts
            boolean completedAbruptly = true;
            try {
                //一次循环后task == null,所以线程过期销毁判断关键在于getTask()
                while (task != null || (task = getTask()) != null) {
                    w.lock();
                    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
                        task = null;
                        w.completedTasks++;
                        w.unlock();
                    }
                }
                completedAbruptly = false;
            } finally {
                processWorkerExit(w, completedAbruptly);
            }
        }

    ThreadPoolExecutor.getTask()

     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())) {
    //如果工作队列为空,线程池线程数减1,并返回null decrementWorkerCount();
    return null; } int wc = workerCountOf(c); //worker工作线程会不会被回收
    //① allowCoreThreadTimeOut == true,核心线程和非核心线程空闲keepAliveTime被销毁,workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)
    //② allowCoreThreadTimeOut == false,非核心线程空闲keepAliveTIme销毁,workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)
    // ,核心线程会被阻塞,不会被销毁workQueue.take()
    boolean timed = allowCoreThreadTimeOut || wc > corePoolSize; if ((wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())) { if (compareAndDecrementWorkerCount(c)) return null; continue; } try { Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take(); if (r != null) return r; timedOut = true; } catch (InterruptedException retry) { timedOut = false; } } }

    所以keepAliveTime具体是怎样实现非核心线程过期销毁的,是个很简单的问题。有点后悔没答上来

    workQueue队列为空,跳出循环,线程就会被销毁。具体代码通过阻塞队列workQueue(keepAliveTime,TimeUnit.NANOSECONDS)实现控制线程存活时间的

    线程销毁的两种场景:

    ① allowCoreThreadTimeOut == true,核心线程和非核心线程空闲keepAliveTime时被销毁,workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)
    ② allowCoreThreadTimeOut == false,非核心线程空闲keepAliveTIme时被销毁,workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)

    核心线程永不销毁的场景

    ① allowCoreThreadTimeOut == false,核心线程永不销毁。workQueue.take()阻塞当前线程。

  • 相关阅读:
    这些简单优化能让你的Win10流畅很多
    win7系统登录界面背景怎么修改?
    如何在win7下通过easyBCD引导安装Ubuntu14.04
    为什么我的电脑打不开便签?
    打开Word为什么会出现感叹号呢???
    图像变换原理
    运行
    php、前端开发(网站建设)环境搭建
    zend studio面板功能
    zend studio汉化
  • 原文地址:https://www.cnblogs.com/wqff-biubiu/p/12589450.html
Copyright © 2020-2023  润新知