并发编程基础之volatile关键字的用法
一:概念
volatile關鍵字是一個輕量級的線程同步,它可以保證線程之間對于共享變量的同步,假設有兩個線程a和b,
它們都可以訪問一個成員變量,當a修改成員變量的值的時候,要保證b也能夠取得成員變量最新的值,程序的
內存模型是這樣的,程序運行時,成員變量的值被加載到內存中,如果線程a運行時,會把變量的值拷貝到cpu分配
給a的高速緩存區,就是內存的一個副本,線程b運行時,會把變量拷貝到cpu分配給b的高速緩存區,正常情況下,
a線程修改成員變量時,會將高速緩存中的值寫入主存,然后b線程運行時讀取主存中值到緩存,但是不是強制性的,
使用volatile關鍵字就是強制性。
1:將高速緩存強制寫入主內存
2:會使b線程高速緩存標記失效
?
二:比較經典的一個示例
t1線程先啟動,然后一直打印‘i love u’,這時t2線程啟動,將flag變量的值修改為true,然后t1線程的執行終止,如果flag變量不加volatile修飾,
出現死循環的概率是存在的,但是比較低,如果加volatile,會強制t2線程修改主內存中flag的值,而且t1線程高速緩存標記會失效,可以保證
一定能夠終止t1程序的執行
/*** */ package com.day2;/*** @author Administrator**/ public class ListAdd1 {private boolean flag;public static void main(String[] args) {ListAdd1 list = new ListAdd1();//線程1Thread t1 = new Thread("t1"){public void run(){while(!list.flag){System.out.println("i love u");}}};//線程2Thread t2 = new Thread("t2"){public void run(){list.flag = true;}};t1.start();//保證t1線程先啟動try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}t2.start();}}?
private volatile boolean flag;
但是volatile并不能保證操作的原子性,線程搶到cpu的時間片,修改高速緩存的值,寫入主內存這幾個過程不是原子的,
?
int i = 0;
i = i+1;
如果線程1在搶到cpu的時間片之后,還沒有修改高速緩存的值,然后線程2也讀取了主內存中緩存的值i = 0,然后執行加1,
寫入高速緩存,線程1之前讀取緩存中的值也是0,然后執行加1,寫入主內存,這樣就出現問題了,所以使用volatile不能
保證線程安全問題。
如下示例:
啟動10個線程,count初始值為0,正常情況,10個線程個循環1000次,最后的count值應該為10000,但是不是,這個值
是隨機的。
/*** */ package com.day2;/*** @author Administrator**/ public class ListAdd2 {private volatile int count;public static void main(String[] args) {ListAdd2 list = new ListAdd2();System.out.println(list.count);for(int i=0;i<10;i++){new Thread("t"+i){public void run(){for(int j=0;j<1000;j++){list.count++;}}}.start();}System.out.println(list.count);}}
如果想確保線程安全,那么必須使用synchronized鎖
synchronized (list) {list.count++;}
因為10個線程訪問的是同一個實例,所以使用對象鎖就可以了。
轉載于:https://www.cnblogs.com/warrior4236/p/7531973.html
總結
以上是生活随笔為你收集整理的并发编程基础之volatile关键字的用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ 1087: [SCOI2005
- 下一篇: VMWare: eth0: error