自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

聊聊Synchronized的優(yōu)化

系統(tǒng)
在早期版本中,synchronized是一種重量級鎖,其底層由Monitor實(shí)現(xiàn),而Monitor又依賴于操作系統(tǒng)的Mutex Lock。線程獲取到鎖后,需要切換狀態(tài),而操作系統(tǒng)在實(shí)現(xiàn)線程的切換時,需要從用戶態(tài)轉(zhuǎn)為核心態(tài),這是一個非常耗時,非常重的操作。

[[375798]]

 早期版本synchronized性能較低的原因

在早期版本中,synchronized是一種重量級鎖,其底層由Monitor實(shí)現(xiàn),而Monitor又依賴于操作系統(tǒng)的Mutex Lock。線程獲取到鎖后,需要切換狀態(tài),而操作系統(tǒng)在實(shí)現(xiàn)線程的切換時,需要從用戶態(tài)轉(zhuǎn)為核心態(tài),這是一個非常耗時,非常重的操作。因此在之前,synchronized是一種重量級鎖。

JDK1.6之后對synchronized的優(yōu)化

現(xiàn)在的synchronized已經(jīng)沒有之前那么笨重了,在虛擬機(jī)層面,對synchronized做了較大的優(yōu)化,引入了自旋鎖、適應(yīng)性自旋鎖、鎖消除、鎖粗化,可以減少鎖操作的開銷。

自旋鎖

有時候,獲取到鎖的線程執(zhí)行的操作耗時極短,為了這么點(diǎn)微不足道的時間,將接下來等待鎖的線程掛起非常的不值得。掛起線程的操作需要在核心態(tài)完成,從用戶態(tài)切換到核心態(tài),耗時比較嚴(yán)重。

因此現(xiàn)在增加這么一樣操作,讓等待鎖的線程執(zhí)行忙循環(huán)等待,不停地去嘗試獲取鎖,像一種自旋的操作,故稱之為自旋鎖。

如果之前線程占有鎖的時間極短,那么自旋鎖的性能將非常的好。但若是占有鎖的時間較長,那么自旋鎖將白白消耗CPU的資源,在自旋次數(shù)到了之后,將會被掛起。

在jdk1.4的時候,自旋鎖默認(rèn)關(guān)閉;jdk1.6之后,自旋鎖默認(rèn)開啟,默認(rèn)自旋10次,當(dāng)然也可以使用PreBlockSpin來修改自旋次數(shù)。

自旋鎖的痛點(diǎn)在于:無法在不同場景中,確定出一個可靠的自旋次數(shù)。因此,衍生出來適應(yīng)性自旋鎖。

適應(yīng)性自旋鎖

在適應(yīng)性自旋鎖中,自旋的次數(shù)不再固定,一般由之前自旋的次數(shù)和鎖持有者的狀態(tài)決定。

如果在一個鎖對象上,之前的線程都能通過自旋來獲取到鎖,并且沒有超過自旋次數(shù),那么虛擬機(jī)認(rèn)為,通過自旋獲取到鎖的概率很大,下一次會增加自旋的次數(shù)。相反的,如果之前很少有線程通過自旋獲取到鎖,那么虛擬機(jī)會減少自旋的次數(shù),減少到一定次數(shù)后,甚至?xí)苯臃艞壸孕?,升級為重量級鎖。

可以看出,適應(yīng)性自旋鎖十分機(jī)智。

鎖消除

從字面意思上可以看出,這是一種直接去除鎖的方法,簡單粗暴。

對于那些根本不可能存在鎖競爭卻又包含鎖的情況,虛擬機(jī)會直接消除這個鎖,避免無意義的鎖請求。比如我在純單線程中對某個方法或者變量加鎖,或者調(diào)用內(nèi)部實(shí)現(xiàn)有鎖的對象(Vector、StringBuffer與HashTable等),虛擬機(jī)會直接消除毫無意義的加鎖。

鎖粗化

在上一文中【多線程】淺說Synchronized,我們談到了synchronized的應(yīng)用-雙重檢驗(yàn)鎖的優(yōu)化過程,強(qiáng)調(diào)將加鎖的范圍盡量限制得小一些,直到存在鎖競爭的實(shí)際區(qū)域才加鎖,這樣程序運(yùn)行更加高效。

但是,如果存在這樣的一種情況:反復(fù)的對同一個對象執(zhí)行加鎖解鎖的操作,也會導(dǎo)致CPU資源的過度消耗。

鎖粗化,就是將反復(fù)的加鎖操作粗化成一個范圍更大的鎖,這樣加鎖只有一次。

例如,在循環(huán)內(nèi)部,調(diào)用StringBuffer的append操作(關(guān)于StringBuffer,可以參考我的另外一篇文章【JAVA】String、StringBuilder、StringBuffer三者的區(qū)別),每次append都需要加鎖,虛擬機(jī)檢測到這種情況后,首先會對append脫鎖,然后進(jìn)行鎖粗化,將鎖的范圍擴(kuò)大到循環(huán)外部。

鎖的狀態(tài)

鎖的狀態(tài)有以下幾種:

  1. 無鎖狀態(tài)
  2. 偏向鎖狀態(tài)
  3. 輕量級鎖狀態(tài)
  4. 重量級鎖狀態(tài)

其中,無鎖狀態(tài)對應(yīng)于鎖消除,Monitor對應(yīng)于重量級鎖,也就是1.6之前的synchronized。

偏向鎖

偏向鎖的核心要義就體現(xiàn)在“偏”字上,這個鎖偏向第一個獲取到它的線程。

在大部分情況下,不存在激烈的鎖競爭,總是由同一個線程獲取到該鎖。那么為了減少同一個線程獲取鎖帶來的開銷,就引入了偏向鎖。

如果一個線程不斷的獲取到了鎖,那么該鎖就進(jìn)入偏向鎖狀態(tài)。當(dāng)這個線程再次請求鎖時,無需做任何同步操作,直接獲取到鎖。

當(dāng)然,偏向鎖適用于基本無鎖競爭的情況,當(dāng)鎖競爭激烈時,偏向鎖就失去了作用,會升級為輕量級鎖。

輕量級鎖

在偏向鎖的狀態(tài)下,此時又出現(xiàn)了一個線程,與偏向線程競爭該鎖,此時該鎖會升級為輕量級鎖。

舉個例子,比如創(chuàng)建一個線程1執(zhí)行同步print()方法打印奇數(shù),這時候的鎖狀態(tài)為偏向鎖。此時,再創(chuàng)建一個線程2同樣執(zhí)行同步print()方法打印偶數(shù),偏向鎖就會升級為輕量級鎖。線程1打印某個奇數(shù)時,線程2并沒有被掛起,而是處于一種自旋狀態(tài),這種自旋效率很高??墒牵?dāng)我再創(chuàng)建100個線程時,同樣執(zhí)行同步print()方法,自旋的效率將會變得十分低下,此時輕量級鎖會升級為重量級鎖,即使用Monitor來進(jìn)行同步。

鎖的升級

無鎖、偏向鎖、輕量級鎖與重量級鎖,會隨著鎖競爭的升級而升級。

從一開始的偏向鎖,產(chǎn)生鎖競爭后,升級為輕量級鎖,自旋失敗后,升級為重量級鎖,一般來說,鎖的升級是單向的。

 

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2022-07-04 08:01:01

鎖優(yōu)化Java虛擬機(jī)

2025-03-26 00:55:00

2023-09-01 08:59:57

2021-06-11 06:54:35

DPDK優(yōu)化HugeTLB

2024-02-29 18:06:39

HTTP性能優(yōu)化

2024-09-03 08:09:00

2020-12-31 05:33:34

軟件性能優(yōu)化

2021-08-03 07:40:46

Synchronize鎖膨脹性能

2020-11-12 08:32:14

Vue3模板優(yōu)化

2021-11-10 18:52:42

SQL技巧優(yōu)化

2022-03-11 10:23:02

React性能優(yōu)化

2020-11-24 11:16:06

JavaScript

2021-11-18 08:20:22

接口索引SQL

2021-08-10 08:01:08

Synchronize鎖膨脹鎖消除

2023-07-13 11:24:14

SQL優(yōu)化賦值

2023-05-26 18:52:55

2023-07-31 07:48:43

Java內(nèi)存虛擬機(jī)

2024-11-22 00:09:15

2021-09-03 23:01:58

CSS 技巧代碼重構(gòu)

2023-12-02 20:41:32

內(nèi)存kube
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號