91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

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

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

Java中synchronized關鍵字的作用是什么

發布時間:2021-06-30 17:31:27 來源:億速云 閱讀:279 作者:Leah 欄目:大數據

這篇文章將為大家詳細講解有關Java中synchronized關鍵字的作用是什么,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

1.  什么是synchronized
我們將其理解為同步鎖,可以實現共享資源的同步訪問,解決線程并發的安全問題。

1.1 怎么使用的

  • 修飾實例方法,作用于當前對象實例加鎖,進入同步代碼前要獲得當前對象實例的鎖
  • 修飾靜態方法,作用于當前類對象加鎖,進入同步代碼前要獲得當前類對象的鎖 。     也就是給當前類加鎖,會作用于類的所有對象實例,因為靜態成員不屬于任何一個實例對象,是類成員( static 表明這是該類的一個靜態資源,不管new了多少個對象,只有一份,所以對該類的所有對象都加了鎖)。     所以如果一個線程A調用一個實例對象的非靜態 synchronized 方法,而線程B需要調用這個實例對象所屬類的靜態 synchronized 方法,是允許的,不會發生互斥現象,因為訪問靜態 synchronized 方法占用的鎖是當前類的鎖,而訪問非靜態 synchronized 方法占用的鎖是當前實例對象鎖。
  • 修飾代碼塊,指定加鎖對象,對給定對象加鎖,進入同步代碼塊前要獲得給定對象的鎖。      和 synchronized 方法一樣,synchronized(this)代碼塊也是鎖定當前對象的。     synchronized 關鍵字加到 static 靜態方法和 synchronized(class)代碼塊上都是是給 Class 類上鎖。     這里再提一下:     synchronized關鍵字加到非 static 靜態方法上是給對象實例上鎖。     另外需要注意的是:     盡量不要使用 synchronized(String a) 因為JVM中,字符串常量池具有緩沖功能!

2.早期的synchronized

JDK1.6之前屬于重量級鎖,依賴于操作系統的Mutex Lock,Java的線程映射到操作系統的原生線程,需要操作系統申請互斥量,操作系統對線程的切換,需要從用戶態切換到內核態,比較耗時,效率底下。

3.對synchronized的優化

JDK1.6之后在JVM層面對synchronized底層做了很多的優化,包括偏向鎖,輕量級鎖,自旋鎖,自適應自旋鎖,鎖消除,鎖粗化等優化技術。

3.1 偏向鎖

目的:在沒有線程競爭的情況下,減少傳統的重量級鎖使用操作系統互斥量的開銷,提升性能。
特點:  
  1. 在沒有鎖競爭的情況下,會把整個鎖消除
  2. 偏向于第一個獲取到偏向鎖的線程
  3. 如果在接下來的執行中偏向鎖沒有被其他線程獲取,那么擁有該鎖的線程就不需要同步
變化:在鎖競爭激烈的場合,偏向鎖失效。原因是,在此情況下,極有可能每次申請鎖的線程不是同一個線程,所以此時不應該使用偏向鎖,否則得不償失。But,偏向鎖失效后,并不會立即膨脹為重量級鎖,而是首先升級為輕量級鎖。
關于偏向鎖的原理可以查看《深入理解Java虛擬機:JVM高級特性與最佳實踐》第二版的13章第三節鎖優化。

3.2 輕量級鎖

當偏向鎖失效,JVM不會立即升級為重量級鎖,而是試圖使用輕量級鎖的優化手段(JDK1.6之后加入的)。輕量級鎖不是為了替代重量級鎖,它的本意是是在沒有線程競爭的情況下,減少傳統的重量級鎖使用操作系統互斥量的開銷,提升性能。
目的:和偏向鎖一樣
特點:  
  1. 和偏向鎖不同,輕量級鎖使用CAS操作代替重量級鎖。
  2. 使用輕量級鎖,不需要申請互斥量。
  3. 輕量級鎖的加鎖和釋放鎖都是CAS操作。
變化:對于大多數鎖來說,在整個同步周期都不存在競爭,這來自經驗數據。如果沒有競爭,輕量級鎖使用CAS操作,避免了使用互斥鎖的開銷。如果存在競爭,除了互斥鎖的開銷,還會有額外的CAS操作,所以如果存在鎖競爭,輕量級鎖比重量級鎖更慢。如果競爭激烈輕量級鎖會迅速膨脹為重量級鎖。
關于輕量級鎖的原理可以查看《深入理解Java虛擬機:JVM高級特性與最佳實踐》第二版的13章第三節鎖優化。

3.3 自旋鎖和自適應自旋鎖

輕量級鎖失效后,JVM避免線程真的在操作系統層面掛起,還會進行一項成為自旋鎖的優化手段。
在JDK1.6之前就有這項技術了,只是他是默認關閉的,可以通過參數--XX:+UseSpinning開啟。JDK1.6之后默認開啟。自旋不能完全替代阻塞,因為它還要占用處理器的時間。如果鎖被占用的時間短,那么自旋鎖的效果就好;否則,反之。自旋等待的時間必須固定,如果超過限定的次數,仍然沒有獲取到鎖,就掛起線程。自旋默認10次,可以使用參數--XX:PreBlockSpin修改。
3.3.1 為什么會有自旋鎖
互斥同步對性能最大的影響是阻塞的實現,因為線程的掛起和恢復都需要轉入內核態去完成(用戶態到內核態的轉換將會耗費一定的時間)。而一般線程持有鎖的時間并不會太長,如果僅僅為了這一點時間而掛起或恢復線程將會得不償失。所以JVM團隊就想:"   能否讓后面來的請求獲取鎖的線程等待一會兒而不被掛起?看看持有鎖的線程是否很快就會釋放鎖"。
目的:為了減少線程的掛起和恢復,減少帶來的系統開銷,引入自旋鎖。
3.3.2 如何實現自旋
為了讓一個線程等待,我們只需要讓線程執行一個忙循環(自旋),這項技術就叫做   自旋
3.3.3 自旋的特點
  1. 執行忙循環
  2. 自旋次數固定(默認10次)
  3. JDK1.6之前默認關閉,之后默認打開
  4. 效果的好壞依賴于鎖被占用的時間的長短
3.3.4 自適應自旋鎖
另外,在JDK1.6時候引入了自適應自旋鎖。改進:自旋次數不是固定的。根據上次同一個鎖的自旋次數和鎖的擁有者的狀態來確定自旋次數。JVM變得越來越聰明了。
與自旋鎖的區別就是自旋次數不固定。

3.4 鎖消除

即使JVM正在運行,如果檢測到共享數據不可能存在競爭,將會執行鎖消除操作。這將會節省毫無意義的請求鎖的時間。

3.5 鎖粗化

原則上我們寫代碼,總是建議將Synchronized代碼塊的作用范圍限制的盡量小,只在共享數據的實際作用域才進行同步,使需要同步的操作數盡量小,如果存在競爭,等待線程也會盡快拿到鎖。
大部分情況下,上面的原則沒有問題,但是如果一些列的連續操作都對同一個對象反復加鎖解鎖,會帶來很多不必要的性能消耗。

 

4.Synchronized和ReenTrantLock對比

① 兩者都是可重入鎖  
兩者都是可重入鎖。   “可重入鎖”概念是:   自己可以再次獲取自己的內部鎖。   比如一個線程獲得了某個對象的鎖,此時這個對象鎖還沒有釋放,當其再次想要獲取這個對象的鎖的時候還是可以獲取的,如果不可鎖重入的話,就會造成死鎖。   同一個線程每次獲取鎖,鎖的計數器都自增1,所以要等到鎖的計數器下降為0時才能釋放鎖。  
② synchronized 依賴于 JVM 而 ReenTrantLock 依賴于 API  
synchronized 是依賴于 JVM 實現的,前面我們也講到了 虛擬機團隊在 JDK1.6 為 synchronized 關鍵字進行了很多優化,但是這些優化都是在虛擬機層面實現的,并沒有直接暴露給我們。   ReenTrantLock 是 JDK 層面實現的(也就是 API 層面,需要 lock() 和 unlock 方法配合 try/finally 語句塊來完成),所以我們可以通過查看它的源代碼,來看它是如何實現的。  
③ ReenTrantLock 比 synchronized 增加了一些高級功能  
相比synchronized,ReenTrantLock增加了一些高級功能。   主要來說主要有三點:  
  a.等待可中斷;b.可實現公平鎖;c.可實現選擇性通知(鎖可以綁定多個條件)  
  • ReenTrantLock提供了一種能夠中斷等待鎖的線程的機制,通過lock.lockInterruptibly()來實現這個機制。     也就是說正在等待的線程可以選擇放棄等待,改為處理其他事情。
  • ReenTrantLock可以指定是公平鎖還是非公平鎖。而synchronized只能是非公平鎖。所謂的公平鎖就是先等待的線程先獲得鎖。ReenTrantLock默認情況是非公平的,可以通過 ReenTrantLock類的     ReentrantLock(boolean fair)     構造方法來制定是否是公平的。
  • synchronized關鍵字與wait()和notify/notifyAll()方法相結合可以實現等待/通知機制,ReentrantLock類當然也可以實現,但是需要借助于Condition接口與newCondition() 方法。     Condition是JDK1.5之后才有的,它具有很好的靈活性,比如可以實現多路通知功能也就是在一個Lock對象中可以創建多個Condition實例(即對象監視器),線程對象可以注冊在指定的Condition中,從而可以有選擇性的進行線程通知,在調度線程上更加靈活。在使用notify/notifyAll()方法進行通知時,被通知的線程是由 JVM 選擇的,用ReentrantLock類結合Condition實例可以實現“選擇性通知” ,這個功能非常重要,而且是Condition接口默認提供的。     而synchronized關鍵字就相當于整個Lock對象中只有一個Condition實例,所有的線程都注冊在它一個身上。     如果執行notifyAll()方法的話就會通知所有處于等待狀態的線程這樣會造成很大的效率問題,而Condition實例的signalAll()方法 只會喚醒注冊在該Condition實例中的所有等待線程。
如果你想使用上述功能,那么選擇ReenTrantLock是一個不錯的選擇。  
④ 性能已不是選擇標準  
在JDK1.6之前,synchronized 的性能是比 ReenTrantLock 差很多。   具體表示為:   synchronized 關鍵字吞吐量隨線程數的增加,下降得非常嚴重。   而ReenTrantLock 基本保持一個比較穩定的水平。   我覺得這也側面反映了, synchronized 關鍵字還有非常大的優化余地。   后續的技術發展也證明了這一點,我們上面也講了在 JDK1.6 之后 JVM 團隊對 synchronized 關鍵字做了很多優化。   JDK1.6 之后,synchronized 和 ReenTrantLock 的性能基本是持平了。所以網上那些說因為性能才選擇 ReenTrantLock 的文章都是錯的!JDK1.6之后,性能已經不是選擇synchronized和ReenTrantLock的影響因素了!而且虛擬機在未來的性能改進中會更偏向于原生的synchronized,所以還是提倡在synchronized能滿足你的需求的情況下,優先考慮使用synchronized關鍵字來進行同步!優化后的synchronized和ReenTrantLock一樣,在很多地方都是用到了CAS操作。  

關于Java中synchronized關鍵字的作用是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

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

AI

土默特左旗| 庆城县| 天峨县| 瓦房店市| 偃师市| 浦县| 龙游县| 彰化县| 衡南县| 辽中县| 靖远县| 楚雄市| 芦溪县| 玉溪市| 大洼县| 沁阳市| 宜良县| 墨玉县| 东乌珠穆沁旗| 宁南县| 卓尼县| 清水河县| 康平县| 汶川县| 安岳县| 江津市| 濮阳市| 临清市| 南京市| 锡林郭勒盟| 固阳县| 两当县| 雷州市| 乌拉特中旗| 安国市| 龙山县| 崇明县| 永昌县| 丰县| 上栗县| 甘孜县|