JVM学习笔记——内存模型篇在本系列内容中我们会对JVM做一个系统的学习,本片将会介绍JVM的内存模型部分
我们会分为以下几部分进行介绍:
- 内存模型
- 乐观锁与悲观锁
- synchronized优化
内存模型简介首先我们来简单介绍一下内存模型:
- 内存模型,全称Java Memory Model,也就是我们常说的JMM
- JMM中定义了一套在多线程读写共享数据时 , 对数据的可见性,有序性和原子性的规则和保障
原子性介绍我们首先介绍一下原子性:
- 原子性是指将一系列操作规划为一个操作,全称不可分离进行
- 我们在单线程下不会出现原子性的问题
- 但在多线程下,每条语句的实际底层操作不止一步 , 可能就会导致操作错误
package cn.itcast.jvm.t4.avo;// 在下述操作中,我们分别创造两个线程,分别执行i++和i--50000次 , 按正常逻辑来说结果应该为0public class Demo4_1 {static int i = 0;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int j = 0; j < 50000; j++) {i++;}});Thread t2 = new Thread(() -> {for (int j = 0; j < 50000; j++) {i--;}});t1.start();t2.start();t1.join();t2.join();System.out.println(i);}}
但我们多次运行的结果如下:// 每次结果均不相同302-9860
原子性分析首先我们分别给出i++和i--的底层操作:// i++getstatic i// 获取静态变量i的值iconst_1// 准备常量1iadd// 加法putstatic i// 将修改后的值存入静态变量i// i--getstatic i// 获取静态变量i的值iconst_1// 准备常量1isub// 减法putstatic i// 将修改后的值存入静态变量i
我们的原子性分为两种情况:- 单线程情况下:我们的顺序肯定是按照正常顺序来执行
- 多线程情况下:我们i++的操作按顺序执行 , i--的操作按顺序执行,但两者操作可能会交替进行
// 单线程// 假设i的初始值为0getstatic i// 线程1-获取静态变量i的值 线程内i=0iconst_1// 线程1-准备常量1iadd// 线程1-自增 线程内i=1putstatic i// 线程1-将修改后的值存入静态变量i 静态变量i=1getstatic i// 线程1-获取静态变量i的值 线程内i=1iconst_1// 线程1-准备常量1isub// 线程1-自减 线程内i=0putstatic i// 线程1-将修改后的值存入静态变量i 静态变量i=0
然后我们分别给出多线程情况下多种结果的底层代码:// 多线程// 负数// 假设i的初始值为0getstatic i// 线程1-获取静态变量i的值 线程内i=0getstatic i// 线程2-获取静态变量i的值 线程内i=0iconst_1// 线程1-准备常量1iadd// 线程1-自增 线程内i=1putstatic i// 线程1-将修改后的值存入静态变量i 静态变量i=1iconst_1// 线程2-准备常量1isub// 线程2-自减 线程内i=-1putstatic i// 线程2-将修改后的值存入静态变量i 静态变量i=-1// 正数// 假设i的初始值为0getstatic i// 线程1-获取静态变量i的值 线程内i=0getstatic i// 线程2-获取静态变量i的值 线程内i=0iconst_1// 线程1-准备常量1iadd// 线程1-自增 线程内i=1iconst_1// 线程2-准备常量1isub// 线程2-自减 线程内i=-1putstatic i// 线程2-将修改后的值存入静态变量i 静态变量i=-1putstatic i// 线程1-将修改后的值存入静态变量i 静态变量i=1
原子性实现那么我们该如何实现多线程的原子性:- 使用synchronized(同步关键字)
synchronized( 对象 ) { // 要作为原子操作代码}
我们如果要实现之前的代码,我们可以将代码修改为:package cn.itcast.jvm.t4.avo;public class Demo4_1 {// 这里的i应该被多线程共用,设为静态变量static int i = 0;// 这里是Obj对象,我们设置它为锁,注意两个线程中的synchronized所对应的锁应该是同一个对象(锁)static Object obj = new Object();public static void main(String[] args) throws InterruptedException {// 采用synchronized设置锁实现原子性,这样i++操作就会完整进行Thread t1 = new Thread(() -> {synchronized (obj) {for (int j = 0; j < 50000; j++) {i++;}}});Thread t2 = new Thread(() -> {// 采用synchronized设置锁实现原子性,这样i--操作就会完整进行synchronized (obj) {for (int j = 0; j < 50000; j++) {i--;}}});t1.start();t2.start();t1.join();t2.join();// 我们的输出结果自然是0了~System.out.println(i);}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Linux学习环境搭建流程
- Archlinux + Dwm 配置流程
- 关于入门深度学习mnist数据集前向计算的记录
- 四十 Java开发学习----MyBatisPlus入门案例与简介
- jvm双亲委派机制详解
- FHE学习笔记 #2 多项式环
- django-environ学习
- 万字详解JVM,让你一文吃透
- 论文笔记 - GRAD-MATCH: A Gradient Matching Based Data Subset Selection For Efficient Learning
- 论文笔记 - SIMILAR: Submodular Information Measures Based Active Learning In Realistic Scenarios