日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入理解 Synchronized

發(fā)布時間:2024/9/30 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解 Synchronized 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

同步

synchronized可以保證方法或者代碼塊在運行時,同一時刻只有一個方法可以進入到臨界區(qū),同時它還可以保證共享變量的內(nèi)存可見性
Java中每一個對象都可以作為鎖,這是synchronized實現(xiàn)同步的基礎(chǔ)。

synchronized 常見的三種用法如下:

  • 普通同步方法,鎖是當前實例對象
  • 靜態(tài)同步方法,鎖是當前類的class對象
  • 同步方法塊,鎖是括號里面的對象
  • 通過如下代碼來分析下synchronized 獲取的是哪個對象的鎖

    public class SynTest {private static List<String> list = new ArrayList<String>();//當前實例的鎖public synchronized void add1(String s){list.add(s);}//SynTest.class 鎖public static synchronized void add2(String s){list.add(s);}//SynTest.class 鎖public void add3(String s){synchronized(SynTest.class){list.add(s);}}//當前實例的鎖public void add4(String s){synchronized(this){list.add(s);}} }

    普通同步方法,鎖是當前實例對象
    add1 方法是synchronized的第一種用法,因為它是普通同步方法,所以獲取當前實例的鎖。
    add2 方法是synchronized的第二種用法,因為它是靜態(tài)同步方法,所以獲取SynTest.class的鎖。
    add3 方法是synchronized的第三種用法。指定鎖:SynTest.class。
    add4 方法是synchronized的第三種用法。指定鎖:this(當前實例)。

    結(jié)論:

    add1和add4方法的鎖都是 當前實例,所以add1和add4 可以實現(xiàn)方法互斥
    add2和add3方法的鎖都是SynTest.class,所以add2和add3可以實現(xiàn)方法互斥。
    **注意:**add1和add2兩個synchronized是不互斥的,因為他們不是同一把鎖。只有同一把鎖才會互斥。

    synchronized塊編譯成字節(jié)碼后會在同步塊的入口位置和退出位置分別插入monitorenter和monitorexit字節(jié)碼指令。如下圖:

    monitorenter和monitorexit指令規(guī)則:
    1. monitorenter在編譯后插入到同步代碼庫的開始位置。
    2. monitorexit插入在方法結(jié)束處和異常處。
    3. 一個monitorenter必須保證有對應(yīng)的monitorexit。
    4. 任何對象都有一個monitor以之關(guān)聯(lián),當一個monitor被持有后,該對象出于鎖定狀態(tài)。線程執(zhí)行到monitorenter指令時,將會嘗試獲取對象所對應(yīng)的monitor的所有權(quán),嘗試獲取對象的鎖。

    靜態(tài)方法和普通方法在編程成字節(jié)碼后會在方法的訪問標識字段中標識為同步方法。

    方法同步的細節(jié)在JVM規(guī)范里并沒有詳細說明。但是,方法的同步同樣可以使用這兩個指令來實現(xiàn)。

    需要提前了解知識點:java內(nèi)存模型

    內(nèi)存可見性

    synchronized關(guān)鍵字強制實施一個互斥鎖,使得被保護的代碼塊在同一時間只能有一個線程進入并執(zhí)行。當然synchronized還有另外一個 方面的作用:在線程進入synchronized塊之前,會把工作存內(nèi)存中的所有內(nèi)容映射到主內(nèi)存上,然后把工作內(nèi)存清空再從主存儲器上拷貝最新的值。而 在線程退出synchronized塊時,同樣會把工作內(nèi)存中的值映射到主內(nèi)存,但此時并不會清空工作內(nèi)存。這樣一來就可以強制其按照上面的順序運行,以 保證線程在執(zhí)行完代碼塊后,工作內(nèi)存中的值和主內(nèi)存中的值是一致的,保證了數(shù)據(jù)的一致性!
    所以由synchronized修飾的set與get方法都是相當于直接對主內(nèi)存進行操作,不會出現(xiàn)數(shù)據(jù)一致性方面的問題。

    指令重排序

    指令重排序是JVM為了優(yōu)化指令,提高程序運行效率,在不影響單線程程序執(zhí)行結(jié)果的前提下,盡可能地提高并行度。
    synchronized塊對應(yīng)java程序來說是原子操作,所以說內(nèi)部不管怎么重排序都不會影響其它線程執(zhí)行導致數(shù)據(jù)錯誤。執(zhí)行的指令也不會溢出方法。

    happens-before

    監(jiān)視器鎖規(guī)則:對一個監(jiān)視器鎖的解鎖,happens- before 于隨后對這個監(jiān)視器鎖的加鎖。

    鎖優(yōu)化

    在多線程并發(fā)編程中synchronized一直是元老級角色,很多人都會稱呼它為重量級鎖。在Java1.5中,synchronize是性能低效的。因為這是一個重量級操作,需要調(diào)用操作接口,導致有可能加鎖消耗的系統(tǒng)時間比加鎖以外的操作還多。相比之下使用Java提供的Lock對象,性能更高一些。但是到了Java1.6,發(fā)生了變化。synchronize在語義上很清晰,可以進行很多優(yōu)化,有適應(yīng)自旋,鎖消除,鎖粗化,輕量級鎖,偏向鎖等等。導致在Java1.6上synchronize的性能并不比Lock差。官方也表示,他們也更支持synchronize,在未來的版本中還有優(yōu)化余地。

    偏向鎖

    簡單的理解,偏向于這個線程。 當一個線程進入同步塊,首先測試對象的mark word 中的threadId是否等同當前線程ID,如果成功,則獲取鎖成功,否則。首先測試mark word中的鎖標識是否為1 。如果沒有設(shè)置。則升級為輕量級鎖。否則 通過CAS操作,將自己的線程ID 嘗試放入 的mark word 的位置。如果成功則獲取鎖成功。否則,說明對象存在競爭。將會在適當?shù)牡胤綊炱皤@取鎖的線程。然后升級鎖。接著執(zhí)行代碼。
    偏向鎖默認為開啟狀態(tài)。只是會在應(yīng)用啟動后延遲啟動通過參數(shù)可以設(shè)置不延時XX:BiasedLockingStartupDelay=0。如果你確定應(yīng)用程序里所有的鎖通常情況下處于競爭狀態(tài),可以通過JVM參數(shù)關(guān)閉偏向鎖:-XX:-UseBiasedLocking=false,那么程序默認會進入輕量級鎖狀態(tài)。

    輕量級鎖

    JVM通過CAS修改對象頭來獲取鎖,如果CAS修改成功則獲取鎖,如果獲取失敗,則說明有競爭,則通過CAS自旋一段時間來修改對象頭,如果還是獲取失敗,則升級為重量級鎖。如果沒有競爭,輕量級鎖使用CAS操作避免了使用互斥量的開銷,但如果存在鎖競爭,除了互斥量的開銷外,還額外發(fā)生了CAS操作,因此在有競爭的情況下,輕量級鎖會比傳統(tǒng)的重量級鎖更慢。

    重量級鎖

    重量級鎖通過對象內(nèi)部的監(jiān)視器(monitor)實現(xiàn),其中monitor的本質(zhì)是依賴于底層操作系統(tǒng)的Mutex Lock實現(xiàn),操作系統(tǒng)實現(xiàn)線程之間的切換需要從用戶態(tài)到內(nèi)核態(tài)的切換,切換成本非常高。

    鎖消除:

    鎖消除是指虛擬機在即時編譯器在運行時,對于一些在代碼上要求同步,但是被檢測到不可能存在數(shù)據(jù)競爭的鎖進行消除。比如,一個鎖不可能被多個線程訪問到,那么在這個鎖上的同步塊JVM將把鎖消除掉。

    鎖粗化

    程序中一系列的連續(xù)操作都對同一個對象反復加鎖和解鎖,甚至加鎖操作是出現(xiàn)在循環(huán)體中的,那即使沒有線程競爭,頻繁地進行互斥同步操作也會導致不必要的性能損耗。

    for(int i=0; i<1000; i++){synchronized(this){...} }

    上面代碼JVM將會優(yōu)化成如下:

    synchronized(this){for(int i=0; i<1000; i++){...} }

    本人簡書blog地址:http://www.jianshu.com/u/1f0067e24ff8????
    點擊這里快速進入簡書

    總結(jié)

    以上是生活随笔為你收集整理的深入理解 Synchronized的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。