公用线程池要不要shutdown?

时间:2024-03-12 17:46:48

  最近学习了线程过后,又想学学线程池,在写测试代码的时候想到一个问题,线程太多可能会导致内存占满的问题,那线程池要不要关闭呢?怎么关闭呢?

  已知关闭有两种方法,shutdown()和shutdownNow()。shutdown()方法会关闭线程池,不再接受新的任务,已接受的任务会继续执行,直到完成。shutdownNow()方法也类似,不过它会去尝试终止正在执行的任务。如果任务都已提交或者都执行完,当然shutdown就没问题啦。那还有线程没execute线程池就被shutdown呢?

  我们先写一个线程池的公用单例。

/**
 * @ClassName ThreadPoolSingleTest
 * @Description 线程池单例模式
 * @Auther zhui
 * @Date 2020/7/2 8:47
 * @Version 1.0
 **/
public class ThreadPoolSingleTest {
    private  static ThreadPoolExecutor threadPoolExecutor=null;

    public static ThreadPoolExecutor getThreadPoolExecutor(){
        if(threadPoolExecutor==null){
            synchronized (ThreadPoolSingleTest.class){
                if(threadPoolExecutor==null){
                    threadPoolExecutor= new ThreadPoolExecutor(10,50,5, TimeUnit.MINUTES,new LinkedBlockingQueue<>());
                }
            }
        }
        return threadPoolExecutor;
    }
}

  然后测试如果还未execute,线程池就被别的线程shutdown了怎么办?

public class Test {
    public static void main(String[] args) {
        ThreadPoolExecutor threadPoolExecutor = ThreadPoolSingleTest.getThreadPoolExecutor();
        //这个线程执行完成后就shutdown线程
        threadPoolExecutor.execute(()->{
            try{
                Thread.sleep(2000);
            }catch (Exception e){}

        });

        //模拟其他线程拿到了线程池实例,但是还未提交任务
        new Thread(()->{
            ThreadPoolExecutor threadPoolExecutor1 = ThreadPoolSingleTest.getThreadPoolExecutor();
            out.println("new Thread已经拿到了ThreadPoolExecutor");
            try{
                //等它睡醒,懵逼的发现线程池被shutdown了
                Thread.sleep(5000);
            }catch (Exception e){}
            threadPoolExecutor1.execute(()->{
                out.println("执行");
            });
        }).start();
        threadPoolExecutor.shutdown();
    }
}

  运行结果还是报错了,线程池被关掉了,无法提交任务。

Exception in thread "Thread-0" java.util.concurrent.RejectedExecutionException: Task 测试.Test$$Lambda$3/1588496549@50697d00 rejected from java.util.concurrent.ThreadPoolExecutor@5456e3d5[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 1]
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
    at 测试.Test.lambda$main$2(Test.java:310)
    at java.lang.Thread.run(Thread.java:748)

  做到这里,就知道了,公用线程池是不能被shutdown的,毕竟在业务上,一个地方手贱的shutdown了,其他持有线程池对象却没来得及提交任务的代码就GameOver了。但是但是就真的有人手贱要shutdown怎么办?哎,那没办法,单例模式再多加一个判断吧。

public class ThreadPoolSingleTest {
    private  static ThreadPoolExecutor threadPoolExecutor=null;

    public static ThreadPoolExecutor getThreadPoolExecutor(){
    //为null和被shutdown都实例化对象
    if(threadPoolExecutor==null||threadPoolExecutor.isShutdown()){
            synchronized (ThreadPoolSingleTest.class){
                if(threadPoolExecutor==null||threadPoolExecutor.isShutdown()){
                    threadPoolExecutor= new ThreadPoolExecutor(10,50,5, TimeUnit.MINUTES,new LinkedBlockingQueue<>());
                }
            }
        }
        return threadPoolExecutor;
    }
}

  以上方法只是防止被shutdown后执行任务失败,但是还是会有错误的风险,所以最好还是不要随便的shutdown线程池了。