-
Java高并发4-解析volatile关键字
一、volatile解析
1.计算机内部的内存模型
- 我们知道计算机内部含有内存和CPU,那么在进行计算的时候,内存读写还是太慢了,因此在内存和CPU之间还是有一个缓存cache
- 那么我们知道如果是一个共享变量的话,就会导致,内存中变量和缓存中的变量由于多线程同步不及时,也就是说,一个线程中的缓存还没来的急写入内存,此时有可能在内存中的变量被其他线程读取了。
- 解决这个问题可以:1)通过在总线加LOCK#锁的方式;2)通过缓存一致性协议
-
第一种方式效率低下,很难实现多线程;第二种方式有一个著名MSI协议,就是指当缓存写入内存之后,会向其他线程发出信号,共享变量数值已变,如果需要的话,需要重新更新。
2.并发编程的三个概念
- 原子性:一组操作要么全部执行成功,要么全部执行失败,不存在部分成功,部分失败的情况
- 可见性:一个线程对共享变量在缓存中已经更改,但是还没有来得及写入内存,此时又有一个线程访问了该变量,那么就会出现数据不一致
- 有序性:各个语句的执行其实不一定按照从上到下的顺序,但是最后个结果一定和按从上到下执行的结果一致,因为如果语句不相干,先执行哪个后执行哪个无所谓,但是语句相干,就会按照从上到下的正常顺序。
3.Java中的内存模型
- 与计算机的内存模型相似,也会有三大特性
- 原子性,这个特性,可以通过synchronnized和lock来保证
- 可见性,Java通过violate来保证,如果共享变量是有violate来修饰那么就是保证,如果改变了它的值就能保证绝对会写入内存之后,别的线程才会调用。
- 有序性,Java中存在happens-before原则来保证有序性,如果两条语句通过该原则仍然不能推断先后执行的先后顺序,那么这两个语句是不是有序的,谁先执行都说不准。
- 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作
- (1)程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作
- (2)锁定规则:一个unLock操作先行发生于后面对同一个锁额lock操作
- (3)volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作
- (4)传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C
- (5)线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作
- (6)线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生
- (7)线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行
- (8)对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始
4.下面我们举个例子
package com.ruigege.threadFoundation1;
public class TestViolate {
public volatile int inc =1;
public static void main(String[] args) {
TestViolate test = new TestViolate();
for(int i=0;i<10;i++) {
//创建十个线程,对inc进行自增操作
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
for(int j=0;j<10000;j++) {
test.inc++;
}
}
});
thread.start();
}
while(Thread.activeCount()>1) {
Thread.yield();//如果存在还没有结束的线程,就需要尽量让出CPU供它们运行
}
System.out.println(test.inc);
}
}
-
我们将这段代码运行三次
- 这结果和我们预想的不一样,为什么呢?下次再说
二、源码:
- 所在包:com.ruigege.ThreadFoundation1
-
https://github.com/ruigege66/ConcurrentJava
- CSDN:https://blog.csdn.net/weixin_44630050
- 博客园:https://www.cnblogs.com/ruigege0000/
出 处:https://www.cnblogs.com/ruigege0000/p/13923531.html
最新更新
python爬虫及其可视化
使用python爬取豆瓣电影短评评论内容
nodejs爬虫
Python正则表达式完全指南
爬取豆瓣Top250图书数据
shp 地图文件批量添加字段
爬虫小试牛刀(爬取学校通知公告)
【python基础】函数-初识函数
【python基础】函数-返回值
HTTP请求:requests模块基础使用必知必会
SQL SERVER中递归
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
uniapp/H5 获取手机桌面壁纸 (静态壁纸)
[前端] DNS解析与优化
为什么在js中需要添加addEventListener()?
JS模块化系统
js通过Object.defineProperty() 定义和控制对象
这是目前我见过最好的跨域解决方案!
减少回流与重绘
减少回流与重绘
如何使用KrpanoToolJS在浏览器切图
performance.now() 与 Date.now() 对比