线程池没你想的那么简单(下)

简介: 自己动手写一个五脏俱全的线程池,同时会了解到线程池的工作原理,以及如何在工作中合理的利用线程池。

而关闭线程通常又有以下两种:


  • 立即关闭:执行关闭方法后不管现在线程池的运行状况,直接一刀切全部停掉,这样会导致任务丢失。


  • 不接受新的任务,同时等待现有任务执行完毕后退出线程池。


立即关闭


我们先来看第一种立即关闭


/**
     * 立即关闭线程池,会造成任务丢失
     */
    public void shutDownNow() {
        isShutDown.set(true);
        tryClose(false);
    }
    /**
     * 关闭线程池
     *
     * @param isTry true 尝试关闭      --> 会等待所有任务执行完毕
     *              false 立即关闭线程池--> 任务有丢失的可能
     */
    private void tryClose(boolean isTry) {
        if (!isTry) {
            closeAllTask();
        } else {
            if (isShutDown.get() && totalTask.get() == 0) {
                closeAllTask();
            }
        }
    }
    /**
     * 关闭所有任务
     */
    private void closeAllTask() {
        for (Worker worker : workers) {
            //LOGGER.info("开始关闭");
            worker.close();
        }
    }
    public void close() {
        thread.interrupt();
    }


很容易看出,最终就是遍历线程池里所有的 worker 线程挨个执行他们的中断函数。


我们来测试一下:



可以发现后面丢进去的三个任务其实是没有被执行的。


完事后关闭


正常关闭则不一样:


/**
     * 任务执行完毕后关闭线程池
     */
    public void shutdown() {
        isShutDown.set(true);
        tryClose(true);
    }



他会在这里多了一个判断,需要所有任务都执行完毕之后才会去中断线程。


同时在线程需要回收时都会尝试关闭线程:



来看看实际效果:



回收线程


上文或多或少提到了线程回收的事情,其实总结就是以下两点:


  • 一旦执行了 shutdown/shutdownNow 方法都会将线程池的状态置为关闭状态,这样只要 worker 线程尝试从队列里获取任务时就会直接返回空,导致 worker 线程被回收。



  • 一旦线程池大小超过了核心线程数就会使用保活时间来从队列里获取任务,所以一旦获取不到返回 null 时就会触发回收。


但如果我们的队列足够大,导致线程数都不会超过核心线程数,这样是不会触发回收的。



比如这里我将队列大小调为 10 ,这样任务就会累计在队列里,不会创建五个 worker 线程。


所以一直都是 Thread-1~3 这三个线程在反复调度任务。


总结


本次实现了线程池里大部分核心功能,我相信只要看完并动手敲一遍一定会对线程池有不一样的理解。


结合目前的内容来总结下:


  • 线程池、队列大小要设计的合理,尽量的让任务从队列中获取执行。


  • 慎用 shutdownNow() 方法关闭线程池,会导致任务丢失(除非业务允许)。


  • 如果任务多,线程执行时间短可以调大 keepalive 值,使得线程尽量不被回收从而可以复用线程。


同时下次会分享一些线程池的新特性,如:


  • 执行带有返回值的线程。


  • 异常处理怎么办?


  • 所有任务执行完怎么通知我?


本文所有源码:


github.com/crossoverJi…


相关文章
|
缓存 Java 应用服务中间件
线程池的10个坑你都遇到过吗
日常开发中,为了更好管理线程资源,减少创建线程和销毁线程的资源损耗,我们会使用线程池来执行一些异步任务。但是线程池使用不当,就可能会引发生产事故。大家看完肯定会有帮助的~
213 0
|
2月前
|
缓存 Java
线程池使用小结
线程池使用小结
19 0
|
4月前
|
存储 Java 调度
浅谈线程池
浅谈线程池
34 1
|
4月前
|
缓存 Java API
厉害了,线程池就该这么玩
厉害了,线程池就该这么玩
43 0
|
4月前
|
Java C++
c++简单线程池实现
c++简单线程池实现
|
10月前
|
Java
6. 实现简单的线程池
6. 实现简单的线程池
48 0
|
存储 Java 测试技术
13.一文彻底了解线程池
大家好,我是王有志。线程池是Java面试中必问的八股文,涉及到非常多的问题,今天我们就通过一篇文章,来彻底搞懂Java面试中关于线程池的问题。
389 2
13.一文彻底了解线程池
|
缓存 Java 调度
线程池的介绍
线程池的介绍
|
存储 Java 调度
线程池使用
线程池使用
KeyAffinityExecutor 线程池
KeyAffinityExecutor 线程池