violate关键字

Violate关键字

引用:https://www.cnblogs.com/dolphin0520/p/3920373.html
这篇博客讲的比较好。
个人理解:violate能够保证可见性和有序性,

可见性:

例子如下:

//线程1
boolean stop = false;
while(!stop){
    doSomething();
}
 
//线程2
stop = true;

当线程1,stop为共享变量,放在主存中,线程1读取一份数据放到工作内存中,进行while循环,而线程二,运行时也读取了stop变量到工作内存中,但是单线程二赋值stop为true时,没发立即将stop的值写入到主存中,只会写入到工作内存。
当将stop用violate关键字修饰时,发生修改后,会产生3中效果。
1.将stop值,立即写入主存。
2.将线程1中工作内存的stop值缓存行,置为无效。
3.由于线程1读取stop值时,工作内存无效,会重新去主存读取。

顺序性:

例子如下:

//线程1:
context = loadContext();   //语句1
inited = true;             //语句2
 
//线程2:
while(!inited ){
  sleep()
}
doSomethingwithconfig(context);

inited被violate修饰时,保证context已经初始化完毕,效果是:
1.当程序执行到volatile变量的读操作或者写操作时,在其前面的操作的更改肯定全部已经进行,且结果已经对后面的操作可见;在其后面的操作肯定还没有进行。
2. 在进行指令优化时,不能将在对volatile变量访问前的语句放在其后面执行,也不能把volatile变量后面的语句放到其前面执行。

violate没发保证原子性

public class Test {
    public volatile int inc = 0;
     
    public void increase() {
        inc++;
    }
     
    public static void main(String[] args) {
        final Test test = new Test();
        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);
    }
}

violate不能保证原子性,violate的使用场景是,

  1. 状态标记量
volatile boolean flag = false;
 
while(!flag){
    doSomething();
}
 
public void setFlag() {
    flag = true;
}
volatile boolean inited = false;
//线程1:
context = loadContext();  
inited = true;            
 
//线程2:
while(!inited ){
sleep()
}
doSomethingwithconfig(context);
  1. 双重循环校验
class Singleton{
    private volatile static Singleton instance = null;
     
    private Singleton() {
         
    }
     
    public static Singleton getInstance() {
        if(instance==null) {
            synchronized (Singleton.class) {
                if(instance==null)
                    instance = new Singleton();
            }
        }
        return instance;
    }
}

双重校验理解:
1.第一次判断(instance==null)是为了减少线程访问时都需要加锁后在判断,影响效率。所以在加锁前做了判断,如果获取锁后,继续判断是否初始化成功,如果没成功在初始化。
2.此时初始化,是分成3个部分,
a.开辟内存对象。
b.初始化对象。
c.将内存对象引用赋值给变量。
b和c可能会发生重排序,这时如果有线程走到第一次判断,则会拿到一个未初始化的对象,运行会发生错误。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值