Java 中的線程管理概念梳理

Java中,線程java.lang.Thread類的一個實例以及線程的執行,主要使用的線程池是ThreadPoolExecutor以及ScheduledThreadPoolExecutor,要使用固定線程上限的線程池。

用synchronized 修飾靜態方法時,表示任何兩個不同線程的調用互斥;修飾成員函數時,表示同一對象的多線程方法調用互斥;當然了,synchronized 後的參數可以是任意對象。Synchronized保證了synchronized塊中變量的可見性,而volatile保證了所修飾變量的可見性。ReentrantLock是java.util.concurrent.locks中的一個類,與synchronized用法類似,但需要顯示的解鎖,它提供了ReentrantReadWriteLock,主要用於讀多寫少且讀不需要互斥的場景。

Java.util.concurrent.atomic包中以Atomic開頭的類提供了一些相關的原子操作,性能提升的原因是內部通過JNI的方式使用了硬件支持的CAS指令。 


Object對象上的三個必備方法:wait、notify、notifyall。Nofity喚醒一個等待線程,notifyall會喚醒所有的等待線程。Wait的使用一般嵌在一個循環中,判斷相關的數據狀態是否達到預期,如果沒有則繼續等待,主要是爲了防止虛假喚醒。

 

Java.util.concurrent 中CountDownLatch提供的機制是當多個線程都到達了預期狀態或者完成預期工作時觸發事件,其他線程可以等待這個事件來觸發自己後續的工作。CyclicBarrier可以協同多個線程,讓多個線程在mybarrier.wait()前等待,直到所有線程都到達了這個屏障時,再一起執行後面的動作。

 

CountDownLatch 與CyclicBarrier都有用於線程協調的,主要差別有:CountDownLatch在多個線程都執行了latch.countDown後才觸發事件,喚醒wait在latch上的線程,而執行countDown的線程在執行完countDown後會繼續自己線程的工作;CyclicBarrier是個柵欄,用於同步所有調用wait方法的線程,並且等所有線程都到了wait的方法時,這些線程才一起返回繼續各自的工作。另外,CountDownLatch不能循環使用,而CyclicBarrier可以循環使用。


Semaphore用於管理信號量,信號量對象構造時傳入信號個數就是控制併發的數量。執行前通過acquire獲取信號,執行後通過release歸還,如果沒有可用的信號,aquire調用就會阻塞。與控制線程數來控制併發數相比,semaphore控制併發數的控制粒度更細。

 

Exchanger用於在兩個線程之間進行數據交換。線程會阻塞在Exchanger的exchange方法,直到另外一個線程也到了同一個Exchanger的exchange方法時,二者進行交換,然後兩個線程會繼續執行自身相關的代碼。

 

異步調用的實現方式常用的有:future 和回調函數。調用的方法會返回一個future對象,然後接着進行自己的處理,後面通過future.get()來獲取真正的返回值。 FutureTask是future的一個具體實現類。ThreadPoolExecutor的submit方法返回的就是一個FutureTask的具體實現。FutureTask幫助實現了具體的任務執行以及與future接口中的get等方法的關聯。FutureTask幫助ThreadPoolExecutor實現了對加入線程池任務的future支持,也使我們能夠實現支持future的任務調度。

 

加鎖互斥能夠方便地實現線程安全,但代價是降低了性能,而併發容器不僅追求線程安全,而且考慮併發,提升容器在併發環境下的性能。比較有代表性的是以CopyOnWrite和Concurrent開頭的幾個容器。


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