跟着ZooKeeper學Java——CountDownLatch和Join的使用


在閱讀ZooKeeper的源碼時,看到這么一個片段,在單機模式啟動的時候,會調用下面的方法,根據zoo.cfg的配置啟動單機版本的服務器:

public void runFromConfig(ServerConfig config) throws IOException {
	//1 創建ZooKeeper服務器
	final ZooKeeperServer zkServer = new ZooKeeperServer();
	final CountDownLatch shutdownLatch = new CountDownLatch(1);
    zkServer.registerServerShutdownHandler(
                    new ZooKeeperServerShutdownHandler(shutdownLatch));
	...
	//2 創建ZooKeeper的NIO線程
	cnxnFactory = ServerCnxnFactory.createFactory();
	cnxnFactory.configure(config.getClientPortAddress(),
	        config.getMaxClientCnxns());
	cnxnFactory.startup(zkServer);
	
	// 3 調用shutdownLatch阻塞,服務器在新線程正常處理請求
	shutdownLatch.await();
	// 4 如果有錯誤,直接調用shutdown
	shutdown();
	// 5 執行cnx.join()等待NIO線程關閉
	cnxnFactory.join();
	if (zkServer.canShutdown()) {
	    zkServer.shutdown(true);
	}
}
...
protected void shutdown() {
    if (cnxnFactory != null) {
        cnxnFactory.shutdown();
    }
}

其中比較有意思的兩個地方:

1 CountDownLatch的使用

開啟NIO新線程接收客戶端的請求,服務端的主線程直接利用countdownlatch掛起。這個CountDownLatch之前有說過,就是個多線程的計數器。

詳細內容參考文章——Java計數器之CountDownLatch、CyclicBarrier、Semaphore

2 join的作用

join的作用就是主線程遇到A.join()之后,就會掛起;登到A結束后,才會繼續執行。可以理解為主線程調用了A的wait方法...

下面有個Join的小例子:

public class JoinTest {
    public static void main(String[] args) throws InterruptedException {
        Thread A = new Thread(()->{
            System.out.println("進入線程A");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("A:線程A結束");
        });
        A.start();

        System.out.println("Main:等待線程A結束");
        A.join();
        System.out.println("Main:線程A已經結束,退出");
    }
}

輸出內容為:

Main:等待線程A結束
進入線程A
A:線程A結束
Main:線程A已經結束,退出

可以看到,Main線程在A.join()的地方掛起了。等A結束后,才繼續執行。

ZooKeeper這樣的設計,使服務器在關閉前,確保NIO線程正確關閉,避免NIO資源的未釋放。


免責聲明!

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



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