日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java并发编程——volatile

發布時間:2025/3/21 java 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java并发编程——volatile 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

volatile可以看成是輕量級的低配版的Synchronized,他主要是作用于共享變量,保證共享變量的可見性。確保共享變量在主內存中一致地準確的更新通知到各個線程,這是Volatile的可見性,同時由于它是低配版的Synchronized,所以他也沒有了Synchronized的一些功能,比如原子性。

Java內存模型


在理解有關Java并發編程的時候,我們是非常有必要的先了解一下Java內存模型的。

Java內存模型規定了所有的變量都存儲在主內存中,線程之間的工作并不是直接去讀取操作主內存的,而是每個工作線程首先會在主內存中拷貝這些共享變量下來線程對變量的操作都是自己的工作線程中完成的,對于不同線程之間是具有不具備可見性的(各做各的),線程間變量值的傳遞均需要通過主內存來完成。Volatile正是為了解決以上的問題而存在的。

工作線程操作變量與主內存的交互


  • read:從主內存中讀取變量
  • load:復制變量到工作線程本地內存作為副本
  • use:運算副本
  • assign:給副本賦值
  • store:副本寫入工作線程的內存中
  • write:線程內存中的共享副本刷新主內存中的共享變量

可見性

可見性是指線程之間變量的可見性,及時得到變量狀態變化的通知,一個線程修改了變量的狀態另一個就及時的知道變量的最新狀態。

舉個例子:A、B線程在主內存中拷貝同一個Volatile修飾變量,A線程把這個變量的狀態由false改為了true,緊跟著B線程就會收到通知他剛剛拷貝的變量已經過期失效,B線程就會更新這個變量,得到最新的狀態true,而不再是過期失效的狀態。

Volatile修飾的變量不允許線程內部緩存和重排序,也就是說直接操作主內存,這樣就對其他線程可見了。但是,但是,但是,Volatile修飾的變量只能保證變量的可見性,而不能保證變量的原子性,這樣就導致一些非原子性的操作仍然存在線程安全的問題。

普通的共享變量在進行操作之后,寫入主內存的時機是不確定的,該線程可能在操作完變量并且還沒寫入主內存的時候就去干別的事情了,這樣就導致在其他線程獲取這個變量的時候并不是最新的值,無法保證可見性,真是這樣的線程安全問題也就導致了程序運行結果并不是我們所期望的結果。

Volatile并不能保證原子性,而他的高配版——Synchronized完全應付了這些問題。Synchronized既能保證可見性又能保證原子性。Synchronized在工作時只能有一個線程獲取鎖執行同步代碼,并在釋放鎖的時候把變量寫入主內存中。

public class MyThread extends Thread {public boolean exit = false; public void run() { while (!exit){//do something}} }復制代碼

上面的代碼使用退出標志終止線程關閉的代碼。看上去似乎是沒有問題,只要其他線程吧exit復制為true就能夠終止線程。但是這樣寫仍然會存在風險,有可能不是我們所期望的效果。上面說過,工作線程會各自在主線程中拷貝變量,然后自顧自的工作。

以實例來說,A、B線程會在主線程中各自拷貝exit變量到自己的工作內存中,當B需要終止A線程的時候,B便會修改自己工作內存中的exit變量,但是由于不確定性B在修改本地exit變量的時候可能還沒把修改后的變量exit寫入主內存中就去了干別的事情了,導致A線程沒有終止。

給exit變量增加Volatile修飾后,B線程把本地變量exit賦值為true的時候,Volatile會強制把最新值寫到主內存中并且會通知A線程告知其本地exit變量已過期失效,立即到主內存中更新exit變量,這樣子便會使A線程的exit變量及時更新。也體現了Volatile在線程之間的可見性。

原子性

從Volatile可見性的問題中我們帶出了原子性這一名詞。原子性是指:一個操作或者多個操作(可以把它看成事務)要么全執行而且不會被中斷,要么全不執行。在Java中,對基本數據類型的變量的讀取和賦值操作是就原子性操作。原子就是不能再細分的意思。

舉個例子:int a = 8; 把8賦值給a這個操作已經不能再細分或分割了,那么類似于這種操作就稱之為原子操作。

再舉個例子:i++; 這個操作就可以分解為 i = i + 1 ,那么類似于這從操作就稱之為非原子操作。

非原子操作帶來的是線程安全問題,使用同步技術Synchronized來把這堆操作變成一個原子操作。

public class Test { public volatile int inc = 0; public void increase() {inc++; } public static void main(String[] args) { final Test test = new Test(); for(int i=0;i<10;i++){ new Thread(){@Override public void run() { for(int j=0;j<1000;j++) test.increase(); }; }.start(); } while(Thread.activeCount()>1){System.out.println(test.inc); } //保證前面的線程都執行完 Thread.yield(); } }復制代碼

上面代碼,我們直觀的認為新建了10個線程,每個線程都對inc變量自增1,那么10個線程最后輸出的結果自然是1000*10=10000,這是我們所期望的。但是通過輸出我們發現結果并不是我們所想要的。

前面提到過,Volatile只能保證變量的可見性,而不能保證原子性。

還是按實例來說,A、B線程創建后各自把inc拷貝到自己的本地內存中。此時A、B都在自己本地線程中對inc++自增,然后A、B線程把運算后的結果寫入主內存中。這樣,盡管A、B線程都進行了自增的運算,我們的期望是等于3,盡管進行了兩次自增,但是此時主內存中的inc變量只是2。

例子也體現了Volatile并不能保證非原子操作,仍然會存在線程安全問題。

解決方案:可以通過synchronized或lock,進行加鎖,來保證操作的原子性。也可以通過AtomicInteger。(不在本文范圍)

有序性

有序性就是程序執行的順序按照代碼的先后順序執行。Java內存模型具備一些先天的“有序性”,即不需要通過任何手段就能夠得到保證的有序性,這個通常也稱為 happens-before 原則。如果兩個操作的執行次序無法從happens-before原則推導出來,那么它們就不能保證它們的有序性,虛擬機可以隨意地對它們進行重排序。?

處理器為了提高程序運行效率,可能會對輸入代碼進行優化,它不保證程序中各個語句的執行先后順序同代碼中的順序一致,但是它會保證程序最終執行結果和代碼順序執行的結果是一致的。處理器的重排序不會影響單個線程,但是面臨并發編程的時候就不能保證正確性了。

volatile關鍵字可以保證一定的“有序性”。synchronized既保證有序性同樣保證原子性。

Volatile原理

在對聲明了volatile變量進行寫操作時,JVM會向處理器發送一條Lock前綴的指令,將這個變量所在緩存行的數據寫會到系統內存。 這一步確保了如果有其他線程對聲明了volatile變量進行修改,則立即更新主內存中數據。

為了保證各個處理器的工作線程一致,每個處理會通過嗅探在總線上傳播的數據來檢查自己的緩存是否過期,當處理器發現自己緩存行對應的內存地址被修改了,就會將當前處理器的緩存行設置成無效狀態,當處理器要對這個數據進行修改操作時,會強制重新從系統內存把數據讀到處理器緩存里。

小結

synchronized?是防止多個線程同時執行一段代碼,這樣同步就會影響程序執行效率,而volatile在某些情況下性能要優于synchronized。Volatile只能保證變量的可見性,并不能保證變量的原子性。對于由于非原子操作而產生的線程安全問題,還是請使用synchronized。

最后使用Volatile的必備兩個條件:

  • 對變量的操作不依賴于當前值,也就是原子操作
  • 該變量沒有包含在具有其他變量的不變式中

That's all Thank you~

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?----- End -----

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?更多好文

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 請掃描下面二維碼

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?歡迎關注~


總結

以上是生活随笔為你收集整理的Java并发编程——volatile的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。