美文网首页Java线程与并发
(五) volatile关键字

(五) volatile关键字

作者: 覆水无言 | 来源:发表于2020-03-11 20:38 被阅读0次

    Java多线程目录

    1 背景

    理解Java多线程的内存抽象逻辑请阅读java多线程内存模型,当代操作系统,处理器为提高处理速度,处理器与内存不直接进行交互,而是先将内存中的数据读取到内部缓存。Java多线程安全就是这样产生的。

    2 volatile是什么

    volatile是Java的一个关键字,在多线程并发中,volatile和synchronized都是重要的关键字,volatile比synchronized更轻量,因为volatile不需要上下文切换,它在多处理器中保证了共享变量的内存可见性

    3 内存可见性

    变量存储在内存上,在Java中被volatile修饰的变量,Java线程内存模型会确保所有线程看到的这个变量值是一致的,也就是这个变量所在的内存在Java多个线程中看到的是一样的。

    3.1 volatile怎样保证内存可见性。

    被volatile修饰的变量会确保两件事

    1. 禁止指令重排
      指令重排是个大概念,这里不详细介绍,指令重排就是我们代码的编译优化等,这个是JVM编译时做的,会影响我们的执行顺序,但不会影响执行结果。volatile禁止了指令重排,会让我们的程序更按照我们的想法执行。
    2. 内存可见性
      volatile保证了在我们对volatile修饰的变量进行修改时,线程缓存会立刻刷入主内存。同时为保持多线程看到的变量值一致性,其他线程读取volatil变量会先从主内存读取值,再与线程缓存比较后使用,形成一个线程修改volatile变量,其他线程看到的结果是一致的。

    4 volatile的局限性

    注意在我们的普通编程中我们并不推荐使用volatile关键字,因为它有各种各样的线程,使用不当达不到多线程并发想要的效果。

    4.1 操作并不是原子性

    volatile关键字只保证了内存可见性与一致性,但它并不是原子操作,所以我们不能在多个线程内对这个变量都进行写操作。

    4.2 运算结果并不依赖当前volatile变量的值,或者只有一个线程在修改volatileb变量。

    也就是说我们在普通的多线程并发操作中并不能使用volatile关键字,只有满足上面条件时才使用,来保证volatile变量一修改,其他线程会立马可见。但无法保证多个线程同时对volatile变量写而造成的线程安全问题。

    public class ThreadOne implements Runnable {
    
        volatile int i = 0;
    
        public void run() {
            i++;
            System.out.println(false + " " + Thread.currentThread().getName() + " " + i);
        }
    
        public static void main(String[] args) {
            ThreadOne one = new ThreadOne();
            for (int i = 1; i < 200; i++) {
                new Thread(one,"" + i).start();
            }
        }
    }
    

    上述代码多个线程对volatile变量i进行了写操作,所以结果一般会出现线程安全问题。

    4.3 变量不需要与其他的状态变量共同参与不变约束。

    5 总结

    1. Java中每个线程都有单独的内存,所以多线程共享变量会有线程安全问题。
    2. volatile修饰的变量每次改变都会立刻刷入主内存。
    3. 每次使用volatile变量都会先从主内存读取在与线程内存的副本进行比较,后使用。
    4. volatile修饰的变量只能保证内存可见性,它不是原子操作。
    5. volatile会禁止指令重排,代码的顺序就是执行的顺序。

    相关文章

      网友评论

        本文标题:(五) volatile关键字

        本文链接:https://www.haomeiwen.com/subject/dpxhjhtx.html