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

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

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


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


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


立即关闭


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


/**
     * 立即关闭线程池,会造成任务丢失
     */
    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…


相关文章
|
4月前
|
缓存 Java
线程池使用小结
线程池使用小结
26 0
|
缓存 Java
线程池简单总结
线程池简单总结
|
6月前
|
缓存 算法 Java
|
6月前
|
Java C++
c++简单线程池实现
c++简单线程池实现
|
存储 Java 测试技术
13.一文彻底了解线程池
大家好,我是王有志。线程池是Java面试中必问的八股文,涉及到非常多的问题,今天我们就通过一篇文章,来彻底搞懂Java面试中关于线程池的问题。
401 2
13.一文彻底了解线程池
|
缓存 算法 Java
线程池和使用
线程池是一种用于管理和复用线程的机制。在多线程应用程序中,线程的创建和销毁需要消耗大量的系统资源,而线程池可以通过预先创建一定数量的线程,然后将任务分配给这些线程来避免频繁地创建和销毁线程,从而提高应用程序的性能和效率。线程池还可以控制并发线程的数量,避免过多的线程竞争资源导致的性能下降和系统崩溃。线程池是多线程编程中常用的一种技术,被广泛应用于各种类型的应用程序中。
76 0
线程池和使用
|
存储 Java 调度
线程池使用
线程池使用
|
Java 数据库连接 容器
关于线程池
关于线程池
86 0
KeyAffinityExecutor 线程池
KeyAffinityExecutor 线程池