公用線程池要不要shutdown?


  最近學習了線程過后,又想學學線程池,在寫測試代碼的時候想到一個問題,線程太多可能會導致內存占滿的問題,那線程池要不要關閉呢?怎么關閉呢?

  已知關閉有兩種方法,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線程池了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM