public class VolatileTest { public static void main(String[] args) { ThreadDemo td = new ThreadDemo(); new Thread(td).start(); while(true){ if(td.getFlag()){ System.out.println("========"); break; } } } } class ThreadDemo implements Runnable{ private boolean flag=false; @Override public void run() { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } flag=true; System.out.println("flag="+getFlag()); } public boolean getFlag(){ return flag; } }
flag是main thread和td共享的數據,他們都在各自的線程內有一個copy,因爲while true的速度十分快,main thread不能讀取到td修改後的值,因此只能輸出 flag=true。java
內存不可見性:當多個thread操做共享數據時,彼此不可見算法
volatile:當多個thread操做共享數據時,保證數據是可見的,內存柵欄 能夠理解爲多個線程直接操做主存中的數據安全
由於使用vloatile 不能指令重排 因此效率低併發
volatile相比synchronized:dom
是一種較爲輕量級的同步策略,volatile不具有互斥性,兩個線程能夠同時訪問共享數據,volatile不能保證變量的原子性,ide
原子性問題:i++this
如下狀況使用volatile不能解決非原子性問題:內存可見性問題依然存在atom
public class AtomicTest { public static void main(String[] args) { AtomicDemo ad = new AtomicDemo(); for(int i=0;i<10;i++){ new Thread(ad).start(); } } } class AtomicDemo implements Runnable{ private int serialNum=0; @Override public void run() { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":"+getSerialNum()); } public int getSerialNum(){ return serialNum++; } }
2、使用源自變量 java.util.concurrent.atomic 原子變量包spa
1.使用volatile保證內存可見性線程
2.使用CAS compare and swap算法保證數據的原子性
CAS是硬件對於併發操做共享數據的支持
CAS包含三個操做數:
內存值V 預估值A 更新值B
(1)首先讀取內存之V 在替換的時候讀取舊值A
AtomicInteger:保證線程安全 內存可見性 原子性問題
private AtomicInteger serialNum=new AtomicInteger(); @Override public void run() { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":"+getSerialNum()); } public int getSerialNum(){ return serialNum.getAndIncrement(); }
CAS算法的模擬:
public class TestCAS { public static void main(String[] args) { final CompareAndSwap cas = new CompareAndSwap(); for(int i=0;i<10;i++){ new Thread(new Runnable() { @Override public void run() { int expectVal = cas.get(); boolean b= cas.compareAndSwap(expectVal,(int)(Math.random()*101)); } }).start(); } } } class CompareAndSwap { private int value; public synchronized int get() { return value; } public synchronized int cas(int expectVal, int newVal) { int oldVal = value; if (oldVal == expectVal) this.value = newVal; return oldVal; } public synchronized boolean compareAndSwap(int expectVal, int newVal) { return expectVal==cas(expectVal,newVal); } }