1. 程式人生 > >為什麼volatile不能保證原子性而Atomic可以?(r)

為什麼volatile不能保證原子性而Atomic可以?(r)

在上篇《非阻塞同步演算法與CAS(Compare and Swap)無鎖演算法》中講到在Java中long賦值不是原子操作,因為先寫32位,再寫後32位,分兩步操作,而AtomicLong賦值是原子操作,為什麼?為什麼volatile能替代簡單的鎖,卻不能保證原子性?這裡面涉及volatile,是java中的一個我覺得這個詞在Java規範中從未被解釋清楚的神奇關鍵詞,在Sun的JDK官方文件是這樣形容volatile的:

The Java programming language provides a second mechanism, volatile fields, that is more convenient than locking for some purposes. A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable.

意思就是說,如果一個變數加了volatile關鍵字,就會告訴編譯器和JVM的記憶體模型:這個變數是對所有執行緒共享的、可見的,每次jvm都會讀取最新寫入的值並使其最新值在所有CPU可見。volatile似乎是有時候可以代替簡單的鎖,似乎加了volatile關鍵字就省掉了鎖。但又說volatile不能保證原子性(java程式設計師很熟悉這句話:volatile僅僅用來保證該變數對所有執行緒的可見性,但不保證原子性)。這不是互相矛盾嗎?

不要將volatile用在getAndOperate場合,僅僅set或者get的場景是適合volatile的

不要將volatile用在getAndOperate場合(這種場合不原子,需要再加鎖),僅僅set或者get的場景是適合volatile的

volatile沒有原子性舉例:AtomicInteger自增

例如你讓一個volatile的integer自增(i++),其實要分成3步:1)讀取volatile變數值到local; 2)增加變數的值;3)把local的值寫回,讓其它的執行緒可見。這3步的jvm指令為:

1 2 3 4 mov   0xc(%r10),%r8d ; Load inc    %r8d           ; Increment mov    %r8d,0xc(%r10) ; Store lock addl $
0x0,(%rsp) ; StoreLoad Barrier

注意最後一步是記憶體屏障。

什麼是記憶體屏障(Memory Barrier)?

。基本上,它是這樣一條指令: a) 確保一些特定操作執行的順序; b) 影響一些資料的可見性(可能是某些指令執行後的結果)。編譯器和CPU可以在保證輸出結果一樣的情況下對指令重排序,使效能得到優化。插入一個記憶體屏障,相當於告訴CPU和編譯器先於這個命令的必須先執行,後於這個命令的必須後執行。記憶體屏障另一個作用是強制更新一次不同CPU的快取。例如,一個寫屏障會把這個屏障前寫入的資料重新整理到快取,這樣任何試圖讀取該資料的執行緒將得到最新值,而不用考慮到底是被哪個cpu核心或者哪顆CPU執行的。

記憶體屏障(memory barrier)和volatile什麼關係?上面的虛擬機器指令裡面有提到,如果你的欄位是volatile,Java記憶體模型將在寫操作後插入一個寫屏障指令,在讀操作前插入一個讀屏障指令。這意味著如果你對一個volatile欄位進行寫操作,你必須知道:1、一旦你完成寫入,任何訪問這個欄位的執行緒將會得到最新的值。2、在你寫入前,會保證所有之前發生的事已經發生,並且任何更新過的資料值也是可見的,因為記憶體屏障會把之前的寫入值都重新整理到快取。

volatile為什麼沒有原子性?

明白了記憶體屏障(memory barrier)這個CPU指令,回到前面的JVM指令:從Load到store到記憶體屏障,一共4步,其中最後一步jvm讓這個最新的變數的值在所有執行緒可見,也就是最後一步讓所有的CPU核心都獲得了最新的值,但中間的幾步(從Load到Store)是不安全的,中間如果其他的CPU修改了值將會丟失。下面的測試程式碼可以實際測試voaltile的自增沒有原子性:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 private static volatile long _longVal = 0; private static class LoopVolatileimplements Runnable { public void run() { long val = 0; while (val < 10000000L) { _longVal++;

相關推薦

為什麼volatile不能保證原子Atomic可以?r

在上篇《非阻塞同步演算法與CAS(Compare and Swap)無鎖演算法》中講到在Java中long賦值不是原子操作,因為先寫32位,再寫後32位,分兩步操作,而AtomicLong賦值是原子操作,為什麼?為什麼volatile能替代簡單的鎖,卻不能保證原子性?

為什麼volatile不能保證原子Atomic可以?

在上篇《非阻塞同步演算法與CAS(Compare and Swap)無鎖演算法》中講到在Java中long賦值不是原子操作,因為先寫32位,再寫後32位,分兩步操作,而AtomicLong賦值是原子操作,為什麼?為什麼volatile能替代簡單的鎖,卻不能保證原子性?這裡面涉及volatile,是java中的

Volatile保證原子

Volatile不保證原子性 前言 通過前面對JMM的介紹,我們知道,各個執行緒對主記憶體中共享變數的操作都是各個執行緒各自拷貝到自己的工作記憶體進行操作後在寫回到主記憶體中的。 這就可能存在一個執行緒AAA修改了共享變數X的值,但是還未寫入主記憶體時,另外一個執行緒BBB又對主記憶體中同一共享變數X進行操作

深入理解Atomic原子操作和volatile原子

log tile 修飾 深入 clas 同時 結果 一個 body 原子操作可以理解為: 一個數,很多線程去同時修改它,不加sync同步鎖,就可以保證修改結果是正確的 Atomic正是采用了CAS算法,所以可以在多線程環境下安全地操作對象。 volatile是Java的關鍵

volatile不能保證原子,也就不能保證執行緒安全

volatile只能保證變數的可見性,無法保證對變數的操作的原子性。 還是以最常用的i++來說吧,包含3個步驟 1,從記憶體讀取i當前的值 2,加1 3,把修改後的值重新整理到記憶體 對於普通變數來說多執行緒下1,2之間被中斷,其

volatile為什麼不能保證原子的思考

1、故事的起因:         前幾天有人問過關於volatile關鍵字的一些問題, 想起了自己剛接觸這個關鍵字時候存在的疑惑,趕上今天有時間就整理了一些自己的想法。         首先,需要明確的一點是,volatile關鍵字修飾的變數可以保證該變數操作的有序性和可

volatile 可以保證可見,但不能保證原子

轉自:http://blog.csdn.net/shukebai/article/details/51163068 在Java執行緒併發處理中,有一個關鍵字volatile的使用目前存在很大的混淆,以為使用這個關鍵字,在進行多執行緒併發處理的時候就可以萬事大吉。 J

Java併發程式設計之驗證volatile不能保證原子

Java併發程式設計之驗證volatile不能保證原子性 通過系列文章的學習,凱哥已經介紹了volatile的三大特性。1:保證可見性 2:不保證原子性 3:保證順序。那麼怎麼來驗證可見性呢?本文凱哥(凱哥Java:kaigejava)將通過程式碼演示來證明為什麼說volatile不能夠保證共享變數的原子性操

java併發之----原子,可見和有序性轉載

一、併發程式設計中的三個概念 在併發程式設計中,我們通常會遇到以下三個問題:原子性問題,可見性問題,有序性問題。我們先看具體看一下這三個概念: 1.原子性 原子性:即一個操作或者多個操作 要麼全部執行並且執行的過程不會被任何因素打斷,要麼就都不執行。 一個很經典的例子就是銀行

Java關鍵字volatile原子,變數可見

The volatile keyword also ensures visibility across the application. If you declare a field to be volatile, this means that as soon as a write occurs for t

編寫安全程式碼:小心volatile原子誤解

這時,exit_flag都需要使用volatile來修飾。不然對於執行緒1的程式碼,如果編譯器發現線上程1的程式碼中沒有任何地方修改exit_flag,有可能會將exit_flag放入暫存器快取。這樣,在每次的條件檢查的時候,都是從暫存器中讀取,而非exit_flag對應的記憶體。這樣將導致每次讀取的值都為0

volatile是非原子 AtomicInteger原子

import java.util.concurrent.atomic.AtomicInteger; /*  * volatile不是原子性的,它只保證變數在多執行緒中可見,操作時並不是執行緒安全的  * AtomicInteger 是原子性的  */ public clas

『ORACLE』 DG能轉換11g

files bsp 備庫 for ima -s rim line 修改 一、最大性能轉換至最大可用 確認主庫模式: [email protected]/* */ hey~2->select protection_mode,protection_level

能測試應用領域

架構 關心 剖析 測試結果 可擴展 服務 style 快速 折線圖 大概說說性能測試的五種應用領域吧,可能純文字內容太多,沒耐心的話,可以跳過不看。。。 ————參考書籍《軟件性能測試過程詳解與案例剖析》 概括來說,可以將性能測試的應用領域劃分為下面五個不同領域:

Mysql數據庫能優化

效率 dir sort variables 緩存 模型 mysql5.6 包含 dpt 參考 http://www.jb51.net/article/82254.htm 今天,數據庫的操作越來越成為整個應用的性能瓶頸了,這點對於Web應用尤其明顯。關於數據庫的性能,這並不只

mysql能優化

配置文件 mysql 數據庫 網絡 信息 mysql性能優化、慢查詢分析、優化索引和配置一.每項的基本思路步驟1.性能瓶頸定位:show命令、慢查詢日誌、explain分析查詢、profiling分析查詢、2.索引及查詢優化3.配置優化二.my

soapui接口能測試---- 模擬不同類型的負載

output tor 10個 相對 超過 對話框 interval -s 根據 SoapUI中提供的不同負載策略允許您模擬各種類型的負載,隨時間的變化,您可以在許多條件下輕松測試目標服務的性能。由於SoapUI還允許您同時運行多個LoadTests(參見下文的示例),可以使

soapui接口能測試---- 輸出報告和統計

color table repo line src testin edi set diag 好的,您已經運行了LoadTest,現在需要創建一些報告或導出收集的數據以進行更詳細的分析。有幾個選項可供您使用,我們將按順序查看:導出統計表的數據(僅限開源)。從統計圖導出數據。在

Web頁面能優化YSlow

java 字符 新版 目標 網絡 imp web頁面 檢查 用戶 YSlow(解析為Why Slow)是雅虎基於網站優化規則推出的工具,幫助你分析並優化網站性能。舊版Yslow 有13條規則,新版Yslow有23項規則,YSlow會根據這些規則分析你的網站,並給出評級。

從NSTimer的失效談起:關於GCD Timer和libdispatch

not 證明 note sta 理解 得到 team 其他 vtable 一、GCD Timer的創建和安放 盡管GCD Timer並不依賴於NSRunLoop,可是有沒有可能在某種情況下,GCD Timer也失效了?就好比一開始我們也不知道NSTim