package concurrent;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/*
* @author: wjf
* @version: 2016年3月26日 下午8:03:50
*/
public class TestVolatile {
// public volatile int inc=0;
public AtomicInteger inc=new AtomicInteger(0);
Lock lock=new ReentrantLock();
/*
* volatile 作用概述:可以保证可见性,一定程度上保证顺序性,一定程度上避免指令重排,
* 例如:
* int x=1; // 1
* int y=2; //2
* volatile boolean flag=false; //3
* x=3; //4
* y=2; //5
* volatile 保证 1,2 在 3之前,4.5 在 3之后
* 并且 语句1,2 对3,4 是可见的。
*
* volatile 使用场景
* 1:标记状态量
* volatile boolean flag=false;
* while(!flag){
* dosomething();
* }
* public void setFlag(){
* flag=true;
* }
*
* volatile boolean inited=false;
* 线程1
* cotext=loadContext();
* inited=true;
* 线程2
* while(!inited){
* sleep();
* }
* dosomethingwithconfig(context) // volatie 可以保证inited 在 context 执行完之后对inited 赋值
*
*2:double check
*
*/
/*
* volatile 可以保证可见性,当线程A 修改共享变量之后,会导致线程B 对共享变量的
* 缓存失效
* 但是却无法保证原子性
* 首先明确一点:内存模型中 ,线程都有自己的工作内存(高速缓存),java 中每个变量都存在主存中
* 例如:i=1 执行线程必须先在自己的工作线程中对变量i 所在的缓存进行操作,然后写入内存
* 例如:对于下面的例子,输出结果可能小于10000
* 比如存在下面的调度顺序:
* 1 A 读取inc 的 值,然后被阻塞
* 2 B 读取inc 的值,然后+1 ,然后被阻塞(没有将inc 的值写会,当然就没有更新到内存中)
* 3 A 唤醒,inc+1,写会,更新到内存中
* 4 B 唤醒,inc 值写会,更新到内存(此时虽然inc 缓存的值已经失效,可是此时的B已经进行完了
* +1操作,只剩下把值写会了)
*/
public void increase(){
// 使用 synchronized 解决这个问题
// synchronized (this){
// inc++;
// }
// 使用 lock 解决这个问题
// lock.lock();
// try{
// inc++;
// }finally{
// lock.unlock();
// }
// 使用AtomicInteger解决
inc.getAndIncrement();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
final TestVolatile test=new TestVolatile();
for(int i=0;i<10;i++){
new Thread(){
public void run(){
for(int j=0;j<1000;j++){
test.increase();
}
}
}.start();
}
while(Thread.activeCount()>1){
Thread.yield();
}
System.out.println(test.inc);
}
}