5.JAVA轻量级线程同步机制:volatile关键字

1.概述

volatile关键字用于修饰共享可变变量,即没有使用final关键字修饰的实例变量或静态变量 ,相应的变量就被称为volatile变量。volatile关键字表示被修饰的变量的值容易变化(即被其他线程更改),因而不稳定。volatile变量的不稳定性意味着对这种变量的读和写操作都必须从高速缓存或者主内存(也是通过高速缓存读取)中读取,以读取变量的相对新值。因此,volatile 变量不会被编译器分配到寄存器进行存储,对volatile变量的读写操作都是内存访问(访问高速缓存相当于主内存)操作 。

2.作用

保障可见性、保障有序性、保障long/double型变量读写操作的原子性。
volatile 关键字在原子性方面仅保障对被修饰的变量的读操作、写操作本身的原子性。如果要保障对volatile变量的赋值操作的原子性,那么这个赋值操作不能涉及任何共享变量(包括被赋值的volatile 变量本身)的访问。
写线程对volatile变量的写操作会产生类似于释放锁的效果。读线程对volatile变量的读操作会产生类似于获得锁的效果。因此,volatile 具有保障有序性可见性的作用。
volatile关键字在可见性方面仅仅是保证读线程能够读取到共享变量的相对新值。对于引用型变量和数组变量, volatile 关键字并不能保证读线程能够读取到相应对象的字段(实例变量、静态变量)、元素的相对新值。

3.典型应用场景

  • 使用volatile变量作为状态标志。在该场景中,应用程序的某个状态由一个线程设置,其他线程会读取该状态并以该状态作为其计算的依据(或者仅仅读取并输出这个状态值)。此时使用volatile变量作为同步机制的好处是一个线程能够“通知”另外一个线程某种事件(例如,网络连接断连之后重新连上)的发生,而这些线程又无须因此而使用锁。从而避免了锁的开销以及相关问题。

  • 使用volatile保障可见性。在该场景中,多个线程共享一个可变状态变量,其中一个线程更新了该变量之后,其他线程在无须加锁的情况下也能够看到该更新 。

  • 使用volatile变量替代锁。volatile关键字并非锁的替代品,但是在一定的条件下它比锁更合适(性能开销小、代码简单)。多个线程共享一组可变状态变量的时候,通常我们需要使用锁来保障对这些变量的更新操作的原子性,以避免产生数据不一致问题。利用volatile变量写操作具有的原子性,我们可以把这一组可变状态变量封装成一个对象,那么对这些状态变量的更新操作就可以通过创建一个新的对象并将该对象引用赋值给相应的引用型变量来实现。在这个过程中,volatile保障了原子性和可见性,从而避免了锁的使用。

  • 使用volatile实现简易版读写锁。在该场景中,读写锁是通过混合使用锁和 volatile变量而实现的,其中锁用于保障共享变量写操作的原子性,volatile变量用于保障共享变量的可见性。因此,与ReentrantReadWriteLock所实现的读
    写锁不同的是,这种简易版读写锁仅涉及一个共享变量并且允许一个线程读取这个共享变量时其他线程可以更新该变量(这是因为读线程并没有加锁)。因此,这种读写锁允许读线程可以读取到共享变量的非最新值。该场景的一个典型例子是实现一个计数器:

    public class Counter{
        private volatile long count;
        public long value(){
            return count;
        }
        public void increment(){
            synchronized(this){
                count++;
            }
        }
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值