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。
内存不可见性:当多个thread操作共享数据时,彼此不可见
volatile:当多个thread操作共享数据时,保证数据是可见的,内存栅栏 可以理解为多个线程直接操作主存中的数据
因为使用vloatile 不能指令重排 所以效率低
volatile相比synchronized:
是一种较为轻量级的同步策略,volatile不具备互斥性,两个线程可以同时访问共享数据,volatile不能保证变量的原子性,
原子性问题:i++
以下情况使用volatile不能解决非原子性问题:内存可见性问题依然存在
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++; } }
二、使用源自变量 java.util.concurrent.atomic 原子变量包
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); } }