Volatile浅析

本文详细解析了volatile关键字的作用原理,包括其可见性和原子性方面的特性。通过示例代码展示了volatile在单个操作与复合操作中的表现差异,并探讨了如何正确使用volatile以确保线程安全。

volatile仅仅用来保证该变量对所有线程的可见性,但不保证原子性。

一开始接触到volatile,百度或者书本上都会说这句话.前半句话的意思是:在volatile读之前,总能看到任意线程对这个变量的最后写入

后半句不保证原子性指的是:不保证符合操作(getAndOperate)的原子性,但是对于volatile变量的读/写,即单个操作是具有原子性的

不要将volatile用在getAndOperate场合(这种场合不原子,需要再加锁),仅仅set或者get的场景是适合volatile的

那么问题来了:下列哪些算是单操作,哪些算是复合操作?
x = 10;         //语句1
y = x;         //语句2
x++;           //语句3
x = x + 1;     //语句4
只有语句1是单操作(JVM会保证原子性,要么赋值成功,要么不成功),其他三个都是复合操作,即先读取x的值,+1操作,最后赋值。
对于64位long/double型变量的读/写,从JSR-133内存模型开始(即从JDK5开始)仅仅只允许把一个64位long/double型变量的写操作拆分为两个32位的写操作来执行,但任意读操作必须要在单个读事物中执行。(来自java并发编程艺术)

volatile关键字的两层写读语义

volatile 写语义:当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存。即在写volatile变量之前,会保证所有之前的事已经发生,并且任何更新过的共享变量也是可见的(这句话也可以这样理解,保证volatile写之前的操作不会重排序到写之后)。

volatile读语义:当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效,线程会从主内存中读取共享变量。(这句话应该怎么理解捏?
我是这样理解的:在读取volatile变量之前,本地内存的值无效(如果有多个处理器,其他处理器的缓存值无效),这意味着读取volatile变量以后的读取都在主内存进行.如果变量x没有volatile修饰,有可能变量x和后面的操作重排序,这样的话就保证不了x的可见性。

下面通过代码理解一下voliate特性:

public class VolatileFeatureExample {

    volatile long v1  = 0L;

    /**
     * 单个变量的写
     * 等价于 public void synchronized set(long)
     * @param l
     */
    public void set(long l){
        v1=l;
    }

    /**
     * 复合操作
     * 等价于:
     *   long temp =get();
     *   temp+=1L;
     *   set(temp);
     */
    public void getAndIncrement(){//复合操作 等价于
        v1++;
    }

    /**
     * 单个变量的写
     * 等价于 public long synchronized get(long)
     * @return
     */
    public long get(){
        return v1;
    }
}
由上面代码可以看出,voliate单个操作相当于synchronized,但是复合操作,仅仅只能保证写的时候(set(temp))刷新到主内存的值是最新的,但是不能保证这两行代码是原子操作的,这就解释了为什么volalite在复合操作上没有原子性。如果大伙觉得这边我讲得不明白,木有事~~~~~下面经典的代码等着哈~
long temp =get();
temp+=1L;

volatile保证原子性吗?

如果上面的分析看懂了,这个小节就可以略过了~~
请看下面例子:
//inc volatile变量
    public volatile int inc = 0;
    //自增操作
    public void increase() {
        inc++;
    }

    public static void main(String[] args) {
        final JMM test = new JMM();
        //10个线程,每个线程对inc自增1000次
        for(int i=0;i<10;i++){
            new Thread(){
                public void run() {
                    for(int j=0;j<1000;j++) {
                        test.increase();

                    }
                };
            }.start();
        }
        System.out.println(test.inc);
    }
output:9000
分析:线程A读取i的值到本地内存之后,还没来得及+1操作(因为volatile保证原子性操作),线程B读取i的值到本地内存,然后A与B线程各自对i+1,同时写入主内存,那么主内存的值为2,而不是3.

将自增操作代码增加synchronized修饰即可保证原子性:
public synchronized void  increase() {
        inc++;
    }

后记

自己也是最近刚看的书,综合书本和几个blog,总结了一下看法,献丑~~~如果有错误,麻烦指正一下哈~~
现在的问题的是:有些锁的源码用到了volatile,为什么这些锁能够保证原子性~~各位等着哈,等我学习完,也会写出来了(捂脸~~)



标题基于Python的自主学习系统后端设计与实现AI更换标题第1章引言介绍自主学习系统的研究背景、意义、现状以及本文的研究方法和创新点。1.1研究背景与意义阐述自主学习系统在教育技术领域的重要性和应用价值。1.2国内外研究现状分析国内外在自主学习系统后端技术方面的研究进展。1.3研究方法与创新点概述本文采用Python技术栈的设计方法和系统创新点。第2章相关理论与技术总结自主学习系统后端开发的相关理论和技术基础。2.1自主学习系统理论阐述自主学习系统的定义、特征和理论基础。2.2Python后端技术栈介绍DjangoFlask等Python后端框架及其适用场景。2.3数据库技术讨论关系型和非关系型数据库在系统中的应用方案。第3章系统设计与实现详细介绍自主学习系统后端的设计方案和实现过程。3.1系统架构设计提出基于微服务的系统架构设计方案。3.2核心模块设计详细说明用户管理、学习资源管理、进度跟踪等核心模块设计。3.3关键技术实现阐述个性化推荐算法、学习行为分析等关键技术的实现。第4章系统测试与评估对系统进行功能测试和性能评估。4.1测试环境与方法介绍测试环境配置和采用的测试方法。4.2功能测试结果展示各功能模块的测试结果和问题修复情况。4.3性能评估分析分析系统在高并发等场景下的性能表现。第5章结论与展望总结研究成果并提出未来改进方向。5.1研究结论概括系统设计的主要成果和技术创新。5.2未来展望指出系统局限性并提出后续优化方向。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值