zoukankan      html  css  js  c++  java
  • Java 中的 volatile

    volatile 是Java虚拟机提供的轻量级的同步机制。

    1. 保证可见性
    2. 不保证原子性
    3. 禁止指令重排

    可见性

    当多个线程操作同一个变量时,每个线程都会将该变量拷贝一份到自己工作内存中,然后线程完成操作之后,将变量写回主内存。因此可见性就是一个线程在修改变量之后,回通知其他线程,告知改变量已经被修改了。
    首先创建一个资源类

    class MyData {
        volatile int number = 0;
        public void setNumber () {
            this.number = 60;
        }
        public void numberPlus() {
            this.number++;
        }
    }
    // 多线程下测试
    public static void main(String[] args) {
       MyData myData = new MyData();
       new Thread(() -> {
                System.out.println(myData.number);
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                myData.setNumber();
                System.out.println(myData.number);
            }, "AAA").start();;
    
            while(myData.number == 0) {
            }
    }
    

    当使用 volatile 修饰 number 之后,程序回输出 0 和 60 之后执行完成退出。
    当没有使用 volatile 修饰 number,程序回输出 0 和 60 之后一直保持执行(死循环),不退出。
    由此可以看出,volatile 修饰的变量在修改后,回通知其他线程,保证可见性。

    原子性

    class MyData {
        volatile int number = 0;
        public void setNumber () {
            this.number = 60;
        }
        public void numberPlus() {
            this.number++;
        }
        AtomicInteger atomicInteger = new AtomicInteger(); // 默认为0
        public void atomicAdd() {
            atomicInteger.getAndIncrement();
        }
    }
    public static void main(String[] args) {
        MyData myData = new MyData();
        for(int i=0; i<20; i++) {
                new Thread(() -> {
                    for(int j=0; j<1000; j++) {
                        myData.numberPlus();
                        myData.atomicAdd();
                    }
                }, String.valueOf(i)).start();;
            }
    
            while(Thread.activeCount() >2) {
                Thread.yield();
            }
            System.out.println(myData.number);
            System.out.println(myData.atomicInteger);
    }
    

    程序输出 number 的值小于20000,atomicIntege r等于20000。
    因为 volatile 不保证原子性,所以在多线程下操作 number 会出现值被覆盖的问题,也就是一个线程还没有完成++,另一个线程就取出了 number 进行++, 最后导致值小于了 20000。
    解决 volatile 原子性问题,可以使用 AtomicInteger

    指令重排

    为了提高性能,编译器和处理器常常会进行指令重排,在多线程环境下,由于指令重排,导致代码的执行顺序和我们书写代码顺序不一致,最终变量能否保持一致是无法确定的,结果无法预测。

  • 相关阅读:
    HDU4003 Find Metal Mineral
    POJ1125 Stockbroker Grapevine
    HDU4028The time of a day
    弱校ACM奋斗史
    POJ1236 Network of Schools
    HDU4004 The Frog's Games
    HDU4001 To Miss Our Children Time
    POJ2186 Popular Cows
    POJ1094 Sorting It All Out
    hadoop2.7.1单机和伪集群的搭建0
  • 原文地址:https://www.cnblogs.com/Godfunc/p/11052348.html
Copyright © 2011-2022 走看看