您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Java中synchronized關鍵字的使用方法,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
在并發編程中,synchronized關鍵字是常出現的角色。之前我們都稱呼synchronized關鍵字為重量鎖,但是在JDK1.6中對synchronized進行了優化,引入了偏向鎖、輕量鎖。本篇介紹synchronized關鍵字的使用方式,區別和偏向鎖、輕量鎖和重量鎖實現原理。
先看看synchronized關鍵字的4種用法。
1、修飾普通方法
private synchronized void synMethod(){ }
這種用法中,synchronized鎖的對象實例。
2、修飾靜態方法
private static synchronized void synMethod(){ }
synchronized在這種情況下,鎖的是當前Class類對象。
3、同步方法塊
private void synMethod1(){ synchronized(this){ } } private void synMethod2(){ synchronized(ThreadTest.class){ } }
synMethod1中鎖對象實例;synMethod2的是當前Class類對象。
再介紹鎖原理
在介紹鎖原理之前,先認識一下Java對象頭Mark Word,以32位為例。
鎖狀態 | 25 bit | 4bit | 1bit | 2bit | ||
| 23bit | 2bit | 是否偏向鎖 | 鎖標志位 | ||
輕量級鎖 | 指向棧中鎖記錄的指針 | 0 | ||||
重量級鎖 | 指向互斥量(重量級鎖)的指針 | 10 | ||||
GC標記 | 空 | 11 | ||||
偏向鎖 | 線程ID | Epoch | 對象分代年齡 | 1 | 01 | |
無鎖 | 對象的hashCode | 對象分代年齡 | 0 | 01 |
上面的表格中,描述的是對象在每個鎖狀態時,對象頭中所存儲的信息。
1、偏向鎖
實際環境中,線程在訪問同步塊時,如果沒有其他線程對鎖進行競爭,并且由同一個線程多次獲得鎖,也就是單線程運行同步代碼,在這種情況下,若是每次還阻塞線程,就代表白白浪費CPU性能。這種情況下,引入了偏向鎖概念。
訪問同步代碼塊
判斷對象頭Mark Word中存儲的線程ID是否指向當前線程,如果是,則表明當前是鎖的重入,不需要再獲得鎖,直接執行同步代碼
如果不是,則嘗試使用CAS算法將線程ID更新至對象頭中。
成功,獲得鎖,執行同步代碼。更新失敗表明存在鎖競爭,等待全局安全點,暫停擁有偏向鎖的線程,根據對象頭的鎖標志位,選擇將偏向鎖升級為輕量鎖或者置為無鎖。
可以使用-XX:-userBiasedLocking=false來關閉JVM偏向鎖優化,默認直接進入輕量鎖。
2、輕量鎖
訪問同步代碼塊時,先在當前線程的線程棧中創建一個鎖記錄(Lock Record)區域。
把對象頭Mark Word拷貝到Lock Record中。
利用CAS嘗試將對象頭Mark Word中的線程指針更新為指向當前線程的指針
更新成功,則獲得輕量鎖。
更新失敗,檢查Mark Word中的指針是否指向當前線程。
如果是,則說明是鎖的重入現象。執行同步代碼塊
如果不是,則說明此時存在競爭。需要把輕量鎖膨脹為重量鎖。
3、重量鎖
重量鎖是基于對象監視器(Monitor)來實現的。
線程在執行同步代碼時,需要調用一個Monitor.enter指令。執行退出后,調用Monitor.exit指令。這里看得出,監視器具有排它性,一個時間點只能有一個線程enter成功,其他線程只能阻塞在隊列中。所以這種重量鎖的操作成本很高。
關于Java中synchronized關鍵字的使用方法就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。