java 并发——volatile
java 并发——volatile
介绍
维基百科: volatile 是一个类型修饰符(type specifier).volatile 的作用是确保本条指令不会因编译器的优化而省略,且要求每次直接读值。
看了上面的话感觉不是那么的好理解,因为 volatile 关键字是和 java 内存模型 JMM(java memory model)是息息相关的,所以在介绍 volatile 之前我们先来看一下 java 内存模型.
内存模型概念
我们的程序执行指令是从 cpu 中执行的,程序执行肯定和数据脱不开干系,这些数据肯定都是在计算机的物理内存中进行.但是随着 cpu 越来越牛x,而内存的话就会显得相对来说不那么效率,这就导致每次 cpu 执行导致每次操作数据都要去内存操作,这样就很耗费时间.
由于计算机的存储设备与 cpu 的运算速度有几个数量级的差距,所以现代计算机系统都不得不加入一层读写速度尽可能接近处理器运算速度的高速缓存(Cache)来作为内存与处理器之间的缓冲:将运算需要使用到的数据复制到缓存中,让运算能快速进行,当运算结束后再从缓存同步回内存之中,这样处理器就无须等待缓慢的内存读写了。
解决了效率的问题但是随之而来也就出现了新的问题需要解决——缓存一致性.因为在程序运行期间会将运行所需要的数据从内存中复制一份到 cpu 高速缓存中之后再进行对应的运算,再运算期间数据的读取是从高速缓存直接读取并不会再取读取内存中的数据了,只有再运算结果出来后才会将数据重新刷新会到内存中.
解决方法:
- 通过数据总线加锁的方式 LOCK.(但是这样效率极为低下不建议)
- 缓存一致性协议.(确保每个缓存中使用的共享变量的副本是一致的。其核心思想如下:当某个 cpu 在写数据时,如果发现操作的变量是共享变量,则会通知其他 cpu 告知该变量的缓存行是无效的,因此其他 cpu 在读取该变量时,发现其无效会重新从主存中加载数据。)
java 内存模型
java 内存模型规定了所有的变量都存储在主内存中,每条运行的线程还是各自的工作内存区域,线程运行的是会从主内存中将变量从主内存拷贝一份到自己的工作内存,线程对变量的所有操作都必须在工作内存中进行,而不是直接操作主内存,不同的线程之间工作内线是不会共享的。直到线程运算结束将值刷新到主内存后,其他线程才可见(可见性).
先举一个场景
public class Test {
static int i = 1;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
i++;
});
Thread t2 = new Thread(() -> {
i++;
});
t1.start();
t2.start();
System.out.println(Test.i);
}
}
这个场景输出有可能不是 3,两个线程从主存中读取 i 的值(1)到各自的高速缓存中,然后线程 t1 执行 +1 操作并将结果写入高速缓存中,最后写入主存中,此时主存 i==2,线程 t2 做同样的操作,但是线程 t2 的工作内存 i 的值有可能还是 1但是现在主存中的 i 应该是 2。所以 t2 执行完最终结果为 2 再将 2 刷新入主内存中而并不是 3。这种现象就是缓存一致性问题。
我们在并发编程中都会知道这几个概念:
- 原子性: 即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行.
- 可见性: 可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值.
- 有序性: 即程序执行的顺序按照代码的先后顺序执行.多线程环境下有影响.
volatile
我们在回顾一下一开始介绍 volatile 的话: volatile 是一个类型修饰符(type specifier).volatile 的作用是确保本条指令不会因编译器的优化而省略,且要求每次直接读值。
看了上面的话只表达出了一点: 可见性.其实还有一个作用就是禁止指令重排序(重排序后面会单独说).所以使用 volatile 关键字来修饰变量就不会存在缓存一致性的问题了.现在我们简单说下 volatile 是怎么禁止指令重排序的: 加入 volatile关键字和没有加入 volatile 关键字时所生成的汇编代码发现,加入 volatile 关键字时,会多出一个 lock 前缀指令。lock 前缀指令其实就相当于一个内存屏障。内存屏障是一组处理指令,用来实现对内存操作的顺序限制。
volatile 就暂且到这里了,感兴趣的朋友可以继续深入研究.volatile 相对于 synchronized 稍微轻量些,在某些场合它可以替代 synchronized,但是又不能完全取代 synchronized.感谢观看!
java 并发——volatile的更多相关文章
- Java并发-volatile的原理及用法
Java并发-volatile的原理及用法 volatile属性:可见性.保证有序性.不保证原子性.一.volatile可见性 在Java的内存中所有的变量都存在主内存中,每个线程有单独CPU缓存内存 ...
- Java并发——volatile的原理
111 Java并发——volatile的原理
- Java 并发 —— volatile 关键字
volatile 修饰变量等于向编译器传达如下两层含义: 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的. 禁止进行指令重排序. volat ...
- JAVA并发--volatile
学过计算机组成原理的一定知道,为了解决内存速度跟不上CPU速度这个问题,在CPU的设计中加入了缓存机制,缓存的速度介于CPU和主存之间.在进行运算的时候,CPU将需要的数据映射一份在缓存中,然后直接操 ...
- Java并发--volatile关键字
一.volatile的实现原理 synchronized是阻塞式同步,在线程竞争激烈的情况下会升级为重量级锁,而volatile就可以说是JVM提供的最轻量级的同步机制.JMM告诉我们,各个线程会将共 ...
- Java并发--volatile详情
volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以 ...
- Java并发——volatile关键字
什么是内存可见性? 这里就要提一下JMM(Java内存模型).当线程在运行的时候,并不是直接直接修改电脑主内存中的变量的值.线程间通讯也不是直接把一个线程的变量的值传给另一个线程,让其刷新变量.下面是 ...
- Java并发——volatile关键字的使用
volatile关键字的使用volatile关键字原理适合使用volatile关键字的情况当且仅当满足以下所有条件时,才==应该==使用volatile关键字:volatile关键字的作用volati ...
- Java并发——volatile
CPU的内存模型如下:
随机推荐
- 用原生js写小游戏--Flappy Bird
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 学习contiki需要知道的一些概念和注意事项
概念: 1.宏:所谓宏,就是一些命令组织在一起,作为一个单独命令完成一个特定任务.Microsoft Word中对宏定义为:“宏就是能组织到一起作为一独立的命令使用的一系列word命令,它能使日常工作 ...
- 树的直径(BFS)
][];];];];,,;vis[i]=; ; j <= n ; j++){ ){;//标记 res[j]=res[root]+; ; i <= n- ; i++){; data[b][a ...
- Rikka with Nickname (简单题)
Rikka with Nickname 链接:https://www.nowcoder.com/acm/contest/148/J来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒空间限制:C/ ...
- Python3学习笔记(MOOC)
文本进度条实例 #!/usr/bin/env python3 import time #for i in range(101): # print ("\r{:3.0f}%".for ...
- 【记录】Mybatis Generator生成数据对象Date/TimeStamp 查询时间格式化
Mybatis Generator是很好的工具帮助我们生成表映射关联代码,最近博主遇到一个问题,找了很久才解决, 就是用Mybatis Generator生成实体类的时候,Date 时间无法格式化输出 ...
- JDBC、ibatis(mybatis)、Hibernate有什么不同?
①JDBC编程流程固定,同时将sql语句和java代码混在了一起,经常需要拼凑sql语句,细节很繁琐: ②ibatis(mybatis)它不完全是一个ORM框架,因为MyBatis需要程序员自己编写S ...
- 59th python下graphviz安装 砖
原文 摘录 感谢分享: https://www.cnblogs.com/liusx0303/p/9155305.html 参考链接:https://blog.csdn.net/u01325041 ...
- oracle死锁查询
select sess.sid ||','|| sess.serial#, lo.oracle_username, lo.os_user_name, ao.object_name, lo.locked ...
- delphi 删除文件夹里面的所有文件
1.新增一个函数 function TForm1.DelDirAll(aDir: string): Boolean;varvSearch: TSearchRec;vRet: integer;vKey: ...