JUC(8)JMM
文章目录
1、JMM
Volatile是java虚拟机提供轻量级的同步机制
- 1、保证可见性
- 2、不保证原子性
- 3、禁止指令重排
什么是JMM
java内存模型,不存在的东西,概念、约定
- 1、线程解锁前,必须把共享变量立刻刷回主存(线程将主存中的变量复制一份到线程中)
- 2、线程加锁前,必须读取主存中的最新值到工作内存中
- 3、加锁和读锁是同一把锁

两个线程同时执行,假如一个线程修改变量、另外一个线程没有及时得到,就会出错。

内存交互操作
内存交互操作有8种,虚拟机实现必须保证每一个操作都是原子的,不可在分的(对于double和long类型的变量来说,load、store、read和write操作在某些平台上允许例外)
- lock (锁定):作用于主内存的变量,把一个变量标识为线程独占状态
- unlock (解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
- read (读取):作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用
- load (载入):作用于工作内存的变量,它把read操作从主存中变量放入工作内存中
- u- se (使用):作用于工作内存中的变量,它把工作内存中的变量传输给执行引擎,每当虚拟机遇到一个需要使用到变量的值,就会使用到这个指令
- assign (赋值):作用于工作内存中的变量,它把一个从执行引擎中接受到的值放入工作内存的变量副本中
- store (存储):作用于主内存中的变量,它把一个从工作内存中一个变量的值传送到主内存中,以便后续的write使用
- write (写入):作用于主内存中的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中
JMM对这八种指令的使用,制定了如下规则:
- 不允许read和load、store和write操作之一单独出现。即使用了read必须load,使用了store必须write
- 不允许线程丢弃他最近的assign操作,即工作变量的数据改变了之后,必须告知主存
不允许一个线程将没有assign的数据从工作内存同步回主内存 - 一个新的变量必须在主内存中诞生,不允许工作内存直接使用一个未被初始化的变量。就是怼变量实施use、store操作之前,必须经过assign和load操作
- 一个变量同一时间只有一个线程能对其进行lock。多次lock后,必须执行相同次数的unlock才能解锁
- 如果对一个变量进行lock操作,会清空所有工作内存中此变量的值,在执行引擎使用这个变量前,必须重新load或assign操作初始化变量的值
- 如果一个变量没有被lock,就不能对其进行unlock操作。也不能unlock一个被其他线程锁住的变量
- 对一个变量进行unlock操作之前,必须把此变量同步回主内存
举例子
package com.jmm;
import java.util.concurrent.TimeUnit;
public class JMMDemo {
private static int num = 0;
public static void main(String[] args) {
new Thread(()->{//线程1对主内存的变化不知道的
while (num == 0){
}
}).start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
num =1;
System.out.println(num);
}
}
测试结果

2、volatile
保证可见性
private volatile static int num = 0;
测试结果:程序立刻停止

不保证原子性
package com.jmm;
/**
* 不保证原子性
*/
public class VolatileDemo {
private volatile static int num = 0;
public static void add(){
num ++;
}
public static void main(String[] args) {
for (int i = 0; i < 200; i++) {
new Thread(()->{
for (int j = 0; j < 1000; j++) {
add();
}
}).start();
}
while(Thread.activeCount() > 2){
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+" " +num);
}
}
测试结果

如果不加lock和synchronized,怎样保证原子性
使用原子类



测试结果

指令重排
什么是指令重排:你写的程序,计算机并不是按照你写的那样去执行的
volatile可以避免指令重排
volatile是可以保持可见性,不能保证原子性,由于内存屏障,可以保证避免指令重排的现象
3、单例模式
饿汉式
package com.single;
/**
* 饿汉式单例
*/
public class HungrySingle {
private HungrySingle(){}
private final static HungrySingle HUNGRY_SINGLE = new HungrySingle();
public static HungrySingle getInstance(){
return HUNGRY_SINGLE;
}
}
懒汉式
package com.single;
/**
* 懒汉式单例
*/
public class LazySingle {
private LazySingle(){
System.out.println(Thread.currentThread().getName()+"ok");
}
private volatile static LazySingle lazySingle;
/**
*双重检测锁模式的 懒汉式单例 DCL懒汉式
*/
public static LazySingle getInstance(){
if(lazySingle == null){
synchronized (LazySingle.class){
if(lazySingle == null){
lazySingle = new LazySingle();
/**
* 1、分配内存空间
* 2、执行构造方法,初始化对象
* 3、把这个对象指向这个空间
*/
}
}
}
return lazySingle;
}
//多线程并发
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
getInstance();
}).start();
}
}
}
JUC(8)JMM的更多相关文章
- java架构之路(多线程)JMM和volatile关键字
说到JMM大家一定很陌生,被我们所熟知的一定是jvm虚拟机,而我们今天讲的JMM和JVM虚拟机没有半毛钱关系,千万不要把JMM的任何事情联想到JVM,把JMM当做一个完全新的事物去理解和认识. 我们先 ...
- Java多线程(7):JUC(上)
您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来- 前面把线程相关的生命周期.关键字.线程池(ThreadPool).ThreadLocal.CAS.锁和AQS都讲完了,现在就剩下怎么来用多线程了 ...
- java架构之路(多线程)JMM和volatile关键字(二)
貌似两个多月没写博客,不知道年前这段时间都去忙了什么. 好久以前写过一次和volatile相关的博客,感觉没写的那么深入吧,这次我们继续说我们的volatile关键字. 复习: 先来简单的复习一遍以前 ...
- JUC(1)线程和进程、并发和并行、线程的状态、lock锁、生产者和消费者问题
1.线程和进程 进程:一个程序,微信.qq...程序的集合.(一个进程包含多个线程,至少包含一个线程.java默认有两个线程:主线程(main).垃圾回收线程(GC) 线程:runnable.thre ...
- JVM学习(七)JMM内存模型
一.什么是JMM 概念:Java内存模型(Java Memory Model ,JMM)就是一种符合内存模型规范的,屏蔽了各种硬件和操作系统的访问差异的,保证了Java程序在各种平台下对内存的访问都能 ...
- Java并发编程的艺术(四)——JMM、重排序、happens-before
什么是JMM JMM就是Java内存模型.目的是为了屏蔽系统和硬件的差异,让同一代码在不同平台下能够达到相同的访问结果.规定了线程和内存之间的关系. 内存划分 JMM规定了内存主要划分为主内存和工作内 ...
- JUC(10)深入理解CAS和ABA
文章目录 1.CAS 2.原子引用解决ABA问题,版本号.修改后,可以看到 1.CAS package com.cas; import java.util.concurrent.atomic.Atom ...
- JUC(7)四大函数式接口
文章目录 1.四大函数式接口(必须掌握) 1.1 function 1.2 Predicate 1.3 Consumer 1.4 Supplier 1.四大函数式接口(必须掌握) 1.lambda表达 ...
- JUC(5)BlockingQueue四组API
1.读写锁ReadWriteLock package com.readlock; import java.util.HashMap; import java.util.Map; /** * ReadW ...
随机推荐
- 梳理清楚springAOP,轻松面向切面编程
不知道大家有没有这样的感觉,平时经常说aop,但是对aop中的一些概念还是模糊,总感觉很飘渺,今天来梳理下关于aop的知识. 一.概念 我们知道现在开发都是spring,讲的最多的也是springAO ...
- Spring源码 10 IOC refresh方法5
本文章基于 Spring 5.3.15 Spring IOC 的核心是 AbstractApplicationContext 的 refresh 方法. 其中一共有 13 个主要方法,这里分析第 5 ...
- 解决linux下U盘变成只读模式
在最近的一个项目里,需要将linux下的些文件拷贝出来.插入U盘后,发现是只读模式. U盘可以写出,不能写入. 折腾了一翻: 最后这样解决的: 将U盘插入到windows下 执行 chkdsk g: ...
- Apple Music 免费试用 2 个月
下载地址:https://redeem.apple.com/am-genshin-impact-2mo-zh-cn?origin=&locale=zh-CN 使用指南 打开链接,点击" ...
- HDU 6222 Heron and His Triangle (pell 方程)
题面(本人翻译) A triangle is a Heron's triangle if it satisfies that the side lengths of it are consecutiv ...
- PHP极简短连接
可用于短连接开发 随便找个PHP空间存放即可 点击查看代码 <html> <head> <meta charset="utf-8"/> < ...
- axios的content-type是自动设置的
一. axios参数的传递方式 首先我们要知道 参数传递一般有两种,一种是 使用 params, 另一种是 data的方式,有很多的时候我们看到的前端代码是这样的. 1. get请求: ...
- 1.6_HTML基础属性
name 属性 name 属性用于指定标签元素的名称. <a> 标签内必须提供 href 或 name 属性. <a name="value"> id 属性 ...
- ELK技术-IK-中文分词器
1.背景 1.1 简介 ES默认的分词器对中文分词并不友好,所以一般会安装中文分词插件,以便能更好的支持中文分词检索. 本例参考文档:<一文教你掌握IK中文分词> 1.2 IK分词器 IK ...
- Linux 破解mysql密码(详细步骤)
当mysql密码忘记时 [root@master ~]# mysql -uroot -p1 mysql: [Warning] Using a password on the command line ...