volatile

volatile 轻量级的同步机制

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

JMM 内存模型

JVM运行程序的实体是线程,每个线程创建,JVM实体都会为其创建一个工作内存(栈空间),工作内存是每个线程的私有的数据区域,而java内存模型中规定所有的变量都存储在主内存中,主内存是共享的内存区域,所有线程都可以访问,但线程对变量的操作必须在工作内存中进行,首先要将变量从主内存中拷贝到自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回到主内存。

硬盘<内存<缓存<CPU

线程将值写回主物理内存,及时通知其他线程,叫 JMM 内存模型的可见性

volatile 可见性代码验证

public class Test01 {
    public static void main(String[] args) {
        MyData myData = new MyData();
        new Thread(() -> {
            try {
                //休眠3秒钟
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //修改myData的值
            myData.change();
            System.out.println(Thread.currentThread().getName() + "修改了myData的值为:" + myData.num);
        }, "AAA线程").start();
        while (myData.num == 0) {

        }
        System.out.println("all thread is over......");
    }
}

class MyData {
    //volatile修饰变量保证了可见性
    volatile int num = 0;
    public void change() {
        this.num = 1;
    }
}

volatile 不保证原子性代码验证

public class Test01 {
    public static void main(String[] args) {
        MyData myData = new MyData();
        CountDownLatch countDownLatch = new CountDownLatch(10);
        //10个线程,每个线程执行1000次 i++ 操作
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    myData.increment();
                }
                countDownLatch.countDown();
            }, String.valueOf(i)).start();
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //正确的数据应该是10000,但是得到的数据却小于10000,原因是多线程情况下出现了写覆盖
        System.out.println(myData.num);
    }
}

class MyData {
    volatile int num = 0;
    public void increment() {
        num++;
    }
}

volatile 不保证原子性的解决方案

public class Test01 {
    public static void main(String[] args) {
        MyData myData = new MyData();
        CountDownLatch latch = new CountDownLatch(20);
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    myData.increment();
                }
                latch.countDown();
            }, String.valueOf(i)).start();
        }
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(myData.atomicInteger);
    }
}

class MyData {
    //AtomicInteger保证了原子性操作
    AtomicInteger atomicInteger = new AtomicInteger();
    public void increment() {
        atomicInteger.getAndIncrement();
    }
}
posted @ 2021-09-28 17:17  紫川先生  阅读(31)  评论(0编辑  收藏  举报