由于實現多線程并發能夠極大地提高程序的運行效率,因此如何有效地實現多線程并發便成為了一個程序員重點關注的問題。
Java 內存模型
在
實現多線程并發之前首先需要了解 Java 內存模型(Java Memory Model), Java MM
的關鍵是線程的工作內存與主內存之間的關系,工作內存存儲的是線程實際操作的數據,而主內存則是線程所操作數據的實際所在位置,因此工作內存中的數據是主
內存中對應數據的一個副本。Java MM 的示意圖如下圖所示。
Java內存模型
所有線程在對數據操作之前都先從主內存中將相應數據緩存到工作內存中,這樣可以降低主內存的讀取頻率,減小數據讀取時延,當線程處理完數據后再將其刷新到主內存中,注意若不加同步操作,工作內存中的數據在處理后不一定會馬上刷新到主內存,同步操作將在后面介紹。
線程的兩種生成方法
Java 可以采用兩種方法生成線程,一種是直接繼承 Thread 類,一種是實現 Runnable 接口,這兩種方法各有優缺點。
線程之間如何進行通信?
線程之間可以通過多種方式進行通信,但面臨的問題都在于如何確保共享信息的及時刷新和同步訪問。
另外介紹Java的兩種比較實用的同步類,這兩種同步類都是實現多個線程相互等待的功能,其中 CyclicBarrier,如其名,可以重復運行,而 CountDownLatch 則運行一次后便失效。
CyclicBarrier
CountDownLatch
多線程如何優雅的結束?
說到線程的結束就不得不提一下 Java 的 GC(Garbage Collection)策略。
引用 Stack Overflow 上的一個答案(From falstro)。
A running thread is considered a so called garbage collection
root and is one of those things keeping stuff from being garbage
collected. When the garbage collector determines whether your object is
‘reachable’ or not, it is always doing so using the set of garbage
collector roots as reference points.
Consider this, why is your main thread not being garbage collected, no one is referencing that one either.
因此若線程沒有安全結束如陷入阻塞或者死循環狀態,即使該線程沒有被引用,JVM也是不會主動清理此線程的,從而會造成內存泄漏。
若多個線程之間存在同步操作,則需合理使用 wait(), notify(), notifyall()以及合理安排各線程的結束順序。
多線程并發調試工具
最后介紹一個實用工具:VisualVM,利用其ThreadDump功能可以大大提高多線程并發調試效率。
