004Volatile关键字

Volatile概念:Volatile关键字的主要作用是使变量在多个线程间可见。

作用:

1.在多线程间可以进行变量的变更,使得线程间进行数据的共享可见

2.阻止指令重排序,happens-before

public class UseVolatile extends Thread{
    
    //为isRunning加上volatile关键字修饰,实现线程通讯过程中的数据共享
    private volatile Boolean isRunning = true;
    
    private void setRunning(boolean isRunning) {
        this.isRunning = isRunning;
    }
    
    public void run() {
        System.out.println("进入run方法");
        while(isRunning == true) {
            //...
        }
        System.out.println("线程停止!");
    }
    
    public static void main(String[] args) throws InterruptedException {
        UseVolatile uv = new UseVolatile();
        //启动run方法的线程
        uv.start();
        //主线程休眠两秒钟
        Thread.sleep(2000);
        //休眠两秒钟后,修改isRunning = false,因为使用volatile修饰isRunning所以主线程修改后可以实现共享,死循环停止。
        uv.setRunning(false);//调用setRunning方法的线程
        
        System.out.println("isRunning的值已经被设置成了false!");
    }

}

输出结果:

进入run方法
isRunning的值已经被设置成了false!
线程停止!

        代码中有两个线程同时访问isRunning变量,分别是执行setRunning()方法的线程和执行run()方法的线程,使用volatile关键字修改isRunning来实现线程间数据共享,run()方法启动无限循环,休眠两秒后启动setRunning()修改isRunning为false,run()方法停止。

 

        一个线程可以执行的操作有使用(use)、赋值(assign)、装载(load)、存储(store)、锁定(lock)、解锁(unlock),而主内存可以执行的操作有读(read)、写(write)、锁定(lock)、解锁(unlock),每个操作都是原子的,内存和线程之间的关系,可以理解为,内存就是一个容器包含一个或多个线程,而线程就是容器内的元素。

        volatile的作用就是强制线程主内存(共享内存)里去读取变量,而不去线程工作内存区里去读取,从而实现了多个线程间的变量可见。也就是满足线程安全的可见性。 

Volatile & happens-before & 指令重排序

Java Memory ModelJava 内存模型)JMM,并发编程这块,没有JMM是不行的,要解决的问题就是一个线程对共享变量的写入何时对另一个线程可见!

比如一个线程给变量 a 赋值

int a = 3; // 向变量 a 写值

要解决的问题就是:"在什么条件下,读取变量a的线程将看到这个值3"

如果缺少同步,那会有很多因素使得读取变量a的线程不能立即看到或者永远看不到这个值3,在JMM的世界里,所有的变量都存储在主内存, 每一个线程都有一个私有的本地内存(线程工作区),本地内存(线程工作区)中存储了该线程使用到的变量在主内存中拷贝!

线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的变量(volatile变量也不例外)。

 happens-before规则:

举个例子:

i = 1; // 操作 A

j = i;  // 操作 B

        如果操作A happens-before 于操作B,那么就可以确定,操作B执行完之后,j 的值一定为 1;因为happens-before关系可以向程序员保证:在操作B执行之前,操作A的执行后的影响[或者说结果](修改 i 的值)操作B是可以观察到的[或者说可见的];换句话说,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须要存在happens-before关系,在这个例子就是A操作的结果要对B操作可见,那么必然存在A happens-before B,简而言之:使用happens-before的概念来阐述操作之间的内存可见性。

        程序顺序规则: 一个线程中的每个操作,happens-before于该线程中的任意后续操作(也就是说你写的操作,如果是单线程执行,那么前面的操作[程序逻辑上]就会happens-before于后面的操作)这里的影响指修改了 i 变量的值;

        监视器锁规则: 对一个锁的解锁,happens-before 于随后对这个锁的加锁;

        volatile变量规则:对一个 volatile域的写,happens-before于任意后续对这个volatile域的读;

        传递性规则: 如果 A happens-before B,B happens-before C,那么A happens-before C;

        传递性在JDK中,JAVA语言为了维持顺序内部的顺序化语义,也就是为了保证程序的最终运行结果需要和在单线程严格意义的顺序化环境下执行的结果一致,程序指令的执行顺序有可能和代码的顺序不一致,这个过程就称之为指令的重排序。指令重排序的意义在于:JVM能根据处理器的特性,充分利用多级缓存,多核等进行适当的指令重排序,使程序在保证业务运行的同时,充分利用CPU的执行特点,最大的发挥机器的性能!

知识点:

1.happens-before是jvm维护程序逻辑先后关系的指令(没有happens-before、没有JMM那么程序会混乱执行)

2.volatile关键字可以组织happens-before即指令重排序

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值