当前位置: 首页 > news >正文

volatitle-线程并发-小白一文速通

目录

简而言之

专业术语解释

1、可见性

原理简介

原理图解

其他方式

2、原子性

原理简介

结合实例分析

3、有序性

原理简介

线程安全问题

Volatile效果

1、保证可见性

2、保证有序性

3、无法保证原子性

Volatile底层的实现机制(重点掌握)

经典案例

Java双重检验锁的单例模式


简而言之

volatile修饰的共享变量特性:

  • 保证多线程对该变量操作的内存可见性
  • 禁止指令重排序

专业术语解释

1、可见性

原理简介

Java虚拟机(JVM)定义Java内存模型(JMM)来保证JAVA程序在所有平台具有相同内存访问效果

Java内存模型(JMM)规定所有变量存在主存中,各线程只能通过各自的工作内存访问、获取

出现问题:多线程执行i++时,可能线程A获取i为1,线程B获取i为2,因为缓存不一致!!!

当用volatile修饰,各线程对它修改会立刻刷新到主存,各线程都能读取到最新数据,即可见性

原理图解

其他方式

  • synchronized
  • Lock

线程释放锁之前,会将共享变量值(被上面两个修饰的变量)刷新到主存


2、原子性

原理简介

基本数据类型的读取和赋值操作 不可中断 ,要么不执行,要么执行完

结合实例分析

i = 2;
j = i;
i++;
i = i + 1;

i = 2 ,为原子性操作。属于基本数据类型int型赋值语句

j = i 不符合原子性。分为读取 i 的值和为 j 赋值两步 

i++和i = i+1 等效,都不符合原子性。分为三步,先读取 i 的值,再加1,最后 i 值写回主存


3、有序性

原理简介

Java内存模型(JMM)允许编译器和处理器在不影响程序执行结果前提下可以重排序语句

var pi = 3.14    //A
var r = 1        //B
var s= pi*r*r    //C

比如正常从上至下原则是 A->B->C

编译后可以是 B->A->C,因为AB相互不依赖

但是C不可以倒反天罡在AB二者之前执行

线程安全问题

var a = 0
var flag = falsefun write() {a = 2;             flag = true     
}fun multiply() {if (flag) {        val ret:int = a * a}}

解读:这里线程1执行write方法,write方法两个指令重排序了,线程2执行multiply方法。

由于重排序,write没执行完,先执行了Flag语句,结果线程2开始执行,运行结果也错误

此时可以为共享变量flag加volatile修饰,禁止重排序!!!


Volatile效果

var a = 0
volatile var flag = falsefun write() {a = 2;             flag = true     
}fun multiply() {if (flag) {        val ret:int = a * a}    
}

假设线程1调用write(),线程2调用multiply()由于flag在两个方法都有依赖,属于共享变量

1、保证可见性

当一个变量被声明为 volatile 时,

线程在每次使用变量的时候都会直接从主内存中读取,而不是从自己的工作内存中读取;=。

volatile确保在线程1中flag值更新立刻刷新主存,线程2也从主存随时读取最新flag

2、保证有序性

通过一种同步机制——内存屏障,阻止屏障两侧指令被重排序,确保变量的读写顺序按照代码逻辑顺序,维持多线程环境中操作的有序性。

3、无法保证原子性

只是对单个volatile变量的读/写具有原子性

但是,volatile 关键字的复合操作(如自增、自减等操作)无原子性。

在多线程环境中,i++,i--无原子性

import kotlin.concurrent.thread  class VolatileExample {  @Volatile  private var count = 0  fun increment() {  count++ // 这个操作在Kotlin中也不是原子性的  }  fun getCount(): Int {  return count  }  companion object {  @JvmStatic  fun main(args: Array<String>) {  val example = VolatileExample()  val t1 = thread {  repeat(1000) {  example.increment()  }  }  val t2 = thread {  repeat(1000) {  example.increment()  }  }  t1.join()  t2.join()  println("Final count is: ${example.getCount()}")  }  }  
}

Volatile底层的实现机制(重点掌握)

  • 生成汇编代码后,加入的volatile关键字会多出lock前缀
  • lock相当于内存屏障
  • 屏障作用是重排序是,阻止后面指令重排序到屏障之前

经典案例

Java双重检验锁的单例模式

class Singleton{private volatile static Singleton instance = null;private Singleton(){}public static Singleton getInstance(){if(instance == null){synchronized(Singleton.class){if(instance == null)instance = new Singleton();}}return instance;}
}


http://www.mrgr.cn/news/1661.html

相关文章:

  • 智能Java开发工具IntelliJ IDEA v2024.2全新发布——更好支持Spring开发
  • 面试官:谈谈你对Shadow DOM的理解
  • MySQL 数据库经验总结
  • 想学接口测试,不知道那个工具适合?
  • 【C++ 面试 - 面向对象】每日 3 题(二)
  • 强!小目标检测全新突破!检测速度快10倍,GPU使用减少73.4%
  • 使用RKNN在Orange Pi 5 (RK3588s) 上部署推理PPO深度学习模型
  • 微前端架构下的单页应用实现策略
  • C++设计模式简介
  • python人工智能002:jupyter基本使用
  • 读高性能MySQL(第4版)笔记01_MySQL架构(上)
  • 石油采集行业应用解决方案
  • 【杂乱笔记】图论
  • 【Unity开发】避免重复加载场景资产AB(AssetBundle)包的优化
  • FPGA实现HDMI传输(一)
  • 我叫:堆排序【JAVA】
  • 掌握PyTorch的加权随机采样:WeightedRandomSampler全解析
  • Android12 呼出电话呼叫中挂断后铃声继续响一下的处理
  • 第132天:内网安全-横向移动Exchange服务有账户CVE漏洞无账户口令爆破
  • SpringCloud之服务提供与调用