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++写
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
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
原文地址:https://www.cnblogs.com/cfas/p/15110510.html
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- sortable.js——Vue 数据更新问题
- 【项目实战】环境搭建
- TensorFlow2.X学习笔记(5)--TensorFlow中阶API之数据管道
- TensorFlow2.X学习笔记(4)--TensorFlow低阶API之AutoGraph相关研究
- TensorFlow2.X学习笔记(3)--TensorFlow低阶API之张量
- TensorFlow2.X学习笔记(2)--TensorFlow的层次结构介绍
- 深入浅出 Vue 中的 key 值
- TensorFlow2.X学习笔记(1)--TensorFlow核心概念
- 【项目实战】ODS 层创建&数据接入
- webpack3 升级到 webpack4 小记
- BigData-Apache HBase数据库
- Tungsten Fabric知识库丨这里有18个TF补丁程序,建议收藏
- BigData-消息队列框架Apache Kafka入门、原理解析
- BigData--Apache Flume框架
- 【项目实战】DWS 层创建&数据接入