編寫多線程程序往往是為了提高資源的利用率,或者提高程序的運行效率,或者更好地監控程序的運行過程等。多線程同步處理的目的是為了讓多個線程協調地並發工作。對多線程進行同步處理可以通過同步方法和同步語句塊實現。Java虛擬機是通過對資源(如內存)加鎖的方式實現這兩種同步方式。這種機制帶來的另一個問題就是死鎖問題(即程序的所有線程都處於阻塞態或等待態)。良好的程序設計應當設法避開這種死鎖問題。
如果在多個並發線程之間共用資源,則可能就需要進行同步處理。Java虛擬機通過給每個對象加鎖的方式實現多線程的同步處理。這裡的對象包括類對象和實例對象兩種。一個類的靜態成員域和靜態成員方法隸屬於類對象。一個類的非靜態成員域和非靜態成員方法是不隸屬於類對象的,而隸屬於類的實例對象。
Java虛擬機為每個對象配備一把鎖和一個等候集。對象內部鎖住的是一些同步方法和同步語句塊。一個方法要成為同步方法只要給該方法加上修飾詞synchronized就可以。同步語句塊的定義格式如下:
Synchronized(引用類型的表達式)
語句塊
其中,關鍵字synchronized是同步語句塊的引導詞;位於“()”內的表達式必須是引用類型的表達式,指向某個類對象或實例對象,即指定與該同步語句塊相關連的對象;語句塊則由一對“{}”及這對大括號所括起來的一系列語句組成。
由於同步處理機制,Java虛擬機在運行同步方法或同步語句塊時在時間和空間上需要一些額外開銷。雖然利用多線程可以提高資源的利用率,但是如果過於頻繁地用同步方法或同步語句塊,則會降低多線程的並行度,並可能因為Java虛擬機的額外開銷過大而最終降低程序的運行效率。
資源短缺會造成程序的所有線程都陷入等待態或阻塞態。死鎖問題常常指的是造成這種情況的問題:資源實際上並不短缺,但由於程序設計不合理而造成程序的所有線程都處於等待態或阻塞態。典型的情況是每個線程都占有若干個資源的同時在等待若干個資源,而等待的資源都被其他線程所控制,所以每個線程都處於阻塞態。
Java虛擬機通過Java語言的多線程特性提高了Java程序的運行效率。在多個線程之間常常因為共享內存等而需要同步處理。同步處理常常會降低線程的並行度,即讓有些線程無法並行而只能串行。因此,很多資料認為多線程同步的粒度越小越好,即建議盡可能地減少在同步方法與同步語句塊中的代碼量,從而縮短多個線程串行運行的時間。實際上,這樣會不會提高程序的運行效率是一個值得討論的問題。這些資料忽略了Java虛擬機為線程的同步處理所需要的額外開銷,即如果頻繁地進入和退出同步方法或同步語句塊,也會降低程序的運行效率。良好的多線程程序設計應當做好多線程同步的粒度與同步處理的次數之間的平衡關系,從而真正提高程序的運行效率。