synchronize原理

?

synchronized的三種應用方式

一. 修飾實例方法,作用于當前實例加鎖,進入同步代碼前要獲得當前實例的鎖。

二. 修飾靜態方法,作用于當前類對象加鎖,進入同步代碼前要獲得當前類對象的鎖。

三. 修飾代碼塊,指定加鎖對象,對給定對象加鎖,進入同步代碼庫前要獲得給定對象。

synchronized的字節碼指令

  synchronized同步塊使用了monitorenter和monitorexit指令實現同步,這兩個指令,本質上都是對一個對象的監視器(monitor)進行獲取,這個過程是排他的,也就是說同一時刻只能有一個線程獲取到由synchronized所保護對象的監視器。

  線程執行到monitorenter指令時,會嘗試獲取對象所對應的monitor所有權,也就是嘗試獲取對象的鎖,而執行monitorexit,就是釋放monitor的所有權。

synchronized的鎖的原理

  兩個重要的概念:一個是對象頭,另一個是monitor。

Java對象頭

  在Hotspot虛擬機中,對象在內存中的布局分為三塊區域:對象頭(Mark Word、Class Metadata Address)、實例數據和對齊填充;Java對象頭是實現synchronized的鎖對象的基礎。一般而言,synchronized使用的鎖對象是存儲在Java對象頭里。它是輕量級鎖和偏向鎖的關鍵。

Mark Word

  Mark Word用于存儲對象自身的運行時數據,如哈希碼(HashCode)、GC分代年齡、鎖狀態標志、線程持有的
鎖、偏向線程 ID、偏向時間戳等等。Java對象頭一般占有兩個機器碼(在32位虛擬機中,1個機器碼等于4字節,
也就是32bit)。

?

?

Class Metadata Address

  類型指針,即是對象指向它的類的元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。

Array length

如果對象是一個Java數組,那在對象頭中還必須有一塊用于記錄數組長度的數據。

Monitor

  Monitor是一個同步工具,它內置于每一個Object對象中,相當于一個許可證。拿到許可證即可以進行操作,沒有拿到則需要阻塞等待。

  在hotspot虛擬機中,通過ObjectMonitor類來實現monitor。

?

?

synchronized鎖的優化

  jdk1.6以后對synchronized的鎖進行了優化,引入了偏向鎖、輕量級鎖,鎖的級別從低到高逐步升級:?

  無鎖->偏向鎖->輕量級鎖->重量級鎖

自旋鎖與自適應自旋

  線程的掛起和恢復會極大的影響開銷。并且jdk官方人員發現,很多線程在等待鎖的時候,在很短的一段時間就獲得了鎖,所以它們在線程等待的時候,并不需要把線程掛起,而是讓他無目的的循環,一般設置10次。這樣就避免了線程切換的開銷,極大的提升了性能。

而適應性自旋,是賦予了自旋一種學習能力,它并不固定自旋10次一下。他可以根據它前面線程的自旋情況,從而調整它的自旋,甚至是不經過自旋而直接掛起。

鎖消除

  對不會存在線程安全的鎖進行消除。

鎖粗化

  如果jvm檢測到有一串零碎的操作都對同一個對象加鎖,將會把鎖粗化到整個操作外部,如循環體。

偏向鎖

  多數情況下,鎖不僅不存在多線程競爭,而且總是由同一線程多次獲得,為了讓其獲得鎖的代價更低而引入了偏向鎖。

  當一個線程訪問同步塊并獲取鎖時,會在對象頭和棧幀中的鎖記錄里存儲鎖偏向的線程ID,以后該線程在進入和退出同步塊時不需要進行CAS操作來加鎖和解鎖,只需簡單地測試一下對象頭的Mark Word里是否存儲著指向當前線程的偏向鎖。

  如果測試成功,表示線程已經獲得了鎖。

  如果測試失敗,則需要再測試一下Mark Word中偏向鎖的標識是否設置成01(表示當前是偏向鎖)。

  如果沒有設置,則使用CAS競爭鎖。

  如果設置了,則嘗試使用CAS將對象頭的偏向鎖指向當前線程。

輕量級鎖

  引入輕量級鎖的主要目的是在多線程競爭不激烈的情況下,通過CAS競爭鎖,減少傳統的重量級鎖使用操作系統互斥量產生的性能消耗。

重量級鎖

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

鎖升級

  偏向鎖升級輕量級鎖:當一個對象持有偏向鎖,一旦第二個線程訪問這個對象,如果產生競爭,偏向鎖升級為輕量級鎖。

  輕量級鎖升級重量級鎖:一般兩個線程對于同一個鎖的操作都會錯開,或者說稍微等待一下(自旋),另一個線程就會釋放鎖。但是當自旋超過一定的次數,或者一個線程在持有鎖,一個在自旋,又有第三個來訪時,輕量級鎖膨脹為重量級鎖,重量級鎖使除了擁有鎖的線程以外的線程都阻塞,防止CPU空轉。

wait和notify的原理

  調用wait方法,首先會獲取監視器鎖,獲得成功以后,會讓當前線程進入等待狀態進入等待隊列并且釋放鎖。

  當其他線程調用notify后,會選擇從等待隊列中喚醒任意一個線程,而執行完notify方法以后,并不會立馬喚醒線程,原因是當前的線程仍然持有這把鎖,處于等待狀態的線程無法獲得鎖。必須要等到當前的線程執行完按monitorexit指令以后,也就是鎖被釋放以后,處于等待隊列中的線程就可以開始競爭鎖了。

wait和notify為什么需要在synchronized里面?

  wait方法的語義有兩個,一個是釋放當前的對象鎖、另一個是使得當前線程進入阻塞隊列,而這些操作都和監視器是相關的,所以wait必須要獲得一個監視器鎖。

而對于notify來說也是一樣,它是喚醒一個線程,既然要去喚醒,首先得知道它在哪里,所以就必須要找到這個對象獲取到這個對象的鎖,然后到這個對象的等待隊列中去喚醒一個線程。

轉載于:https://www.cnblogs.com/heqiyoujing/p/11144649.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/247634.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/247634.shtml
英文地址,請注明出處:http://en.pswp.cn/news/247634.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

不能修改“System Roots”鑰匙串

iOS mac添加證書 不能修改“System Roots”鑰匙串錯誤 如圖: 解決方式: 打開鑰匙串---登錄---,直接把證書拖過來 然后,查看--我的證書,里面,找到證書,即可

stylus在vue中的使用

stylus是一個css預處理器,比較流行的css預處理器有sass、less、stylus,它們都一樣,都是css的語法糖,可以使用變量,可以有簡單的邏輯,使css的開發效率更高,更易維護。stylus來自node社區&#xf…

未來產品的設計

Donald A. Norman繼《情感化設計》之后,又一設計精品力作: 未來產品的設計樣章試讀及本書預定:http://www.china-pub.com/195642市場價 :¥39.00 會員價 : ¥29.25(75折) 【作  者】(美)Donald…

vue-cli webpack 配置分析

目錄結構 . ├── README.md ├── build │ ├── build.js │ ├── check-versions.js │ ├── dev-client.js │ ├── dev-server.js │ ├── utils.js │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ └── webpack.prod.c…

css之字體圖標

SVG與字體圖標 SVG圖片是矢量圖片,不會隨著圖片的伸縮而影響質量,通常把只有一種顏色的圖標做成SVG,通過SVG生成字體圖標,放到項目中使用。 https://icomoon.io/是一個比較快捷的生成字體圖標的線上工具,進入主頁后&…

history.back(-1)和history.go(-1)的區別

history.back(-1):直接返回當前頁的上一頁,數據全部消息,是個新頁面 history.go(-1):也是返回當前頁的上一頁,不過表單里的數據全部還在 history.back(0) 刷新 history.back(1) 前進 history.back(-1) 后退

研發階段模擬接口數據

因為在vue-cli工程中需要創建很多.vue文件,我們希望創建vue文件和創建html、css、js文件一樣右鍵即可選擇創建,并且創建的文件中可預先寫好模板代碼。 webstorm-Preferences打開選項界面 選擇File and Code Templates,點擊綠色加號 填…

真實項目中 ThreadLocal 的妙用

一、什么是 ThreadLocal ThreadLocal 提供了線程的局部變量,每個線程都可以通過 set() 和 get() 來對這個局部變量進行操作,但不會和其他線程的局部變量沖突,實現了線程間的據隔離。 簡單講:一個獲取用戶的請求線程 A,…

css之flex布局

flex布局是css3中的重要布局方式,稱為“彈性布局”,每次想到它主要是遇到元素垂直居中、元素寬高自適應的問題,這些問題在flex中都能過簡單設置就解決,它更像是原生APP中的布局操作,布局不必寫N多的盒模型代碼來實現&a…

javascript對URL中的參數進行簡單加密處理

javascript的api本來就支持Base64,因此我們可以很方便的來進行編碼和解碼。 var encodeData window.btoa("namexiaoming&age10")//編碼 var decodeData window.atob(encodeData)//解碼。 下面來個具體的例子來說明如何對url中參數進行轉碼&#xff…

Fibinary Numbers

http://acm.hust.edu.cn/vjudge/contest/view.action?cid30506#problem/V 題意:從右向左,每一個位數,分別表示一個fibonacci數,1表示有,0表示沒有;求兩個數的和,同樣按照這種形式存儲 #include…

移動web開發DRP問題

DPR dpr問題是移動端web開發上需要注意的問題,用大白話說就是,代碼中所設置的像素值實際上是虛擬像素,手機屏幕上的像素實際為物理像素,原始的手機,虛擬像素與物理像素是1:1覆蓋的,但隨著移動端屏幕的技術發…

HTML元素title里面如何換行

在調試代碼的時候我就遇到一個問題,HTML元素title里面通常只顯示一行,那我想要他換行,就是多行顯示,如何實現?JS代碼里面比如Alert里面又該如何換行? 經過我的一番實驗 要實現這種效果有幾種方法&#xff0…

A20 GPIO中斷類型差別結果迥異的問題思考

A20GPIO中斷類型差別結果迥異的問題思考 最近在使用全志A20做開發時,發現在處理中斷的時候,用電平觸發模式,報中斷比較亂,用邊沿觸發則很穩定,不會亂報。筆者感到比較困惑,筆者用電平觸發寫的code如下&…

div內圖片和文字水平垂直居中

大小不固定的圖片、多行文字的水平垂直居中 本文綜述 想必寫css的都知道如何讓單行文字在高度固定的容器內垂直居中,但是您知道或者想過讓行數不固定的文字在高度固定的容器內垂直居中呢?本文將會告訴你如何實現多行文字的垂直居中顯示。 關于圖片垂直居…

sticky-footer實現記錄

sticky-footer是css中的一個經典問題: 當頁面內容超出屏幕,頁腳模塊會像正常頁面一樣,被推到內容下方,需要拖動滾動條才能看到。 而當頁面內容小于屏幕高度,頁腳模塊會固定在屏幕底部,就像是底邊距為零的…

敏友的【敏捷個人】有感(3): 有感于“敏捷個人”討論與練習

2010年我對個人管理進行了自己的一些思考,在2011年提出敏捷個人概念,并且在線上、線下進行了多次交流,在一些大會上也做過分享。現在,已經有很 多IT和非IT的敏友們知道并在踐行敏捷個人,幫助自己更快的成長。我收到大家…

jQuery編寫插件

引言: 在項目中不同頁面經常要用到已經寫好的交互,比如彈窗,比如下拉菜單,比如選項卡,比如刪除... 此時如果每次都把代碼copy一份無疑是一件比較麻煩并且無趣的事情,而且個人認為有些low了,我們…

webstorm中nodejs代碼提示

preferences->languages&frameworks->Node.js and Npm中選擇一個本地的node版本 preferences->languages&frameworks->JavaScript->Libraries 勾選node.js Core 回到代碼

9012教你如何使用gulp4開發項目腳手架

本文將會介紹如何使用gulp4來搭建項目腳手架,如果您還在使用gulp3或更老的版本,您也以通過本文的一些思想將之前的項目進行完善,更新。如果gulp不是你們團隊的重點,也可以移步我的另一篇文章:用 webpack 4.0 擼單頁/多頁腳手架 (j…