Java多线程高并发面试(一)-volatile

目录

1.volatile

1.1 volatile是什么?

1.2 JMM内存模型之可见性

1.3 可见性的代码验证

1.4 volatile不保证原子性

1.5 volatile不保证原子性理论解释

1.6 volatile不保证原子性问题解决

1.7 volatile指令重排序案例1

1.8 volatile指令重排序案例2

1.9 单利模式在多线环境下存在的安全性问题

1.10 单例模式volatile分析


1.volatile

1.1 volatile是什么?

1.概念: volatile是JVM提供的一种轻量级同步机制

2.特性

(1)保证可见性Q1:什么是可见性?

(2)不保证原子性Q2:什么是原子性

(3)禁止指令重排序Q3:什么指令重排序?

 想要理解volatile的特性,需要解决上面的灵魂三问,请继续往下看。

1.2 JMM内存模型之可见性

1.概念:JMM是全称是Java Memory Model ,即Java内存模型,它是一组规则或规范,用于定义程序中各个变量的访问方式;是抽象的概念,并不真实存在。简而言之:JMM是一种约束,用于定义内存中各个变量的读写方式。

2.JMM的同步规定

(1)线程加锁前,必须从主存中读取共享变量的最新值到线程自己的工作内存中。Q1:什么是线程自己的工作内存?

(2)线程解锁前,必须将线程自己工作内存中的值刷回主存中。

(3)加锁解锁必须是同一把锁。

3.线程的不可见性

(1) 概念:线程自己的工作内存:Java程序运行的实体是线程,JVM为每个线程都分配一个私有的内存空间(私有内存空间归该线程独享,其他线程不能访问),这个私有内存空间称之为线程自己的工作内存(2.Q1)。

(2)线程访问共享变量的方式:

场景:某一时刻,线程1,线程2同时访问主存中的变量num,线程1将num的修改为num=8。

过程

         ①线程1,线程2先将主存中共享num的值拷贝一个副本到自己线程的工作内存中。此时,线程1,线程2中的副本 num = 5。

         ②线程1修改自己工作内存中副本 num = 8。

         ③线程1的副本num的值修改后,会立即刷回主存,此时主存的 num = 8。

         ④主存中num的值变化后,并没有通知线程2重新从主存中拷贝num最新的值,此时,线程2中的副本 num = 5。

结论:线程1对共享变量num的修改对线程2是不可见的现象,称之为线程不可见性

概念线程对共享变量的修改,不能通知其他线程看见称之为线程的不可见性反之线程对共享变量的修改,能够立即通知其他线程看见,称之为线程的可见性。

4.JMM三大特性

(1)可见性

(2)原子性

(3)有序性

1.3 可见性的代码验证

(1)不可见性验证

/**
 * 验证volatile的可见性
 */
public class VisibilityDemo {

    //共享变量 5
    public static /*volatile*/ int num = 5;

    public static void main(String[] args) {
        //开启线程thread-1
        new Thread(() -> {
            //休眠2秒
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //修改num的值
            num = 8;
            System.out.println("thread-1 修改了num的值:" + num);
        }, "thread-1").start();

        //开启线程thread-1
        new Thread(() -> {
            System.out.println("thread-2获取num="+num);
            while (true) {
                if (num != 5) {
                    System.out.println("thread-2 获取了修改后的num="+num);
                    break;
                }
            }
        }, "thread-2").start();
    }
}

运行结果:

(2)可见性验证

   用volatile修饰变量 num : public static volatile int num = 5;

/**
 * 验证volatile的可见性
 */
public class VisibilityDemo {

    //共享变量 5
    public static volatile int num = 5;

    public static void main(String[] args) {
        //开启线程thread-1
        new Thread(() -> {
            //休眠2秒
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //修改num的值
            num = 8;
            System.out.println("thread-1 修改了num的值:" + num);
        }, "thread-1").start();

        //开启线程thread-1
        new Thread(() -> {
            System.out.println("thread-2获取num="+num);
            while (true) {
                if (num != 5) {
                    System.out.println("thread-2 获取了修改后的num="+num);
                    break;
                }
            }
        }, "thread-2").start();
    }
}

运行结果: 

1.4 volatile不保证原子性

(1)什么是原子性?

原子性是指不可以分割的整体,线程处理具体业务时,处理过程中不能被加塞或者打断,需要整体完整,业务要么同时成功,要么同时失败。

(2)volatile不保证原子性代码验证

/**
 * volatile不能保证原子性
 */
public class AtomDemo {
    //字段
    private int sum = 0;

    /**
     * 自增
     */
    public void add(){
        sum ++;
    }

    public static void main(String[] args) {
        //共享变量
        AtomDemo atomDemo = new AtomDemo();

        //开启20个线程
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                for (int j = 0; j < 1000; j++) {
                    atomDemo.add();
                }
            },String.valueOf(i)).start();
        }

        //等待上面20个线程执行完毕,main输出sum的值
        while(Thread.activeCount()>2){ //最小两个线程,main,gc
            //如果线程数大于2,main线程让出执行权
            Thread.yield();
        }

        //main线程输出sum的值
        System.out.println("20个线程,每个线程加1000次,理论结果=20000?而实际结果="+atomDemo.sum);
    }

 运行结果:

1.5 volatile不保证原子性理论解释

1.6 volatile不保证原子性问题解决

1.7 volatile指令重排序案例1

1.8 volatile指令重排序案例2

1.9 单利模式在多线环境下存在的安全性问题

1.10 单例模式volatile分析

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值