輔助線程 標識要用對了纔不會白白等待

背景

之前一個應用有一個小功能,每隔1分鐘創建一個線程來清理無效的http連接
主要邏輯之前是這樣寫的

private volatile boolean running = true;
@Override
    public void run() {
        try {
            while (running) {
                synchronized (this) {
                    wait(1000);
                    closeConnections();
                }
            }
        } catch (InterruptedException ex) {
            shutdown();
        }
    }

    public void shutdown() {
        running= false;
        synchronized (this) {
            notifyAll();
        }
    }

問題說明

最終的影響就是 不停地創建線程 直到線程溢出 OOM!

分析

有經驗的同學應該能看到這裏有個running,這個就是爲了標識線程要退出的信號量
但是 用錯了位置,或者說用錯了時間,導致線程一直是running狀態 而無法獲得notify退出

解決辦法

    private volatile boolean running = true;
    @Override
    public void run() {
        try {
            while (running ) {
                synchronized (this) {
                    wait(1000);
                    running= false;
                    connMgr.closeExpiredConnections();
                    connMgr.closeIdleConnections(5 * 60, TimeUnit.SECONDS);
                    logger.trace("clear closed http connections ok ,next to exit");
                }
            }
        } catch (InterruptedException ex) {
            shutdown();
        }
    }

    public void shutdown() {
//    	running= false;need to mark at wait
        synchronized (this) {
            notifyAll();
        }
    }

效果

線程能正常被notify 然後退出

拓展

其實這樣寫也有不合理的地方 比如try while的範圍,一般來講 synchronized是寫在while外面的,而 try 是寫在 while裏面的,這樣也符合此場景下功能要求,當然這樣寫也不能說有啥大問題,總體是正能量的

另外 也不需要用wait, 因爲就這一個線程在處理,可以sleep再直接退出 不涉及競爭的問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章