<nav id="luije"><kbd id="luije"></kbd></nav>
<center id="luije"><form id="luije"></form></center><tt id="luije"><form id="luije"></form></tt>
<output id="luije"><xmp id="luije"></xmp></output>
  • <form id="luije"><acronym id="luije"></acronym></form>
  • <output id="luije"><font id="luije"><rp id="luije"></rp></font></output>
    <sub id="luije"><form id="luije"></form></sub>
  • <sub id="luije"></sub>
    <li id="luije"></li>
  • <acronym id="luije"><noframes id="luije"><sub id="luije"></sub></noframes></acronym>
  • <rp id="luije"><output id="luije"></output></rp>
    <rp id="luije"></rp>
  • <var id="luije"></var>
  • <acronym id="luije"><nav id="luije"></nav></acronym>
  • <li id="luije"><strike id="luije"><font id="luije"></font></strike></li>
    <form id="luije"></form>
  • <output id="luije"><table id="luije"><input id="luije"></input></table></output>
  • <var id="luije"><table id="luije"></table></var>
    溫馨提示×

    溫馨提示×

    您好,登錄后才能下訂單哦!

    密碼登錄×
    登錄注冊×
    其他方式登錄
    點擊 登錄注冊 即表示同意《億速云用戶服務條款》

    Java的Synchronized鎖原理和優化的方法

    發布時間:2023-11-30 11:39:36 來源:億速云 閱讀:76 作者:栢白 欄目:開發技術

    本篇文章和大家了解一下Java的Synchronized鎖原理和優化的方法。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有所幫助。


    一、synchronized介紹

    synchronized中文意思是同步,也稱之為”同步鎖“。

    synchronized的作用是保證在同一時刻, 被修飾的代碼塊或方法只會有一個線程執行,以達到保證并發安全的效果。

    synchronized是Java中解決并發問題的一種最常用的方法,也是最簡單的一種方法。

    在JDK1.5之前synchronized是一個重量級鎖,相對于j.u.c.Lock,它會顯得那么笨重,隨著Javs SE 1.6對synchronized進行的各種優化后,synchronized并不會顯得那么重了。

    synchronized的作用主要有三個:

    • 原子性: 確保線程互斥地訪問同步代碼;

    • 可見性: 保證共享變量的修改能夠及時可見,其實是通過Java內存模型中的 “ 對一個變量unlock操作之前,必須要同步到主內存中;如果對一個變量進行lock操作,則將會清空工作內存中此變量的值,在執行引擎使用此變量前,需要重新從主內存中load操作或assign操作初始化變量值 ” 來保證的;

    • 有序性: 有效解決重排序問題,即 “一個unlock操作先行發生(happen-before)于后面對同一個鎖的lock操作”;

    二、synchronized的使用

    synchronized的3種使用方式:

    • 修飾實例方法: 作用于當前實例加鎖

    • 修飾靜態方法: 作用于當前類對象加鎖

    • 修飾代碼塊: 指定加鎖對象,對給定對象加鎖

    1.修飾方法

    Synchronized修飾一個方法很簡單,就是在方法的前面加synchronized,synchronized修飾方法和修飾一個代碼塊類似,只是作用范圍不一樣,修飾代碼塊是大括號括起來的范圍,而修飾方法范圍是整個函數。

    • 方法一:修飾的是一個方法

    public synchronized void method()
    {
       // todo
    }
    • 方法二:修飾的是一個代碼塊

    public void method()
    {
       synchronized(this) {
          // todo
       }
    }

    方法一與方法二是等價的,都是鎖定了整個方法時的內容。

    synchronized關鍵字不能繼承。雖然可以使用synchronized來定義方法,但synchronized并不屬于方法定義的一部分,因此,synchronized關鍵字不能被繼承。

    • 在子類方法中加上synchronized關鍵字

    class Parent {
       public synchronized void method() { }
    }
    class Child extends Parent {
       public synchronized void method() { }
    }
    • 在子類方法中調用父類的同步方法

    class Parent {
       public synchronized void method() {   }
    }
    class Child extends Parent {
       public void method() { super.method();   }
    }

    注意:

    • 在定義接口方法時不能使用synchronized關鍵字。

    • 構造方法不能使用synchronized關鍵字,但可以使用synchronized代碼塊來進行同步。

    當有一個明確的對象作為鎖時,就可以用類似下面這樣的方式寫程序:

    public void method3(SomeObject obj)
    {
       //obj 鎖定的對象
       synchronized(obj)
       {
          // todo
       }
    }

    當沒有明確的對象作為鎖,只是想讓一段代碼同步時,可以創建一個特殊的對象來充當鎖:

    class Test implements Runnable
    {
       private byte[] lock = new byte[0];  // 特殊的instance變量
       public void method()
       {
          synchronized(lock) {
             // todo 同步代碼塊
          }
       }
       public void run() {
       }
    }
    • 2.修飾一個靜態方法

    synchronized也可修飾一個靜態方法,用法如下:

    public synchronized static void method() {
       // todo
    }
    • 3.修飾一個類

    Synchronized還可作用于一個類,用法如下:

    class ClassName {
       public void method() {
          synchronized(ClassName.class) {
             // todo
          }
       }
    }

    使用總結

    • 無論synchronized關鍵字加在方法上還是對象上,如果它作用的對象是非靜態的,則它取得的鎖是對象;如果synchronized作用的對象是一個靜態方法或一個類,則它取得的鎖是對類,該類所有的對象同一把鎖。

    • 每個對象只有一個鎖(lock)與之相關聯,誰拿到這個鎖誰就可以運行它所控制的那段代碼。

    • 實現同步是要很大的系統開銷作為代價的,甚至可能造成死鎖,所以盡量避免無謂的同步控制。

    三、synchronized的底層實現

    synchronized的底層實現,就不得不談數據在JVM內存的存儲:Java對象頭,以及Monitor對象監視器。

    對象頭

    在JVM中,對象在內存中的布局分為三塊區域:對象頭、實例數據和對齊填充。如下圖所示:

    Java的Synchronized鎖原理和優化的方法

    • 實例數據: 存放類的屬性數據信息,包括父類的屬性信息;

    • 對齊填充: 由于虛擬機要求 對象起始地址必須是8字節的整數倍。填充數據不是必須存在的,僅僅是為了字節對齊;

    • 對象頭: Java對象頭一般占有2個機器碼(在32位虛擬機中,1個機器碼等于4字節,也就是32bit,在64位虛擬機中,1個機器碼是8個字節,也就是64bit),但是如果對象是數組類型,則需要3個機器碼,因為JVM虛擬機可以通過Java對象的元數據信息確定Java對象的大小,但是無法從數組的元數據來確認數組的大小,所以用一塊來記錄數組長度。

    synchronized用的鎖就是存在Java對象頭里的,那么什么是Java對象頭呢?Hotspot虛擬機的對象頭主要包括兩部分數據:Mark Word(標記字段)、Class Pointer(類型指針)。

    其中 Class Pointer是對象指向它的類元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例,Mark Word用于存儲對象自身的運行時數據,它是實現輕量級鎖和偏向鎖的關鍵。

    監視器(Monitor)

    任何一個對象都有一個Monitor與之關聯,當且一個Monitor被持有后,它將處于鎖定狀態。

    synchronized在JVM里的實現都是 基于進入和退出Monitor對象來實現方法同步和代碼塊同步,雖然具體實現細節不一樣,但是都可以通過成對的MonitorEnterMonitorExit指令來實現。

    • MonitorEnter指令: 插入在同步代碼塊的開始位置,當代碼執行到該指令時,將會嘗試獲取該對象Monitor的所有權,即嘗試獲得該對象的鎖;

    • MonitorExit指令: 插入在方法結束處和異常處,JVM保證每個MonitorEnter必須有對應的MonitorExit;

    那什么是Monitor?可以把它理解為 一個同步工具,也可以描述為 一種同步機制,它通常被描述為一個對象。

    與一切皆對象一樣,所有的Java對象是天生的Monitor,每一個Java對象都有成為Monitor的潛質,因為在Java的設計中 ,每一個Java對象自打娘胎里出來就帶了一把看不見的鎖,它叫做內部鎖或者Monitor鎖。

    也就是通常說Synchronized的對象鎖,MarkWord鎖標識位為10,其中指針指向的是Monitor對象的起始地址。在Java虛擬機(HotSpot)中,Monitor是由ObjectMonitor實現的。

    四、synchronized 鎖的升級順序

    鎖解決了數據的安全性,但是同樣帶來了性能的下降。hotspot 虛擬機的作者經過調查發現,大部分情況下,加鎖的代碼不僅僅不存在多線程競爭,而且總是由同一個線程多次獲得。所以基于這樣一個概率。

    synchronized 在JDK1.6 之后做了一些優化,為了減少獲得鎖和釋放鎖來的性能開銷,引入了偏向鎖、輕量級鎖、自旋鎖、重量級鎖,鎖的狀態根據競爭激烈的程度從低到高不斷升級。

    鎖主要存在四種狀態,依次是:無鎖狀態、偏向鎖狀態、輕量級鎖狀態、重量級鎖狀態,鎖可以從偏向鎖升級到輕量級鎖,再升級的重量級鎖。但是鎖的升級是單向的,也就是說只能從低到高升級,不會出現鎖的降級。而且這個過程就是開銷逐漸加大的過程。

    Java的Synchronized鎖原理和優化的方法

    以上就是Java的Synchronized鎖原理和優化的方法的簡略介紹,當然詳細使用上面的不同還得要大家自己使用過才領會。如果想了解更多,歡迎關注億速云行業資訊頻道哦!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    自拍偷自拍亚洲精品牛影院_99久热re在线精品99re8_国国产a国产片免费_成人午夜精品无码区
    <nav id="luije"><kbd id="luije"></kbd></nav>
    <center id="luije"><form id="luije"></form></center><tt id="luije"><form id="luije"></form></tt>
    <output id="luije"><xmp id="luije"></xmp></output>
  • <form id="luije"><acronym id="luije"></acronym></form>
  • <output id="luije"><font id="luije"><rp id="luije"></rp></font></output>
    <sub id="luije"><form id="luije"></form></sub>
  • <sub id="luije"></sub>
    <li id="luije"></li>
  • <acronym id="luije"><noframes id="luije"><sub id="luije"></sub></noframes></acronym>
  • <rp id="luije"><output id="luije"></output></rp>
    <rp id="luije"></rp>
  • <var id="luije"></var>
  • <acronym id="luije"><nav id="luije"></nav></acronym>
  • <li id="luije"><strike id="luije"><font id="luije"></font></strike></li>
    <form id="luije"></form>
  • <output id="luije"><table id="luije"><input id="luije"></input></table></output>
  • <var id="luije"><table id="luije"></table></var>