Volatile关键字

volatile作用:是为了解决内存不可见(线程不可见问题)。什么是内存不可见。请看下面的例子
例子:

//任务类
class ThreadDemo implements  Runnable{
    public  boolean flag = false;
    @Override
    public void run() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        flag = true;
    }
}
//main方法测试
 public static void main(String[] args){
        ThreadDemo t1 = new ThreadDemo();
        new Thread(t1).start();
        
        while(true){
            synchronized (t1){
                if (t1.flag){
                    System.out.println("-----------");
                    break;
                }
            }
        }
    }
运行结果:

在这里插入图片描述

从上面的程可知,有两个线程分别是t1和main线程。t1用来修改flag的值,main线程用来读flag的值。但是没有读到。原因就是内存不可见。
在这里插入图片描述
两个线程开始时都将数据读到自己的拥有的内存当中再执行,main线程中的while循环是一个特别高效的语句,执行速度很快main执行起来没有时间区再去读主存当中的flag变量,所以造成线程不可见现象。

解决方案1:在使用volatile关键字
public volatile boolean flag = false;
执行结果:

方案2:使用synchronized关键字

 while(true){
            synchronized (t1){
                if (t1.flag){
                    System.out.println("-----------");
                    break;
                }
            }
  }

这样每次判断前让main线程重新读取一下t1对象。但是这样效率很差,远远不如volatile关键字。但是他们各有优势。volatile不能保证变量的原子性。那咱说一说数据的原子性。

例子:

//main
 AtomicThread a = new AtomicThread();
        for(int i =0 ; i < 10 ;i++){
            new Thread(a).start();
        }
//任务类
class AtomicThread implements  Runnable{
    int number = 0;
    @Override
    public void run() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName()+"---"+number++);
    }
}
```结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/2019031515565440.png)
出现这种的现象的原因就是破坏了原子性。

解决方案:将变量定义为原子变量,(java1.5后)
 AtomicInteger number  = new AtomicInteger(0);
 System.out.println(Thread.currentThread().getName()+"---"+number.getAndIncrement());



原子变量实现的原理:
<1>原子变量一定是内存可见的都是被volatile关键字修饰的
<2>CAS算法(Compare  and  Swap)


CAS算法:
内存值:V
预期值:A
更新值:B

当且仅当V=A的时候才更新B,不然啥操作也不做。
public class ComapreAndSwap {
    public static void main(String[] args){
        CAS cas = new CAS();
        for (int i =0 ; i< 5;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                   System.out.println(cas.setValue(0,2)); 
                }
            }).start();
        }
    }
}
class CAS{
    private   int number;
    synchronized  public int getNumber(){
        return  number;
    }
    synchronized  public int compare(int expectValue,int updateValue){
        int oldValue = this.number;
        if (oldValue == expectValue){
            this.number = updateValue;
        }
        return  oldValue;
    }
    synchronized boolean setValue(int expectValue,int updateValue){
        return  expectValue == compare(expectValue,updateValue);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值