聊聊jvm中内存模型的坑

jvm线程的内存模型

看图,简单来说线程中操作的变量是副本。在并发情况下,如果数据发生变更,副本的数据就变为脏数据。这个时候就会有并发问题。

参考:https://www.cnblogs.com/yeyang/p/12580682.html

怎么解决并发问题

解决的方案有两种:

1. 加排它锁,将并发的操作变成串行的操作。

2. 无锁方案:通过cas操作,并保证如果变量发生变更,其它的线程需要立即知道。(java的原子操作类使用的就是这种方案:cas+volatile)

volatile关键字实战

先说结论, 从实战效果上看,whlie循环中的变量是无法感知到其它线程对变量的修改的,但是再加上volatile关键字修饰之后可以感知到。而for循环中即使不加关键字volatile修饰,也是可以感知到变化的。这点在写代码时特别要注意。

测试代码如下:

//结论: while循环的写法,可以反应出变量的可见性问题,for循环的写法不能反应可见性问题
public class Demo {
    static AtomicLong atomicLong = new AtomicLong(0);
    public static int a = 0;
    //public volatile static int a = 0;
    @SneakyThrows
    public static void main(String[] args) {
        test03();
    }

    //while循环在变量不加volatile关键字修饰时,无法感知到变量变化。
    public static void test02() throws InterruptedException {
        Thread thread01 = new Thread(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                System.out.println("test01:"+a);
                while (true) {
                    if (a >= 2) {
                        System.out.println("我变了");
                    }
                }
            }
        });
        thread01.start();

        Thread thread02 = new Thread(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                for(int i=0;i<2;i++){
                    a++;
                    System.out.println("test02:" + a);
                }
            }
        });
        thread02.start();
        Thread.sleep(10000);
    }

    //for循环即使不加volatile关键字修饰,也可以感知到变量变化。
    public static void test03() throws InterruptedException {
        Thread thread01 = new Thread(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                System.out.println("test01:"+a);
                for(int i=0; i<10000; i++){
                    if (i==0) {
                        Thread.sleep(1000);
                    }
                    if (a >= 2) {
                        System.out.println("我变了");
                    }
                }
            }
        });
        thread01.start();

        Thread thread02 = new Thread(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                for(int i=0;i<2;i++){
                    a++;
                    System.out.println("test02:" + a);
                }
            }
        });
        thread02.start();
        Thread.sleep(10000);
    }
}

相关推荐

最近更新

  1. TCP协议是安全的吗?

    2024-04-14 15:42:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-14 15:42:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-14 15:42:03       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-14 15:42:03       20 阅读

热门阅读

  1. 【算法】Cordic算法的原理及matlab/verilog应用

    2024-04-14 15:42:03       14 阅读
  2. 题目:输入3个数a,b,c,按大小顺序输出。

    2024-04-14 15:42:03       13 阅读
  3. 谷歌翻译接口-国内使用在线翻译API

    2024-04-14 15:42:03       14 阅读
  4. 云服务器&宝塔&ssh:tabby 部署SpringBoot项目

    2024-04-14 15:42:03       38 阅读
  5. 《高等数学》笔记

    2024-04-14 15:42:03       20 阅读
  6. 两分钟启动一个flask应用

    2024-04-14 15:42:03       17 阅读
  7. 使用requests包批量下载网页图片

    2024-04-14 15:42:03       17 阅读
  8. Android 日历-周视图

    2024-04-14 15:42:03       18 阅读