1. 程式人生 > >Java並發編程之synchronized

Java並發編程之synchronized

異常 moni 實現 心態 cin 同步塊 enum 鎖對象 靈活

在Java編程中,為了保證線程安全,有3種不同的思路
1、互斥同步:包括synchronized和lock等。

2、非阻塞同步:如AtomicInteger的increaseAndGet()方法等。

3、無同步:如ThreadLocal方案。

本文介紹使用synchronized實現同步的方法。

1、修飾方法 synchronized static方法:鎖加在類上;synchronized 普通方法:鎖加在對象上。由此可以知道:
  • 當一個線程正在訪問一個對象的synchronized方法,那麽其他線程不能訪問該對象的其他synchronized方法。
  • 當一個線程正在訪問一個對象的synchronized方法,那麽其他線程能訪問該對象的非synchronized方法。
  • 如果一個線程A需要訪問對象object1的synchronized方法fun1,另外一個線程B需要訪問對象object2的synchronized方法fun1,即使object1和object2是同一類型,也不會產生線程安全問題,因為他們訪問的是不同的對象,所以不存在互斥問題。
  • 如果一個線程執行一個對象的synchronized普通方法,另外一個線程需要執行這個對象所屬類的synchronized static方法,此時不會發生互斥現象,因為訪問synchronized static方法占用的是類鎖,而訪問synchronized普通方法占用的是對象鎖,所以不存在互斥問題。
2、修飾代碼塊:代碼如下所示。
synchronized(synObject) {
......
}
當在某個線程中執行這段代碼塊,該線程會獲取對象synObject的鎖,從而使得其他線程無法同時訪問該代碼塊。synObject可以是this,代表獲取當前對象的鎖,也可以是類中的一個屬性,代表獲取該屬性的鎖。修飾代碼塊與修飾方法相比,更加靈活,可以選擇方法中需要同步的代碼塊進行同步。 無論synObject是不是this,對於被同步的對象而言,不同方法之間的相互影響,類似於1中描述:如果是某對象的一個同步代碼塊被執行,那麽該對象的所有同步代碼塊、同步方法,都要等該代碼塊執行完才能夠執行;同步方法與之類似。 3、synchronized還可以修飾類,如下所示。
synchronized(xxx.class) {
......
}
就像synchronized(syncObject)與synchronized普通方法作用類似,synchronized(xx.class)與synchronized static方法作用類似,是加在類上的鎖。同樣,synchronized(xx.class)與synchronized static方法,如果是對同一類的鎖,也會互斥。 4、對於synchronized方法或者synchronized代碼塊,當出現異常時,JVM會自動釋放當前線程占用的鎖,因此不會由於異常導致出現死鎖現象。 5、原理解析:在Java中,每一個對象都擁有一個鎖標記(monitor),多線程同時訪問某個對象時,線程只有獲取了該對象的鎖才能訪問。每個類應該也有這個標記。這就解釋了為什麽同一個對象的不同synchronized方法和synchronized代碼塊是互斥的,因為他們共用一個鎖;同樣解釋了類層面的互斥。 對於synchronized代碼塊,對應的字節碼是monitorenter和monitorexit;synchronized方法對應的字節碼仍然是synchronized。monitorenter和monitorexit字節碼指令需要reference類型的參數,當Java程序中沒有明確指定時,JVM會取實例對象或Class對象作為鎖對象。 註意:synchronized同步塊對同一條線程來說是可重入的,不會出現自己把自己鎖死的問題。 6、同步塊在已進入的線程執行完之前,會阻塞後面其他線程的進入。而Java的線程是映射到操作系統的原生線程之上的,如果要阻塞或喚醒一個線程,都需要操作系統來幫忙完成,這就需要從用戶態轉換到核心態中,因此狀態轉換需要耗費很多的處理器時間。對於代碼簡單的同步塊(如被synchronized修飾的getter()或setter()方法),狀態轉換消耗的時間有可能比用戶代碼執行的時間還要長。所以synchronized是Java語言中一個重量級(Heavyweight)的操作,有經驗的程序員都會在確實必要的情況下才使用這種操作。而虛擬機本身也會進行一些優化,譬如在通知操作系統阻塞線程之前加入一段自旋等待過程,避免頻繁地切入到核心態之中。

Java並發編程之synchronized