Volatile关键字 方便以后查看

本文详细介绍了Java中的volatile关键字,它主要用于防止指令重排和保证变量的可见性。通过示例代码展示了volatile如何避免对象构造过程中的问题,以及在并发环境下如何确保线程间数据的正确同步。然而,volatile并不能保证原子性,对于复合操作如`a++`,仍需要借助synchronized来保证操作的完整性。
摘要由CSDN通过智能技术生成

Volatile关键字

Volatiile 的作用
1,防止指令重排
2,保证变量的可见性但是不能保证其原子性

防止指令重排:

public class Cat {
    private static volatile Cat cat;

    //私有化构造函数
    private Cat(){};

    private static Cat getCat(){
        if(cat == null){
            synchronized (cat){
                if(cat == null){
                    cat = new Cat();
                }
            }
        }
        return cat;
    }

/*为什么我们要在变量前面加上volatile关键字?

  • 首先我们要了解对象的构造过程
  • 1,给对象分配内存空间
  • 2,初始化对象
  • 3,将分配的内存空间地址赋值给对象的应用
  • 由于操作系统对指令码的重新排序可能会变成
  • 1,给对象分配内存空间
  • 2,将分配好的内存空间地址赋值给对象的引用
  • 3,初始化化对象
  • 如果这个流程在多线成的情况下就可能见没有初始化的对象医用暴露出来,出现不可预测的结果,因此为了防止
  • 这个指令重排我们需要将变量变成volatile类型的变量;
  • */

可见性
指一个线程修改了共同变量,而另一个线程不知道,查询的是之前没有修改的数据,这样会造成第二个线程查询的是脏数据,这是因为每个线程都有一个高速的缓存区–线程工作内存;vloatile关键字能够有效的解决这个问题;

public class VolatileTest {
    static  int a = 1;
    static int b = 2;
    public void Change(){
        a = 3;
        b = a;
    }
    public void print(){
        System.out.println("b:"+b+"::a:"+a);
    }
    public static void main(String[] args) {
        while (true){
            final VolatileTest volatileTest = new VolatileTest();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    volatileTest.Change();
                }
            }).start();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    volatileTest.print();
                }
            }).start();
            if(a == 3 && b == 1){
                break;
            }
        }
    }
}

在这里插入图片描述

原子性:
关于原子性,volatile关键字只对单词的读写保持原子性,

public class VolatileTest01 {
    private static volatile int a = 0;
    public void Change(){
        a++;
    }
    public static void main(String[] args) throws InterruptedException {
        final VolatileTest01 volatileTest01 = new VolatileTest01();
        for (int i = 0; i < 1000; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    volatileTest01.Change();
                }
            }).start();
        }
        Thread.sleep(1000);//为了保证上面的代码能够全部执行完毕
        System.out.println(a);
    }
}

在这里插入图片描述

这样就可以看出volatile关键字不能够保证原子性(如果能够保证原子性的话结果应该是1000),因为a++是一个复合操作:
1,读取a的值;
2,2,将a+1;
3,3,将a的值再次写回内存
Volatile这个关键字不能保证这三个操作的原子性,我们可以通过加锁(synchronized)的方式实现他的原子性。

可见性的原因:
因为线程不是本身不是直接跟内存进行数据交换的,而是通过线程自身的工作内存完成的,所以会导致没有可见性;volatile是通过的将线程修改后的值强制的刷新到主内存中,然后会使别的线程的线程工作内存失效,需要重新在主内存中获取最新的值;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值