国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 網站 > 建站經驗 > 正文

Java中synchronized正確使用方法解析

2019-11-02 14:07:18
字體:
來源:轉載
供稿:網友

生活中隨處可見并行的例子,并行 顧名思義就是一起進行的意思,同樣的程序在某些時候也需要并行來提高效率,在上一篇文章中我們了解了 Java 語言對緩存導致的可見性問題、編譯優化導致的順序性問題的解決方法,下面我們就來看看 Java 中解決因線程切換導致的原子性問題的解決方案 -- 鎖 。

說到鎖我們并不陌生,日常工作中也可能經常會用到,但是我們不能只停留在用的層面上,為什么要加鎖,不加鎖行不行,不行的話會導致哪些問題,這些都是在使用加鎖語句時我們需要考慮的。

來看一個使用 32 位的 CPU 寫 long 型變量需不需要加鎖的問題:

我們知道 long 型變量長度為 64 位,在 32 位 CPU 上寫 long 型變量至少需要拆分成 2 個步驟:一次寫 高 32 位,一次寫低 32 位。

對于單核 CPU 來說,同一時刻只有一個線程在執行,禁止 CPU 中斷就意味著禁止線程切換,獲得 CPU 使用權的這個線程就會一直運行,所以 2 次寫操作要么同時都被執行,要么都不被執行,單核 CPU 是保證原子性的。

對于多核 CPU,同一時刻,一個線程在 CPU-1 上運行,另一個線程在 CPU-2 上運行,此時禁止 CPU 切換,只能保證 CPU 上有線程運行,并不能保證同一時刻只有一個線程運行,如果兩個線程同時都在寫高位,那么得出的結果可就不正確了。

所以,互斥修改共享變量這個條件非常重要,也就是說同一時刻只有一個線程在修改共享變量,只要保證這個條件,不論單核還是多核,操作就都是原子性的了。

一說到互斥、原子性,我們馬上就想到了代碼加鎖,沒錯加鎖是正確的選擇,但是怎么加呢? 要想知道怎么加鎖,首先我們要知道加鎖鎖的是什么以及我們想要保護的資源是什么,看下圖說說鎖的是什么,要保護的是什么呢?

圖中鎖的 M 資源,保護的也是 M 資源。

程序中的鎖與現實中的鎖也是類似的,每一把鎖都有自己要保護的資源,這是至關重要的,如圖保護資源 M 的鎖為 LM,就像我家大門的鎖保護我家,你家大門的鎖保護你家一樣,如果程序出現類似我家大門鎖保護你家的情況,那么就會導致詭異的并發問題了。

了解了鎖的是什么與保護的是什么之后,我們看看怎么加鎖的問題,還是用 count += 1 的例子,看代碼:

class Test{ long value = 0L; long get() {  return value; } synchronized void addOne() {  value += 1; }}

分析一下,這段代碼中鎖的是當前對象,要保護的資源是對象中的成員屬性 value,這樣的加鎖方式開啟10 個線程分別調用 10000次 addOne()方法,我們預期的結果是 value 最終會達到 100000,結果如何呢 ?

經過測試,addOne() 不加 synchronized 結果會出現小于 100000 的情況,加上 synchronized 結果符合我們的預期,針對測試結果,簡要分析如下:

加鎖之后,線程之間是互斥的,也就是說同一時刻只有一個線程執行,這樣就原子性可以保證了。

那么可見性呢?一個線程操作結束后另一個線程能獲取到上一個線程的操作結果嗎?答案是肯定的,這就跟我們上一章說的 happen before 原則聯系到一起了,“一個鎖的解鎖操作對另一個鎖的加鎖操作是可見的”,再結合傳遞性規則,一個鎖在解鎖前,對共享變量的修改,即解鎖前對共享變量修改 happen before 于 這個鎖的解鎖,這個鎖的解鎖操作 happen before于另一個鎖的加鎖。

所以,解鎖前對共享變量修改happen before于另一個鎖的加鎖,也就是說解鎖前對共享變量修改對于另一個鎖的加鎖是可見的。

到這一切看似還挺完美,其實我們忽略了 get() 方法,多線程操作 get() 方法會是安全的嗎?在沒有任何前提操作的情況下,直接調用 get() 方法當然沒問題,就是取值又不涉及修改。但是如果在執行 addOne() 方法后調用呢?顯然,這時候 value 值的修改對 get() 方法是不可見的,happen before 中只說了鎖的規則,這里要想保證可見性,對 get()方法也需要加上一把鎖。代碼如下:

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 陆河县| 保康县| 连南| 北宁市| 宿迁市| 永州市| 普安县| 靖宇县| 那曲县| 扎鲁特旗| 岳池县| 玉树县| 新野县| 揭东县| 云南省| 高台县| 深水埗区| 乐东| 怀来县| 井研县| 慈利县| 兴和县| 大化| 大同市| 汶川县| 河西区| 香河县| 玛多县| 精河县| 奉化市| 勐海县| 黔西县| 四川省| 枣阳市| 淮安市| 凉城县| 绥棱县| 吉木萨尔县| 衡阳市| 洛川县| 大兴区|