【线程池为什么要shutdown()】

线程池为什么要shutdown()

线程的内存泄漏

线程池在处理任务的时候,内部会启动线程,而线程的启动在addWorker中,也是使用Thread对象的start()方法。这种线程会占用一个虚拟机栈,在JVM层面输入GC root,根据可达性分析算法,这个线程就不会被回收,会一直占用JVM内存资源,这样就会造成所有的线程的核心线程永远都不会被回收,也就是内存泄漏。

另外,当执行任务时,start()会调用Worker的run方法(实现了Runnable),而在Worker的run方法中又使用了ThreadPoolExecutor的runWorker(Worker w)方法。也就是启动了的线程,还指向了Worker对象。Worker对象也无法被回收。

同时Worker是ThreadPoolExecutor的内部类,如果内部类不能被回收,外部类ThreadPoolExecutor也不能被回收。所以说,如果没有关闭ThreadPoolExecutor,就会造成堆内存占用很严重,进而影响GC。

调用了shutdown()

把线程池的状态从RUNNING改为SHUTDOWN,所有阻塞的线程,通过SHUTDOWN跳出任务获取的过程,因为我们核心线程执行完任务后,通过getTask()从阻塞队列中获取任务。如果是非核心线程,则调用poll(keepAliveTime,TimeUnit.NANOSECOND)来获取任务,一段时间后,获取不到线程结束。如果是核心线程,执行take(),一直在这里等待阻塞。当执行shutdown(),更改了线程池的状态后,就不会再走到take()方法了.

还会调用InterruptIdleWorkers(),把所有的没有执行中断任务的线程的interrupt标记设为true。设为中断后,这个时候已经走到take()方法的线程就会被唤醒,会继续向下走,重新循环,重新判断线程池是否已经shutdown(),进而退出getTask()方法,就会退出runWorker(Worker w);最后做一些处理,返回到Worker的run方法,结束run方法。

    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())) {
                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;
            }
        }
    }

调用了shutdownNow()

把状态改为STOP.当执行到getTask()之前就会判断线程池的状态,线程池的状态不是RUNNING就直接结束,并且interruptWorkers()会中断所有正在进行的线程,包括正在进行的任务。以更快的速度结束掉线程的生命周期

结论

调用shutdownNow()或者shutdown()后,工作线程没有了,Woker对象就没有指向了,Worker对象没有指向了,线程池对象也就没有指向了,这样就可以被GC正常回收。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值