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 = false

fun 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 = false

fun 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;
    }
}

  • 32
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值