1. 程式人生 > >volatile失效,慎重使用volatile關鍵字

volatile失效,慎重使用volatile關鍵字

volatile關鍵字相信瞭解Java多執行緒的讀者都很清楚它的作用。volatile關鍵字用於宣告簡單型別變數,如int、float、boolean等資料型別。如果這些簡單資料型別宣告為volatile,對它們的操作就會變成原子級別的。但這有一定的限制。例如,下面的例子中的n就不是原子級別的:

  1. package mythread;  
  2. publicclass JoinThread extends Thread  
  3. {  
  4. publicstaticvolatileint n = 0;  
  5. publicvoid run()  
  6.     {  
  7. for (int i = 0; i < 10; i++)  
  8. try
  9.         {  
  10.                 n = n + 1;  
  11.                 sleep(3); // 為了使執行結果更隨機,延遲3毫秒 
  12.             }  
  13. catch (Exception e)  
  14.             {  
  15.             }  
  16.     }  
  17. publicstaticvoid main(String[] args) throws Exception  
  18.     {  
  19.         Thread threads[] = new Thread[100];  
  20. for (int i = 0; i < threads.length; i++)  
  21. // 建立100個執行緒 
  22.             threads[i] = new JoinThread();  
  23. for (int i = 0; i < threads.length; i++)  
  24. // 執行剛才建立的100個執行緒 
  25.             threads[i].start();  
  26. for (int i = 0; i < threads.length; i++)  
  27. // 100個執行緒都執行完後繼續 
  28.             threads[i].join();  
  29.         System.out.println("n=" + JoinThread.n);  
  30.     }  
  31. }  

如果對n的操作是原子級別的,最後輸出的結果應該為n=1000,而在執行上面積程式碼時,很多時侯輸出的n都小於1000,這說明n=n+1不是原子級別的操作。原因是宣告為volatile的簡單變數如果當前值由該變數以前的值相關,那麼volatile關鍵字不起作用,也就是說如下的表示式都不是原子操作:

n = n + 1;
n++;

如果要想使這種情況變成原子操作,需要使用synchronized關鍵字,如上的程式碼可以改成如下的形式:

  1. package mythread;  
  2. publicclass JoinThread extends Thread  
  3. {  
  4. publicstaticint n = 0;  
  5. publicstaticsynchronizedvoid inc()  
  6.     {  
  7.         n++;  
  8.     }  
  9. publicvoid run()  
  10.     {  
  11. for (int i = 0; i < 10; i++)  
  12. try
  13.             {  
  14.                 inc(); // n = n + 1 改成了 inc(); 
  15.                 sleep(3); // 為了使執行結果更隨機,延遲3毫秒 
  16.             }  
  17. catch (Exception e)  
  18.             {  
  19.             }  
  20.     }  
  21. publicstaticvoid main(String[] args) throws Exception  
  22.     {  
  23.         Thread threads[] = new Thread[100];  
  24. for (int i = 0; i < threads.length; i++)  
  25. // 建立100個執行緒 
  26.             threads[i] = new JoinThread();  
  27. for (int i = 0; i < threads.length; i++)  
  28. // 執行剛才建立的100個執行緒 
  29.             threads[i].start();  
  30. for (int i = 0; i < threads.length; i++)  
  31. // 100個執行緒都執行完後繼續 
  32.             threads[i].join();  
  33.         System.out.println("n=" + JoinThread.n);  
  34.     }  
  35. }  

上面的程式碼將n=n+1改成了inc(),其中inc方法使用了synchronized關鍵字進行方法同步。因此,在使用volatile關鍵字時要慎重,並不是只要簡單型別變數使用volatile修飾,對這個變數的所有操作都是原來操作,當變數的值由自身的上一個決定時,如n=n+1、n++等,volatile關鍵字將失效,只有當變數的值和自身上一個值無關時對該變數的操作才是原子級別的,如n = m + 1,這個就是原級別的。所以在使用volatile關鍵時一定要謹慎,如果自己沒有把握,可以使用synchronized來代替volatile。

相關推薦

volatile失效慎重使用volatile關鍵字

volatile關鍵字相信瞭解Java多執行緒的讀者都很清楚它的作用。volatile關鍵字用於宣告簡單型別變數,如int、float、boolean等資料型別。如果這些簡單資料型別宣告為volatile,對它們的操作就會變成原子級別的。但這有一定的限制。例如,下面的例子

constvolatilestatictypdef幾個關鍵字辨析和理解

iostream 很好 都是 種類 狀態 優點 ror 識別 出錯 1、const類型修飾符 const它限定一個變量初始化後就不允許被改變的修飾符。使用const在一定程度上可以提高程序的安全性和可靠性。它即有預編譯命令的優點也有預編譯沒有的優點。const修飾的變量被

java學習(1).staticvolatiletransientfinal等關鍵字

static 靜態關鍵字 簡而言之一句話,不對類來例項化就可以用。 一,相關用法 1,static可以修飾類中定義的變數 也叫做靜態變數。 此時表明這個變數和具體類的例項無關而是和類相關的。靜態變數和普通類變數的區別也就是。類變數不區分例項,也就是說

多執行緒之volatile、ThreadLocal、synchronized關鍵字區別

     轉載自:https://blog.csdn.net/paincupid/article/details/47346423 1.volatile volatile主要是用來在多執行緒中同步變數。  在一般情況下,為了提升效能,每個執行緒在執行時

並發編程之ThreadLocal、Volatile、synchronized、Atomic關鍵字掃盲

匯編指令 free clas 保持 break 作用 nta 總結 read 版權聲明:本文為博主原創文章,未經博主允許不得轉載。轉載註明出處:Sunzxyong https://blog.csdn.net/u010687392/article/details/50549

ThreadLocal、Volatile、synchronized、Atomic關鍵字掃盲

前言 對於ThreadLocal、Volatile、synchronized、Atomic這四個關鍵字,我想一提及到大家肯定都想到的是解決在多執行緒併發環境下資源的共享問題,但是要細說每一個的特點、區別、應用場景、內部實現等,卻可能模糊不清,說不出個所以然來,所以,本文就對

Eclipse搜尋失效搜尋類、檔案失效(Open Resource失效或者搜關鍵字失效(Search失效)解決

最近要跑以前的老專案,重新用Eclipse從SVN匯出來之後,搜尋失效。原因:搜尋範圍是用working set 做限制的,但是以前的程式碼刪掉或者移走,working set 已經失效了,導致搜不到東西解決:刪掉working set,重新配置working set即可。

Java Volatile 原理使用

當一個變數被Volatile修飾後,它就擁有了兩種特性 1、執行緒可見性,當一個執行緒修改了這個被Volatile修飾的變數,那麼這個變數的變動其他的執行緒都能讀的到 2、禁止指令重排序優化。 但是

volatile 作用原理

volatile會增加一個記憶體屏障。1. 禁止指令重排序12345678//x、y為非volatile變數//flag為volatile變數x = 2;        //語句1y = 0;        //語句2flag = true;  //語句3x = 4;    

獲取iOS系統版本號慎重使用[[[UIDevice currentDevice] systemVersion] floatValue]——【sdk缺陷】

net 版本 ice system family class 失效 color -s iOS 最常見的獲取系統版本的方法是: [[[UIDevice currentDevice] systemVersion] floatValue] 可是。這個floatValue是

應對Memcache緩存失效導致高並發查詢DB

post 過期 == 導致 寫入 標記 線程 name memcach 當Memcached緩存失效時,容易出現高並發的查詢DB,導致DB壓力驟然上升。 這篇blog主要是探討如何在緩存將要失效時,及時地更新緩存,而不是如何在緩存失效之後,如何防止高並發的DB查詢。 解決

Elasticsearch全文檢索高亮關鍵字

code spa nsh pes lds exp response sets highlight 問題 用如下這樣的term方式,可以高亮 .setQuery(QueryBuilders.termQuery("PARAM_NAME", "a")) { "query":

百度地圖手機端單觸點單擊和長按事件解決部分手機(小米手機)地圖單擊事件失效多觸點、拖動依然觸發長按的bug

|| ble apply timeout console dto eat 問題 int /** * Author 嶽曉 * * 對百度地圖的事件擴展,目前擴展了fastclick和longclick, * 解決某些設備click不執行的問題

網卡速率變化導致paramiko模塊timeout的失效多線程超時控制解決辦法。

context .com 判斷 cep util sha fff fail stdout 起因: 上周給幾個集群的機器升級軟件包,每個集群大概兩千臺服務器,但是在軟件發包和批量執行命令的過程中有兩個集群都遇到了問題,在批量執行命令的時候總是會在後面卡住久久不能退出

jquery.lazyload 懶加載失效圖片無法加載

.com fad png 失效 bsp move class 每次 渲染 ajax請求的數據,使用js模板進行渲染,出現了無法實現懶加載的情況解決辦法是在js模板引擎之後使用 而且遇到一個問題,首頁會有多個接口請求,所以要在每次ajax請求接口,渲染模板後都

CentOS7經常發現DNS配置失效配置信息被清空

spa device manager fatal -s some toc onf 發現 問題描述: 使用CentOS7後,經常發現/etc/resolv.conf下的永久配置DNS信息不再那麽好使,添加的nameserver 192.168.1.xxx的信息在

ORACLE索引失效更新統計信息

exec use cascade not null dna oracl HERE ima gree 有時候建立索引的時候不走索引,排除了字段數據問題和sql寫法問題之外,應該是統計信息有問題,得重新收集。 一:解鎖統計信息 為了穩定執行計劃,一般統計信息都會被鎖住的,在更新

支付寶 支付寶掃描生成的二維碼提示:碼已失效請重新整理二維碼後重試

問題描述: 開發過程中整合支付寶支付是掃描生成的二維碼提示:二維碼失效? 1 最近在做支付寶電腦網站支付開發時,使用官方sdk執行後,掃描生成的付款二維碼提示:碼已失效,請重新整理二維碼後重試。 導致這種錯誤的原因是我們使用了正式環境的支付寶APP掃描的沙箱環境下的付款二維碼  解決辦

selenium常見問題:element is not attached to the page document頁面重新整理後元素失效需要重新定位元素

 測試中,常遇到此問題,特此寫一個重新獲取元素的函式,已供呼叫解決此方法     #找不到元素時,重新獲取元素,eletype預設獲取單個元素,若=1,則獲取多個元素 #weblement有值,則傳入webelement def retying_get_el

springboot2.0 異步操作@Async失效無法進入異步

cond olt log拆分 ack int ring tst 外部 拒絕策略 springboot異步操作可以使用@EnableAsync和@Async兩個註解,本質就是多線程和動態代理。 一、配置一個線程池 @Configuration @EnableAsync/