如何掌握Synchronized關(guān)鍵字

這篇文章主要講解了“如何掌握Synchronized關(guān)鍵字”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“如何掌握Synchronized關(guān)鍵字”吧!

湞江網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),湞江網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為湞江上千多家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站制作要多少錢,請找那個(gè)售后服務(wù)好的湞江做網(wǎng)站的公司定做!

一、synchronized的用法

1.1、三種使用方式

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 靜態(tài)方法

  3. 非靜態(tài)方法

  4. 代碼塊

代碼示例:

public class Test {     //對象     Object object=new Object();     //共享變量     private static int num;     //靜態(tài)方法     public synchronized static void lock1(){         num ++;     }     //普通方法     public synchronized  void lock2(){         num ++;     }      public void lock3(){         //代碼塊         synchronized (object){             num ++;         }     } }

1.2、作用范圍

面試時(shí)經(jīng)常會(huì)問:synchronized 關(guān)鍵字鎖的是什么?或者說它的作用范圍是什么?

總結(jié)一下:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 非靜態(tài)方法鎖的是當(dāng)前對象 (就是 this)

  3. 靜態(tài)方法鎖的是類對象 Test.class

  4. 代碼塊鎖的是自定義的 Object 對象

1.3、原子性、可見性、有序性

我們都知道并發(fā)編程需要考慮三個(gè)問題:原子性、可見性、有序性。

那么,使用 synchronized 關(guān)鍵字是如何解決這三個(gè)問題的?

  • 原子性:synchronized 關(guān)鍵字能保證只有一個(gè)線程能拿到鎖,能夠進(jìn)入同步代碼塊,不會(huì)出現(xiàn)原子性問題

  • 可見性:執(zhí)行 synchronized 時(shí),對應(yīng) lock 原子操作將會(huì)清空工作內(nèi)存中此變量的值,并重新 read  來刷新內(nèi)存,不會(huì)出現(xiàn)可見性的問題

  • 有序性:執(zhí)行 synchronized  時(shí),依然可能發(fā)生重排序,只不過,我們有同步代碼塊,可以保證只有一個(gè)線程執(zhí)行同步代碼中的代碼,不會(huì)出現(xiàn)有序性問題

二、對象內(nèi)存布局

上面說了,這三種方式都是鎖的是對象、對象、對象(說三遍),但是聽起來好像很抽象的樣子,對象還能被鎖?該如何操作?

其實(shí)是和對象內(nèi)存布局有關(guān)系。

耳聽為虛,眼見為實(shí),下面讓你親眼看到對象是由啥組成的。

示例代碼:

//1、需要導(dǎo)入包 import org.openjdk.jol.info.ClassLayout; //2、定義Lock類 public class Lock {     int i;     boolean flag; } //3、將Lock對象打印出來 public class Test {     public static void main(String[] args){         Lock lock = new Lock();         System.out.println(ClassLayout.parseInstance(lock).toPrintable());     } }

打印出來的結(jié)果是這樣的:

 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE       0     4           (object header)                           01 47 70 9d (00000001 01000111 01110000 10011101) (-1653586175)       4     4           (object header)                           11 00 00 00 (00010001 00000000 00000000 00000000) (17)       8     4           (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)      12     4           int L.i                                   0      16     1           boolean L.flag                            false      17     7           (loss due to the next object alignment) Instance size: 24 bytes Space losses: 0 bytes internal + 7 bytes external = 7 bytes total

對打印結(jié)果,詳細(xì)解釋一下:

2.1、對象頭(Object Header)

Object Header 是 MarkWord 和 Class Pointer 組成的,后面會(huì)詳細(xì)解釋。

打印結(jié)果:占用 4+4+4=12 個(gè) bytes。

2.2、實(shí)例數(shù)據(jù)(Interface Data)

對象實(shí)例數(shù)據(jù)包括了對象的所有成員變量,其大小由各個(gè)成員變量大小決定的。

當(dāng)然,不包括靜態(tài)成員變量,因?yàn)樗窃诜椒▍^(qū)維護(hù)的!

打印結(jié)果:可以看到 int L.i 和 boolean L.flag 就是實(shí)例數(shù)據(jù),占用 4+1=5 個(gè) bytes。

2.3、填充數(shù)據(jù)(Padding)

Java 對象占用空間是 8 字節(jié)對齊的,即所有 Java 對象占用 bytes 數(shù)必須是 8  的倍數(shù),因?yàn)楫?dāng)我們從磁盤中取一個(gè)數(shù)據(jù)時(shí),不會(huì)是一個(gè)字節(jié)的去讀,都是按照一整塊來讀取的,這一塊大小就是 8 個(gè)字節(jié),所以為了完整,padding  的作用就是補(bǔ)充字節(jié),保證對象是 8 字節(jié)的整數(shù)倍。

打印結(jié)果:可以看到(loss due to the next object alignment) 這個(gè)就是填充數(shù)據(jù),占用 7個(gè)字節(jié)。

這樣的話,12+5+7=24 一共是 24 個(gè) bytes,正好是 8 的倍數(shù)。

所以說,一個(gè)對象的內(nèi)存布局是由對象頭、實(shí)例數(shù)據(jù)、填充數(shù)據(jù)組成的。

接下來:重點(diǎn)關(guān)注這個(gè)對象頭。

三、細(xì)說對象頭

上面提到了對象頭,直接看官網(wǎng)上的解釋,官網(wǎng)地址在文末:

3.1、對象頭(object header)

  • object header:Common structure at the beginning of every GC-managed heap  object. (Every oop points to an object header.) Includes fundamental information  about the heap object's layout, type, GC state, synchronization state, and  identity hash code. Consists of two words. In arrays it is immediately followed  by a length field. Note that both Java objects and VM-internal objects have a  common object header format.

  • 翻譯:在每個(gè) gc 管理的堆對象開始處的公共結(jié)構(gòu)。(每個(gè) oop 都指向一個(gè)對象頭)包括關(guān)于堆對象的布局、類型、GC  狀態(tài)、同步狀態(tài)和標(biāo)識(shí)哈希碼的基本信息。由兩個(gè)詞組成。在數(shù)組中,緊隨其后的是長度字段。注意,Java 對象和 vm 內(nèi)部對象都有一個(gè)通用的對象頭格式。

3.2、Klass Point

  • The second word of every object header. Points to another object (a  metaobject) which describes the layout and behavior of the original object. For  Java objects, the "klass" contains a C++ style "vtable".

  • 翻譯:每個(gè)對象頭的第二個(gè)字。指向另一個(gè)對象(元對象),該對象描述原始對象的布局和行為。對于 Java 對象,“klass”包含一個(gè)  c++風(fēng)格的“虛函數(shù)表”。

3.3、Mark Word

  • The first word of every object header. Usually a set of bitfields including  synchronization state and identity hash code. May also be a pointer (with  characteristic low bit encoding) to synchronization related information. During  GC, may contain GC state bits.

  • 翻譯:每個(gè)對象頭的第一個(gè)字。通常是一組位域,包括同步狀態(tài)和身份哈希碼。也可能是同步相關(guān)信息的指針(具有低比特編碼特征)。在 GC 期間,可能包含 GC  狀態(tài)位。

總結(jié)一下:其實(shí)對象頭就是 MarkWord 和 Klass Point 組成的。MarkWord 是用來存儲(chǔ)對象的 hashCode、鎖信息或分代年齡或  GC 標(biāo)志等信息。Klass Point 是對象指向它的類元數(shù)據(jù)的指針,虛擬機(jī)通過這個(gè)指針來確定這個(gè)對象是哪個(gè)類的實(shí)例。

那么問題來了!!

問題:那上面說的 MarkWord 是存儲(chǔ)的 hashcode、鎖信息或分代年齡或 GC 標(biāo)志是在那定義的呢?

你可以下載 OpenJDK 的源碼,在 markOop.hpp 的文件中可以看到 Mark Word 的狀態(tài)信息:

如何掌握Synchronized關(guān)鍵字

markOop.hpp

可以看到還是寫的非常清晰的,畫圖總結(jié)一下:

如何掌握Synchronized關(guān)鍵字

Mark Word空間

四、synchronized 深入分析

把 Test.java 編譯為 Test.class ,并在對應(yīng)目錄下執(zhí)行javap -v Test.class  這個(gè)命令,你能看到對應(yīng)的字節(jié)碼,如下:

如何掌握Synchronized關(guān)鍵字

字節(jié)碼

上圖可以看到 JVM 對于同步方法和同步代碼塊的處理方式是不同的。

對于同步代碼塊:采用 monitorenter 和 monitorexit 兩個(gè)指令來實(shí)現(xiàn)同步。

如何掌握Synchronized關(guān)鍵字

monitorenter 指令可以理解為加鎖,monitorexit 可以理解為釋放鎖。

進(jìn)入 monitorenter 指令后,線程將持有 Monitor 對象,退出 monitorenter 指令后,線程將釋放該 Monitor  對象。

對于方法:出現(xiàn)了ACC_SYNCHRONIZED 標(biāo)識(shí)。

當(dāng)出現(xiàn)了 ACC_SYNCHRONIZED 標(biāo)識(shí)符的時(shí)候,Jvm 會(huì)隱式調(diào)用 monitorenter 和 monitorexit。在執(zhí)行同步方法前會(huì)調(diào)用  monitorenter,在執(zhí)行完同步方法后會(huì)調(diào)用 monitorexit,釋放 Monitor 對象。

你可以發(fā)現(xiàn),不管是同步代碼塊還是同步方法,都和 Monitor 對象有關(guān)系。

那么問題又來了!!

問題:這個(gè) Monitor 對象是啥呢?monitorenter 和 monitorexit 又是什么呢?

4.1、monitorenter

直接看 JVM 規(guī)范里對它的描述,地址在文末:

  • Each object is associated with a monitor. A monitor is locked if and only if  it has an owner. The thread that executes monitorenter attempts to gain  ownership of the monitor associated with objectref, as follows:

  • If the entry count of the monitor associated with objectref is zero, the  thread enters the monitor and sets its entry count to one. The thread is then  the owner of the monitor.

  • If the thread already owns the monitor associated with objectref, it reenters  the monitor, incrementing its entry count.

  • If another thread already owns the monitor associated with objectref, the  thread blocks until the monitor's entry count is zero, then tries again to gain  ownership.

  • 翻譯:每一個(gè)對象都會(huì)和一個(gè)監(jiān)視器 Monitor 關(guān)聯(lián)。監(jiān)視器被占用時(shí)會(huì)被鎖住,其他線程無法來獲取該 Monitor。當(dāng) JVM  執(zhí)行某個(gè)線程的某個(gè)方法內(nèi)部的 onitorenter 時(shí),它會(huì)嘗試去獲取當(dāng)前對象對應(yīng)的 Monitor 的所有權(quán)。

執(zhí)行過程如下:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 若 Monior 的進(jìn)入數(shù)為 0,線程可以進(jìn)入 Monitor,并將 monitor 的進(jìn)入數(shù)置為 1。當(dāng)前線程成為 Monitor 的 owner  擁有者。

  3. 若線程已擁有 Monitor 的所有權(quán),允許它重入 Monitor,則進(jìn)入 Monitor 的進(jìn)入數(shù)加 1。

  4. 若其他線程已經(jīng)占有 Monitor 的所有權(quán),那么當(dāng)前嘗試獲取 Monitor 的所有權(quán)的線程會(huì)被阻塞,直到 Monitor 的進(jìn)入數(shù)變?yōu)? 0,才能重新嘗試獲取 Monitor 的所有權(quán)。

4.2、monitorexit

看 JVM 規(guī)范里對它的描述,地址在文末:

  • The thread that executes monitorexit must be the owner of the monitor  associated with the instance referenced by objectref.

  • The thread decrements the entry count of the monitor associated with  objectref. If as a result the value of the entry count is zero, the thread exits  the monitor and is no longer its owner. Other threads that are blocking to enter  the monitor are allowed to attempt to do so.

執(zhí)行過程如下:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 能執(zhí)行 monitorexit 指令的線程一定是擁有當(dāng)前對象的 Monitor 的所有權(quán)的線程。

  3. 執(zhí)行 monitorexit 時(shí)會(huì)將 Monitor 的進(jìn)入數(shù)減 1。當(dāng) Monitor 的進(jìn)入數(shù)減為 0 時(shí),當(dāng)前線程退出 Monitor,不再擁有  Monitor 的所有權(quán),此時(shí)其他被這個(gè) Monitor 阻塞的線程可以嘗試去獲取這個(gè) Monitor 的所有權(quán)。

4.3、Monitor 監(jiān)視器

每個(gè)對象都會(huì)關(guān)聯(lián)一個(gè) Monitor 對象,也叫做監(jiān)視器。

在 HotSpot 虛擬機(jī)中,Monitor 是由 ObjectMonitor 實(shí)現(xiàn)的。其源碼是用 c++來實(shí)現(xiàn)的,位于 HotSpot 虛擬機(jī)源碼  ObjectMonitor.hpp 文件中(路徑:src/share/vm/runtime/objectMonitor.hpp)

ObjectMonitor 主要數(shù)據(jù)結(jié)構(gòu)如下:

ObjectMonitor() {     _header       = NULL;     _count        = 0;     _waiters      = 0,     _recursions   = 0;     //線程的重入次數(shù)     _object       = NULL;  //存儲(chǔ)該monitor對象     _owner        = NULL;  //標(biāo)識(shí)擁有該monitor的線程     _WaitSet      = NULL;  //處于wait狀態(tài)的線程會(huì)被加入到_WaitSet     _WaitSetLock  = 0 ;     _Responsible  = NULL ;     _succ         = NULL ;     _cxq          = NULL ; //多線程競爭鎖時(shí)的單向列表     FreeNext      = NULL ;     _EntryList    = NULL ; //等待獲取鎖的線程,會(huì)放到這里     _SpinFreq     = 0 ;     _SpinClock    = 0 ;     OwnerIsThread = 0 ;   }

看到這里,我相信你就能明白為啥之前要解釋對象內(nèi)存布局、對象頭,因?yàn)檫@三者之間是有對應(yīng)關(guān)系的。

畫圖總結(jié)一下:

如何掌握Synchronized關(guān)鍵字

可以看到 ObjectMonitor 的數(shù)據(jù)結(jié)構(gòu)中包含:_owner、_WaitSet 和_EntryList。

它們之間的關(guān)系轉(zhuǎn)換如下:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 當(dāng)多個(gè)線程同時(shí)訪問同一段代碼塊或者某個(gè)同步方法的時(shí)候,這些線程會(huì)首先被放進(jìn)_EntryList 隊(duì)列中,處于 blocked  狀態(tài)的線程,都會(huì)放入該隊(duì)列中。

  3. 當(dāng)某個(gè)線程獲取到對象的 Monitor 時(shí),此時(shí)就就可以進(jìn)入 running 狀態(tài),執(zhí)行代碼邏輯,此時(shí),ObjectMonitor 對象的_owner  指向當(dāng)前線程,_count 加 1 表示當(dāng)前對象鎖被一個(gè)線程獲取。而沒有獲取到鎖的線程,會(huì)再次進(jìn)入_EntryList 被掛起。

  4. 當(dāng) running 狀態(tài)的線程調(diào)用 wait()方法,當(dāng)前線程就會(huì)釋放 Monitor 對象,進(jìn)入 waiting 狀態(tài),ObjectMonitor  對象的_owner 變?yōu)?null,_count 減 1,同時(shí)線程進(jìn)入_WaitSet 隊(duì)列,直到有線程調(diào)用  notify()方法喚醒該線程,則該線程再次進(jìn)入_EntryList 隊(duì)列,直到再次競爭到鎖再進(jìn)入_owner 區(qū)。

  5. 如果當(dāng)前線程執(zhí)行完畢,那么也釋放 monitor 對象,ObjectMonitor 對象的_owner 變?yōu)?null,_count 減 1。

這個(gè)過程大致就是在 JDK6 之前實(shí)現(xiàn)的原理。

但是,JDK6 之前,synchronized關(guān)鍵字的效率是非常低的。

原因如下:

Monitor 對象是依靠底層操作系統(tǒng)的 Mutex Lock 來實(shí)現(xiàn)互斥的,線程申請 Mutex 成功,則持有該 Mutex,其它線程將無法獲取到該  Mutex。

既然 Mutex Lock  涉及到底層操作系統(tǒng),那這個(gè)時(shí)候就存在操作系統(tǒng)用戶態(tài)和核心態(tài)的轉(zhuǎn)換,這種切換會(huì)消耗大量的系統(tǒng)資源,因?yàn)橛脩魬B(tài)與內(nèi)核態(tài)都有各自專用的內(nèi)存空間,專用的寄存器等,用戶態(tài)切換至內(nèi)核態(tài)需要傳遞給許多變量、參數(shù)給內(nèi)核,內(nèi)核也需要保護(hù)好用戶態(tài)在切換時(shí)的一些寄存器值、變量等。

所以,在JDK 6 之后,從Jvm層面進(jìn)行了優(yōu)化,分為了偏向鎖,輕量級(jí)鎖,自旋鎖,重量級(jí)鎖。

五、鎖升級(jí)

下面就依此來說鎖是如何一步步升級(jí)的。

5.1、偏向鎖

1、什么是偏向鎖?

HotSpot作者經(jīng)過研究實(shí)踐發(fā)現(xiàn),在大多數(shù)情況下,鎖不僅不存在多線程競爭,而且總是由同一線程多次獲得,為了讓線程獲得鎖的代價(jià)更低,引進(jìn)了偏向鎖。

偏向鎖的“偏”,就是偏心的“偏”,它的意思是這個(gè)鎖會(huì)偏向于第一個(gè)獲得它的線程,會(huì)在對象頭存儲(chǔ)鎖偏向的線程ID,以后該線程進(jìn)入和退出同步塊時(shí)只需要檢查是否為偏向鎖、鎖標(biāo)志位以及ThreadID即可。

如何掌握Synchronized關(guān)鍵字

偏向鎖Mark Word

不過一旦出現(xiàn)多個(gè)線程競爭時(shí)必須撤銷偏向鎖,所以撤銷偏向鎖消耗的性能必須小于之前節(jié)省下來的CAS原子操作的性能消耗,不然就得不償失了。

2、偏向鎖原理

無鎖到偏向鎖的轉(zhuǎn)換流程圖:

如何掌握Synchronized關(guān)鍵字

偏向鎖流程圖

參數(shù):-XX:+UseBiasedLocking 開啟偏向鎖

簡單來說:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 線程訪問同步代碼塊,使用 CAS 操作將 Thread ID 放到 MarkWord 當(dāng)中

  3. 如果線程 CAS 成功,此時(shí)線程就會(huì)獲取到偏向鎖

  4. 如果線程 CAS 失敗,證明已經(jīng)有別的線程持有鎖,這個(gè)時(shí)候啟動(dòng)偏向鎖撤銷,執(zhí)行下面的操作

3、偏向鎖的撤銷

流程如下:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 偏向鎖的撤銷動(dòng)作必須等待全局安全點(diǎn)

  3. 暫停原持有偏向鎖的線程

  4. 將 Thread ID置為null,使其變成無鎖狀態(tài)

  5. 恢復(fù)原持有偏向鎖線程,開始進(jìn)行輕量級(jí)加鎖流程

5.2 輕量級(jí)鎖

1、什么是輕量級(jí)鎖?

輕量級(jí)鎖是JDK  6之中加入的鎖機(jī)制,它名字中的“輕量級(jí)”是相對于使用monitor的傳統(tǒng)鎖而言的,因此傳統(tǒng)的鎖機(jī)制就稱為“重量級(jí)”鎖。需要強(qiáng)調(diào)一點(diǎn)的是,輕量級(jí)鎖并不是用來代替重量級(jí)鎖的。

引入輕量級(jí)鎖的目的:在多線程交替執(zhí)行同步塊的情況下,盡量避免重量級(jí)鎖引起的性能消耗,但是如果多個(gè)線程在同一時(shí)刻進(jìn)入臨界區(qū),會(huì)導(dǎo)致輕量級(jí)鎖膨脹升級(jí)重量級(jí)鎖,所以輕量級(jí)鎖的出現(xiàn)并非是要替代重量級(jí)鎖。

2、輕量級(jí)鎖原理

當(dāng)關(guān)閉偏向鎖功能或者多個(gè)線程競爭偏向鎖導(dǎo)致偏向鎖升級(jí)為輕量級(jí)鎖,則會(huì)嘗試獲取輕量級(jí)鎖。

流程圖如下:

 如何掌握Synchronized關(guān)鍵字

輕量級(jí)鎖升級(jí)過程

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 判斷當(dāng)前對象是否處于無鎖狀態(tài)(hashcode、0、01),如果是,則JVM首先將在當(dāng)前線程的棧幀中建立一個(gè)名為鎖記錄(Lock  Record)的空間,用于存儲(chǔ)鎖對象目前的 Mark Word 的拷貝(官方把這份拷貝加了一個(gè) Displaced 前綴,即Displaced Mark  Word),將對象的 Mark Word復(fù)制到棧幀中的 Lock Record 中,將 Lock Reocrd 中的 owner 指向當(dāng)前對象。

  3. JVM利用CAS操作嘗試將對象的 Mark Word 更新為指向 Lock Record 的指針,如果成功,表示競爭到鎖,則將鎖標(biāo)志位變成  00,執(zhí)行同步操作。

  4. 如果失敗,則判斷當(dāng)前對象的Mark  Word是否指向當(dāng)前線程的棧幀,如果是,則表示當(dāng)前線程已經(jīng)持有當(dāng)前對象的鎖,則直接執(zhí)行同步代碼塊;否則只能說明該鎖對象已經(jīng)被其他線程搶占了,這時(shí)輕量級(jí)鎖需要膨脹為重量級(jí)鎖,鎖標(biāo)志位變成10,后面等待的線程將會(huì)進(jìn)入阻塞狀態(tài)。

5.3 自旋鎖

1、為什么會(huì)有自旋鎖?

前面聊 monitor 實(shí)現(xiàn)鎖的時(shí)候,知道 monitor 會(huì)阻塞和喚醒線程,線程的阻塞和喚醒需要 CPU 從用戶態(tài)轉(zhuǎn)為核心態(tài),頻繁的阻塞和喚醒對 CPU  來說是一件負(fù)擔(dān)很重的工作,這些操作給系統(tǒng)的并發(fā)性能帶來了很大的壓力。

同時(shí),虛擬機(jī)的開發(fā)團(tuán)隊(duì)也注意到在許多應(yīng)用上,共享數(shù)據(jù)的鎖定狀態(tài)只會(huì)持續(xù)很短的一段時(shí)間,為了這段時(shí)間阻塞和喚醒線程并不值得。

如果物理機(jī)器有一個(gè)以上的處理器,能讓兩個(gè)或以上的線程同時(shí)并行執(zhí)行,我們就可以讓后面請求鎖的那個(gè)線程“稍等一下”,但不放棄處理器的執(zhí)行時(shí)間,看看持有鎖的線程是否很快就會(huì)釋放鎖。為了讓線程等待,我們只需讓線程執(zhí)行一個(gè)循環(huán)(自旋)  , 這就是所謂的自旋鎖。

2、自旋鎖的優(yōu)缺點(diǎn)

自旋等待不能代替阻塞,且先不說對處理器數(shù)量的要求,自旋等待本身雖然避免了線程切換的開銷,但它是要占用處理器時(shí)間的。

如果鎖被占用的時(shí)間很短,自旋等待的效果就會(huì)非常好,反之,如果鎖被占用的時(shí)間很長。那么自旋的線程只會(huì)白白消耗處理器資源,而不會(huì)做任何有用的工作,反而會(huì)帶來性能上的浪費(fèi)。

所以,自旋等待的時(shí)間必須要有一定的限度,如果在多線程交替執(zhí)行同步塊的情況下,可以避免重量級(jí)鎖引起的性能消耗。

自旋超過了限定的次數(shù)仍然沒有成功獲得鎖,就應(yīng)當(dāng)使用傳統(tǒng)的方式去掛起線程了。自旋次數(shù)的默認(rèn)值是10次,你可以使用參數(shù) -XX : PreBlockSpin  來更改。

5.4 適應(yīng)性自旋鎖

在JDK 6中引入了自適應(yīng)的自旋鎖。自適應(yīng)意味著自旋的時(shí)間不再固定了,而是由前一次在同一鎖上的自選時(shí)間及鎖的擁有者的狀態(tài)來決定。

如果在同一個(gè)對象鎖上,自旋等待剛剛成功獲得過鎖,并且持有鎖的線程正在運(yùn)行中,那虛擬機(jī)就會(huì)認(rèn)為這次自旋也很有可能再次成功,進(jìn)而它將允許自旋等待持續(xù)相對更長的時(shí)間,比如100次循環(huán)。

如果,對于某個(gè)鎖,自旋很少成功獲得過,那在以后要獲取這個(gè)鎖時(shí)可能會(huì)省略掉自旋過程,避免浪費(fèi)服務(wù)器處理資源。

有了自適應(yīng)自旋鎖,虛擬機(jī)對程序的狀況預(yù)測就會(huì)變得準(zhǔn)確,性能也會(huì)有所提升。

感謝各位的閱讀,以上就是“如何掌握Synchronized關(guān)鍵字”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對如何掌握Synchronized關(guān)鍵字這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

標(biāo)題名稱:如何掌握Synchronized關(guān)鍵字
文章源于:http://muchs.cn/article4/gdigie.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、品牌網(wǎng)站設(shè)計(jì)、小程序開發(fā)、營銷型網(wǎng)站建設(shè)、做網(wǎng)站、用戶體驗(yàn)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)