一、synchronized含義
synchronized是Java語言的關鍵字,可用來給對象和方法或者代碼塊加鎖,當它鎖定一個方法或者一個代碼塊的時候,同一時刻非常多只有一個線程執行這段代碼。當兩個并發線程訪問同一個對象object中的這個加鎖同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以后才能執行該代碼塊。然而,當一個線程訪問object的一個加鎖代碼塊時,另一個線程仍可以訪問該object中的非加鎖代碼塊。
synchronized的作用是保證在同一時刻, 被修飾的代碼塊或方法只會有一個線程執行,以達到保證并發安全的效果。synchronized是Java中解決并發問題的一種最常用的方法,也是最簡單的一種方法。在JDK1.5之前synchronized是一個重量級鎖,相對于j.u.c.Lock,它會顯得那么笨重,隨著Javs SE 1.6對synchronized進行的各種優化后,synchronized并不會顯得那么重了。
二、synchronized的作用
1、原子性
所謂原子性就是指一個操作或者多個操作,要么全部執行并且執行的過程不會被任何因素打斷,要么就都不執行。被synchronized修飾的類或對象的所有操作都是原子的,因為在執行操作之前必須先獲得類或對象的鎖,直到執行完才能釋放。
2、可見性
可見性是指多個線程訪問一個資源時,該資源的狀態、值信息等對于其他線程都是可見的。synchronized和volatile都具有可見性,其中synchronized對一個類或對象加鎖時,一個線程如果要訪問該類或對象必須先獲得它的鎖,而這個鎖的狀態對于其他任何線程都是可見的,并且在釋放鎖之前會將對變量的修改刷新到共享內存當中,保證資源變量的可見性。
3、有序性
有序性值程序執行的順序按照代碼先后執行。 synchronized和volatile都具有有序性,Java允許編譯器和處理器對指令進行重排,但是指令重排并不會影響單線程的順序,它影響的是多線程并發執行的順序性。synchronized保證了每個時刻都只有一個線程訪問同步代碼塊,也就確定了線程執行同步代碼塊是分先后順序的,保證了有序性。
三、synchronized的使用
1、修飾實例方法
作用于當前對象實例加鎖,進入同步代碼前要獲得當前對象實例的鎖:
synchronized void method() { //業務代碼}
2、修飾靜態方法
即給當前類加鎖,會作用于類的所有對象實例 ,進入同步代碼前要獲得 當前 class 的鎖。因為靜態成員不屬于任何一個實例對象,是類成員( static 表明這是該類的一個靜態資源,不管 new 了多少個對象,只有一份)。所以,如果一個線程 A 調用一個實例對象的非靜態 synchronized 方法,而線程 B 需要調用這個實例對象所屬類的靜態 synchronized 方法,是允許的,不會發生互斥現象,因為訪問靜態 synchronized 方法占用的鎖是當前類的鎖,而訪問非靜態 synchronized 方法占用的鎖是當前實例對象鎖:
synchronized void staic method() { //業務代碼}
3、修飾代碼塊
指定加鎖對象,對給定對象/類加鎖。synchronized(this|object) 表示進入同步代碼庫前要獲得給定對象的鎖。synchronized(類.class) 表示進入同步代碼前要獲得當前 class 的鎖:
synchronized(this) { //業務代碼}
延伸閱讀1:synchronized 鎖的升級順序
鎖主要存在四種狀態,依次是:無鎖狀態、偏向鎖狀態、輕量級鎖狀態、重量級鎖狀態,鎖可以從偏向鎖升級到輕量級鎖,再升級的重量級鎖。但是鎖的升級是單向的,也就是說只能從低到高升級,不會出現鎖的降級。而且這個過程就是開銷逐漸加大的過程。