• jvm cas java cas 并发编程


    思考一个问题,10个线程对一个变量进行i++赋值1000 结果是什么?

    下边是测试的代码

    package com.hd.jxd;

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;

    public class DemoLock {b
    int i=0;
    public void incr(){
    i++;
    }

    public static void main(String[] args) {
    DemoLock demoLock=new DemoLock();
    for (int i = 0; i <10 ; i++) {
    new Thread(new Runnable() {
    @Override
    public void run() {
    for (int j = 0; j < 1000; j++) {
    demoLock.incr();
    }
    }
    }).start();
    }
    try {
    Thread.sleep(1000);//休息一下等待线程全部执行完在打印不然会执行完一半就没有意思了
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println(demoLock.i);
    }
    }
    代码给你们写好了直接复制粘贴测试一下打印结果为8641是一个小于一万的数(每次测试不一定是这个结果,但是一定小于一万)
    为什么结果小于一万这里就涉及到我们的JVM内存模型

    一,请看下图

    二,然后在看下边这段话

    JVM描述了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这些底层细节并遵守以下规则

    规则1:所有的变量都存储在主内存中(即共享内存)

    规则2:每个线程都有自己独立的工作内存(即本地内存)

    规则3:线程对共享变量的所有操作都必须在自己的工作内存中进行,不能直接从主内存中读写(比如主内存i变量现在是i=9,你t1要把9这个信息拷贝来,然后进行赋值操作不能直接修改主内存,修改好了之后通过“刷新”操作改变主内存的值)

    规则4:不同线程之间无法直接访问其他线程工作内存中的变量,线程之间变量的值传递需要通过主内存来完成(t1不能直接访问t2的值必须经过主内存才可以)

    一,二都看完了,然后我们分析一下,为什么会小于一万

    主内存好比一个大屏幕显示着对i进行i++的操作,1,2,3,4,5,6.....

    假如这时候主内存(大屏幕)显示i=8了,于是t1从主内存拷贝一下8然后赋值到自己的本地内存中,t1理所当然的操作自己的本地内存进行i++。可是这个时候别忘了还有t2,因为t2刚才也在大屏幕看到的是(i=8)然后我也在我本地内存操作i++,并且已经操作完了,不但操作完我还把主内存刷新成i=9了。这个时候t1根本不知道发生了什么(因为规则4原因)于是t1又把主内存刷新了一便还是i=9。这样理解了吧,10个线程每个线程进行1000次,总有几率出现那么几次,这样就造成了为什么数值会小于一万。

    这个问题怎么解决呢,咱先不不管别人我们自己想想假如遇到这个问题咋办

    第一,当大屏幕显示的时候为了避免出错,那么咱这样,当某一个线程拷贝主内存之后其他谁都别操作,就在那里等着,看着。咱一个个来,就不乱了,这种办法就是加锁synchronized,虽说也可以不过效率保证不了,肯定慢对不对。

    第二,你想啊,这样行不行,哥哥我t1从主内存中拷贝数据到本地内存中,对不对,我可不可比较一下,就是我本地内存和主内存在比较一下,我拿到8,我比较一下我t1本地内存和主内存都是8,ok可以没问题,我对其进行修改,如果主内存已经是9了 8!=9那么没办法我只能在拿一次(始终以主内存为准)把本地内存再改成9,然后再比较直到和主内存一致才可以,(底层源码用的是do while循环始终比较)。

    我们平时用的方法只是compareAndSet传2个参数一个expect就是本地内存值,你拷贝主内存之后的值(官方叫期望值一个熊样叫什么无所谓知道它干什么就行),和要进行修改的值update(i++之后的值)。你可能要问了不是还有一个主内存值吗,对这个valueOffset就是主内存的值。OK三个值齐活。

    Java是跑虚拟机的,刚才说的拷贝主内存这事Java可干不了,所以有一个类unsafe它可以拿到主内存数据。

    unsafe.compareAndSwapObject这个方法底层是用C++写

    博主教你手撸JVM 开源项目
    https://github.com/anons-org/nada
    https://gitee.com/grateful/nada

    博主长期对外收徒,欢迎咨询。
    《编程语言设计和实现》《MUD游戏开发》《软件破解和加密》《游戏辅助外挂》《JAVA开发》 以上课程非诚勿扰!



    =================================
    QQ:184377367
    GOLang Q群:6848027
    电子电路入门群 436173132
    C/C++/QT群 1414577
    单片机嵌入式群 306312845
    MUD/LIB/巫师交流群 391486684
    java/springboot/hadoop/ 群 4915800
    WEB前端开发交流群 214737701
    操作系统研发群:15375777
    Linux公社Q群:812742841
    汇编/辅助/破解新手群:755783453
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    asp.net源码坊2015-3月第二周TOP10下载排行
    Asp.Net编程需要学习什么
    面试的同学看过来
    Asp.Net模板生成HTML页面
    毕业设计之房产中介系统源码
    HTML常用状态代码
    Asp.Net毕业设计论文
    网页常用Javascript
    intellij idea使用笔记
    bootstrap-table使用笔记
  • 原文地址:https://www.cnblogs.com/cfas/p/15110510.html
Copyright © 2020-2023  润新知