JAVA并发-从缓存一致性说volatile 讲的很好
生活随笔
收集整理的這篇文章主要介紹了
JAVA并发-从缓存一致性说volatile 讲的很好
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
http://blog.csdn.net/yizhenn/article/details/52384477
?
?
學過計算機組成原理的一定知道,為了解決內存速度跟不上CPU速度這個問題,在CPU的設計中加入了緩存機制,緩存的速度介于CPU和主存之間。在進行運算的時候,CPU將需要的數據映射一份在緩存中,然后直接操作位于緩存中的數據,操作完畢后再將緩存中的數據寫回到主存。這在單線程環境中是沒有任何問題的。但是在多線程環境中就大不同了。? (緩存是指在內存中劃分出一塊區域用于存放常使用的輸入輸出數據,以緩解CPU與外設處理速度不匹配的問題)假設現在有這樣的一個場景:有兩個線程thread1和thread2,他們都在操作位于主存上的一個數據int a=2(具體操作為讀取a的值并執行一個自增操作)。邏輯上正確的結果:應當是最后a=4。但可能有這樣的情況,thread1將a=2從主存映射到自己的工作內存上,自增后變成a=3,在將a=3從工作內存寫回到主存之前,thread2也將a=2從從主存映射到自己的工作內存上,也自增后變成a=3。然后兩個線程先后將a=3寫回到主存上。顯然,a=3不是我們想看到的。看,這就是一個常見的緩存一致性問題。兩個線程對a的操作結果互不可見,thread1不知道thread2對a進行了自增,thread2也不知道thread1對a進行了自增。在多線程編程中就是會出現這樣一致性的問題。(在JMM中,可以知道,內存分為主內存和工作內存,每個線程有自己 的工作內存,他們共享主內存)。?
因此我們要辦法讓線程對共享變量的操作結果互相可見,java語言中的volatile關鍵字就干了一件這樣的事。使用volatile修飾的共享變量,當有線程修改了他的值的時候,他會立即強制將修改的值寫回到主存,并通知其他使用該共享變量的線程:他們的緩存區中關于此變量的值已經失效。請重新從主存中讀取。?
仔細閱讀volatile干的事,一共有3點影響:?
1 將修改的值強制刷新到主存?
2 通知其他相關線程變量已經失效?
3 其它線程再使用變量的時候就會重新從主存讀取?
這就解決了JAVA并發編程中的可見性問題。?
可見性:當多個線程訪問同一個共享變量的時候,一個線程對該共享變量的修改能夠實時的被訪問該共享變量的其他線程知曉。?
繼續說上面的那個例子,如果變量a被使用了volatile修飾,那么在thread1中,當a變為3的時候,就會強制刷新到主存。如果這個時候,thread2已經將a=2從從主存映射到緩存上,那么在對a進行自增操作以前,會重新到主存中讀取a=3,然后自增到a=4,然后寫回到主存。上面的過程很完美,但這樣是否保證了a最終的結果一定是4呢?未必。? ++這個操作非原子,a=a+1 同樣非原子,先讀a 然后再寫 a
繼續說上面的那個例子,如果變量a被使用了volatile修飾,那么在thread1中,當a變為3的時候,就會強制刷新到主存。如果這個時候,thread2已經將a=2從從主存映射到緩存上并且已經做完了自增操作,此時a=3,那么最終主存中a的值為3。?
所以,如果我們想讓a的最終值是4,僅僅保證可見性是不夠的,還得保證原子性。也就是對于變量a的自增操作加鎖,保證任意一個時刻只有一個線程對a進行自增操作。可以說volatile是一種“輕量級的鎖”,它能保證鎖的可見性,但不能保證鎖的原子性。?
volatile變量的一種典型用法,就是用于那些狀態的標記,比如: (這是一個最典型的應用,主要用于單例模式)
[java]?view plaincopy
在其他線程中,可能會修改flag的值為true,代表退出循環。如果不使用volatile修飾flag,可能在flag被回收之后,主線程還沒收到其值改變的消息。這是volatile的一種典型應用。
?
轉載于:https://www.cnblogs.com/silyvin/p/9106786.html
總結
以上是生活随笔為你收集整理的JAVA并发-从缓存一致性说volatile 讲的很好的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 上证指数3000点什么意思
- 下一篇: collate