volatile关键字概念

1. volatile概念

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

volatile用来修饰变量:private volatile int num = 0;
当前有两个线程t1,t2,这是两个独立的线程,没有任何关系,但是有一块儿共享的数据,比如int a = 0;这个a是这两个线程共享的变量,t1的run方法里面a=10;t1的run方法里面a=20。t1线程修改a=10对t2线程不可见,同理t2线程修改a=20对t1线程a=10不可见。虽然变量a是共享的,但是t1由0改成10,t2线程肯定不知道,它拿到时a=0,改成a=20。虽然拿到的是同一份副本,但是t1,t2可定没关系。现在想让有关系,a变化时,t1,t2实时知道,t1修改a=10,t2马上知道a=10,t2从a=10变成a=20,a始终保持一致性,同理,t2修改a=20,t1马上知道a变成20了。
早期,没有volatile,在a上加一把锁。效率不高。

2. 示例【com.bjsxt.base.sync007】RunThread

public class RunThread extends Thread {
    private 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 {
        RunThread rt = new RunThread();
        rt.start();
        Thread.sleep(3000);
        rt.setRunning(false);
        System.out.println("isRunning的值已经被设置了false");
        Thread.sleep(1000);
        System.out.println(rt.isRunning);
    }
}

执行结果
这里写图片描述

jdk执行一个线程的时候,都会单独分配一块儿空间,但是在jdk1.5以后,对每一个线程Thread做了一个优化,对每一个线程加了一块儿独立的运行的内存空间,存储主内存中的一些当前线程所使用的引用变量,把当前主内存中的一些变量的副本copy到了自己的区间中,线程运行中,直接去副本取值,线程运行效率高。
当前有一个主函数线程,在rt.start()这句又产生了一个新的线程rt线程,对应JVM有rt线程空间,产生rt线程独立内存空间,装主内存中的一些变量isRunning=true, 在rt线程执行过程中,isRunning变量被引用,把变量的值copy到rt空间,rt线程的线程执行引擎在执行过程中,就直接会去找自己独立空间的isRunning,虽然把主内存中的值置位false,但是rt线程执行所依赖的独立内存空间的isRunning。
如果每次去主内存空间取值,太浪费性能,用volatile。

public class RunThread extends Thread {
    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 {
        RunThread rt = new RunThread();
        Thread.sleep(4000);
        rt.start();
        Thread.sleep(3000);
        rt.setRunning(false);
        System.out.println("isRunning的值已经被设置了false");
        Thread.sleep(1000);
        System.out.println(rt.isRunning);
    }
}

执行结果
这里写图片描述
这里写图片描述

同一个变量在rt和main线程实现了两个线程间可见。

3. 示例总结

  • 在java中,每一个线程都会有一块工作内存区,其中存放着所有线程共享的主内存中的变量值的拷贝。当线程执行时,他在自己的工作内存区中操作这些变量。为了存取一个共享的变量,一个线程通常先获取锁定并去清除它的内存工作区,把这些共享变量从所有线程的共享内存区中正确的装入到他自己的工作内存区中,当线程解锁时保证该工作内存区中变量的值写回到共享内存中。
  • 一个线程可以执行的操作有使用(use)、赋值(assign)、装载(load)、存储(store)、锁定(lock)、解锁(unlock)。
  • 而主内存可以执行的操作有读(read)、写(write)、锁定(lock)、解锁(unlock),每个操作都是原子的。
  • volatile的作用就是强制线程到主内存(共享内存)里去读取变量,而不去线程工作内存区里去读取,从而实现了多个线程间的变量可见。也就是满足线程安全的可见性。

猜你喜欢

转载自blog.csdn.net/ada_yangyang/article/details/80823798