多线程之volatile关键字详解

volatile关键字主要有两大特性:

1、内存可见性

2、防止指令重排(指令重排是JVM底层优化)

内存可见性解析

多个线程对同一个变量进行操作时,其他线程对变量的修改对于当前线程不可见。线程对变量进行操作时,会去主存中读取该变量的值,然后将该值作为副本保存在当前线程中,当有其他线程对该值进行修改时,当前线程并不会去主存中读取最新值,而是继续使用副本值。

代码示例

/**
 *  启动两个线程任务,分别对Apple实例中的num变量进行读写
 */
public class VolatileTest {

    public static void main(String[] args) {
        Apple apple = new Apple();
        new Thread(new Runnable() {
            @Override
            public void run() {
                /** 线程不睡,后面线程读取的就是刷新后的值
                 *  线程睡了之后,后面线程从主存中读取的就是修改前的值,该值存在后面线程中作为副本,
                 *  其他线程修改的值刷新到主存中,但是后面线程不会去主存中读取,所以后续while循环的值是线程副本中的值,
                 *  所以其他线程修改的值对后面线程不可见,因此while循环不会读取最新值一直死循环,
                 *  加volatile关键字修饰变量即可保证内存可见性,让线程每次读取该变量的时候都直接到主存中去读取
                 */
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                apple.setNum(10);
                System.out.println("已修改num值为10");
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    if (apple.getNum() == 10) {
                        // 不加volatile无法打印
                        System.out.println("--------------");
                        break;
                    }
                }
            }
        }).start();
    }
}



class Apple {
    // 加volatile修饰保证内存可见性,可以去掉看下有什么异同
    private volatile int num = 1; 


    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }
}

指令重排解析


当前创建对象的过程是
1)栈内存开启空间给对象引用
2)堆内存分配对象地址,并准备初始化对象
3)初始化对象
4)栈内存引用指向堆内存中对象地址
优化之后可能会变成 1,2,4,3。此时栈空间已经引用了堆空间的地址,但是此时对象还没初始化,那么对象的使用可能就会抛出
nullPointException.

最后

使用volatile关键字会防止JVM底层优化指令重排,指令重排提升程序执行效率,但是也会给我们程序带来不确定性(空指针异常)。

volatile确保其他线程对变量的更新操作会通知到其他线程,可以看作一个轻量级的锁,但是它与锁又有所不同:

1)没有锁的互斥性

2)不能保证变量的原子性操作

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值