java volatile关键字使用方法及注意事项

java volatile关键字使用方法及注意事项

什么是volatile关键字

volatile 关键字在多线程程序中起着很重要的作用。当多个线程操作同一个变量时,每个线程将拥有对那个变量的本地缓存拷贝,因此,当某一个线程修改了这个变量的值时,实际上修改的是它本地缓存中的变量值,而不是主内存中的变量值,操作这个变量的其他线程并不知道这个变量的值被改变了。为了避免这种情况,我们可以用 valatile 关键字声明这个变量,用 valatile 声明了这个变量之后,变量将不在本地缓存中保存,而在主内存中保存,当有线程修改了它的值以后,它的更新值将被更新到主内存当中,随后,其他线程也能访问更新后的值。当一个变量被声明为 volatile 后,java 内存模型确保所有使用该变量的线程能看到相同的、一致的值。

volatile关键字使用

首先,创建 VolatileData 类,代码如下:

public class VolatileData {

  //声明为volatile类型
  private volatile int counter = 0;

  /**
  * 返回counter变量的值
  * @return
  */
  public int getCounter() {
    return counter;
  }

  /**
  * 自增counter变量的值
  */
  public void increaseCounter() {
    ++counter;
  }
}

接下来创建 VolatileThread 类,代码如下:

public class VolatileThread extends Thread {
  private final VolatileData volatileData;

  public VolatileThread(VolatileData volatileData) {
    this.volatileData = volatileData;
  }

  /**
  * 调用VolatileData类中的两个方法,进行取值和自增操作
  */
  @Override
  public void run() {
    int oldValue = volatileData.getCounter();
    System.out.println("[Thread " + Thread.currentThread().getId() + "]: Old value = " + oldValue);
    volatileData.increaseCounter();
    int newValue = volatileData.getCounter();
    System.out.println("[Thread " + Thread.currentThread().getId() + "]: New value = " + newValue);
  }
 }

最后,创建 VolatileMain 类,对以上程序进行测试,代码如下:

public class VolatileMain {

  private final static int TOTAL_THREADS = 2;

  public static void main(String[] args) throws InterruptedException {
    VolatileData volatileData = new VolatileData();

    Thread[] threads = new Thread[TOTAL_THREADS];
    for(int i = 0; i < TOTAL_THREADS; ++i)
      threads[i] = new VolatileThread(volatileData);

    //开始读取变量值的操作
    for(int i = 0; i < TOTAL_THREADS; ++i)
      threads[i].start();

    //等待所有线程操作终止
    for(int i = 0; i < TOTAL_THREADS; ++i)
      threads[i].join();
  }
}

在 VolatileMain 类中,使用了两个线程来访问 volatile 变量,输出如下:

[Thread 10]: Old value = 0
[Thread 11]: Old value = 0
[Thread 10]: New value = 1
[Thread 11]: New value = 2

从输出可以看到,首先,两个线程都输出了相同的值,接着,在 increaseCounter 方法被调用之后,两个线程都访问和输出了最新的 volatile 变量的值。

happens-before 关系

在使用 volatile 关键字时,不得不提一下 java 内存模型的 happens-before 关系。happens-before 关系是 java 内存模型的一个重要方面。它建立在两个不同的事件之间,使第一个事件对对象的所有改变都可以被第二个事件看到和反映出。比如当一个线程对 volatile 变量进行写操作后,另一个线程随后访问该变量,happens-before 关系就建立了。因此,所有对 volatile 变量的改变对其他线程来说是可见的。

需要注意的

当在程序中使用 volatile 关键字时,我们必须注意以下几点:

  1. volatile 关键字并不能消除原子之间的同步操作的需要,因为内存一致性错误仍然是可能的
  2. 使用原子变量比使用 synchronized 同步代码更有效率,但是为了避免内存一致性错误,需要作出额外的努力
  3. volatile 关键字不能替代 synchronized 同步代码块和方法

以上就是关于java volatile关键字的使用方法,如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • Java 并发编程:volatile的使用及其原理解析

    Java并发编程系列[未完]: •Java 并发编程:核心理论 •Java并发编程:Synchronized及其实现原理 •Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) •Java 并发编程:线程间的协作(wait/notify/sleep/yield/join) •Java 并发编程:volatile的使用及其原理 一.volatile的作用 在<Java并发编程:核心理论>一文中,我们已经提到过可见性.有序性及原子性问题,通常情况下我们可以通过Synchroniz

  • 解析java中volatile关键字

    在java多线程编程中经常volatile,有时候这个关键字和synchronized 或者lock经常有人混淆,具体解析如下: 在多线程的环境中会存在成员变量可见性问题: java的每个线程都存在一个线程栈的内存空间,该内存空间保存了该线程运行时的变量信息,当线程访问某一个变量值的时候首先会根据这个变量的地址找到对象的堆内存或者是栈堆存(原生数据类型)中的具体的内容,然后把这个内同赋值一个副本保存在本线程的线程栈中,紧接着对这个变量的一切操作在线程完成退出之前都和堆栈内存中的变量内容是没有关系

  • Java中volatile关键字的作用与用法详解

    volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以重获生机. volatile 关键字作用是,使系统中所有线程对该关键字修饰的变量共享可见,可以禁止线程的工作内存对volatile修饰的变量进行缓存. volatile 2个使用场景: 1.可见性:Java提供了volatile关键字来保证可见性. 当一个共享变量被volatile修饰时,它会保证修

  • java 高并发中volatile的实现原理

    java 高并发中volatile的实现原理 摘要: 在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的"可见性".可见性的意思是当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值.它在某些情况下比synchronized的开销更小 1. 定义: java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致的更新,线程应该确保通过排他锁单独获得这个变量.

  • Java关键字volatile和synchronized作用和区别

    volatile是变量修饰符,而synchronized则是作用于一段代码或方法:如下三句get代码: int i1; int geti1() {return i1;} volatile int i2; int geti2() {return i2;} int i3; synchronized int geti3() {return i3;} geti1() 得到存储在当前线程中i1的数值.多个线程有多个i1变量拷贝,而且这些i1之间可以相互不同.换句话说,另一个线程可能已经改变了它线程内的i1

  • Java使用volatile关键字的注意事项

    Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性.这就是说线程能够自动发现 volatile 变量的最新值.Volatile 变量可用于提供线程安全,但是只能应用于非常有限的一组用例:多个变量之间或者某个变量的当前值与修改后值之间没有约束.因此,单独使用 volatile 还不足以实现计数器.互斥锁或任何具有与多个变量相关的不变式. volatile关键字是Java中的一种稍弱的同步机制,为什么称之为弱机制. 在理解这个之前,我们先来看看java在进行同步时

  • Java中volatile关键字实现原理

    前言 我们知道volatile关键字的作用是保证变量在多线程之间的可见性,它是java.util.concurrent包的核心,没有volatile就没有这么多的并发类给我们使用. 本文详细解读一下volatile关键字如何保证变量在多线程之间的可见性,在此之前,有必要讲解一下CPU缓存的相关知识,掌握这部分知识一定会让我们更好地理解volatile的原理,从而更好.更正确地地使用volatile关键字. CPU缓存 CPU缓存的出现主要是为了解决CPU运算速度与内存读写速度不匹配的矛盾,因为C

  • java volatile关键字使用方法及注意事项

    java volatile关键字使用方法及注意事项 什么是volatile关键字 volatile 关键字在多线程程序中起着很重要的作用.当多个线程操作同一个变量时,每个线程将拥有对那个变量的本地缓存拷贝,因此,当某一个线程修改了这个变量的值时,实际上修改的是它本地缓存中的变量值,而不是主内存中的变量值,操作这个变量的其他线程并不知道这个变量的值被改变了.为了避免这种情况,我们可以用 valatile 关键字声明这个变量,用 valatile 声明了这个变量之后,变量将不在本地缓存中保存,而在主

  • java volatile关键字的含义详细介绍

    java volatile关键字 在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉. Java语言是支持多线程的,为了解决线程并发的问题,在语言内部引入了 同步块 和 volatile 关键字机制. synchronized  同步块大家都比较熟悉,通过 synchronized 关键字来实现,所有加上synchronized 和 块语句,在多线程访问的时候,同一时刻只能有一个线程能够用 synchron

  • 梳理总结Java static关键字的方法作用

    目录 概述 定义和使用格式 类变量 静态方法 调用格式 静态原理图解 静态代码块 概述 关于 static 关键字的使用,它可以用来修饰的成员变量和成员方法,被修饰的成员是属于类的,而不是单单是属 于某个对象的.也就是说,既然属于类,就可以不靠创建对象来调用了. 定义和使用格式 类变量 当 static 修饰成员变量时,该变量称为类变量.该类的每个对象都共享同一个类变量的值.任何对象都可以更改 该类变量的值,但也可以在不创建该类的对象的情况下对类变量进行操作. 类变量:使用 static关键字修

  • java volatile关键字作用及使用场景详解

    1. volatile关键字的作用:保证了变量的可见性(visibility).被volatile关键字修饰的变量,如果值发生了变更,其他线程立马可见,避免出现脏读的现象.如以下代码片段,isShutDown被置为true后,doWork方法仍有执行.如用volatile修饰isShutDown变量,可避免此问题. public class VolatileTest3 { static class Work { boolean isShutDown = false; void shutdown(

  • Java Volatile关键字实现原理过程解析

    volatile的用法 volatile通常被比喻成"轻量级的synchronized",也是Java并发编程中比较重要的一个关键字.和synchronized不同,volatile是一个变量修饰符,只能用来修饰变量.无法修饰方法及代码块等. volatile的用法比较简单,只需要在声明一个可能被多线程同时访问的变量时,使用volatile修饰就可以了. 如以下代码,是一个比较典型的使用双重锁校验的形式实现单例的,其中使用volatile关键字修饰可能被多个线程同时访问到的single

  • 简单了解java volatile关键字实现的原理

    一.volatile关键字的语义分析 1.保证可见性 对共享变量的修改,其他线程能够马上感知到.但不能保证原子性(i++) 2.保证有序性 3.volatile的原理和实现机制 有volatile修饰的共享变量进行写操作的时候会多出有 "lock"标志的汇编代码,Lock前缀的指令在多核处理器下会引发两件事情: 1)将当前处理器缓存行中的数据写回到系统内存中 2)这个写回内存的操作会使在其他cpu里缓存了该内存地址的数据无效. 二.volatile的使用场景 1.状态标志(开关模式)

  • Java Volatile关键字同步机制详解

    Volatile关键字--最轻量级的同步机制1.保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的.(实现可见性) 例如:如果一个oldvalue -->修改为newvalue ,这时的newvalue可以被其他的线程看到. 2.volatile不是线程安全的,只能保证对单次读/写的原子性.i++ 这种操作不能保证原子性.(不能保证原子性)最常使用场景:一写多读代码演示Volatile的可见性 public class VolatileCa

  • Java Volatile关键字你真的了解吗

    目录 正文 并发编程的三要素 1.原子性 2.可见性 3.有序性 Volatile Volatile 的内存模型 Volatile 的实现原理 (1) lock (2) unclock (3) read (4) load (5) use (6) assign (7) store (8) write Volatile源码案例 总结 正文 在谈 Volatile 之前,我们先回顾下 Java 内存模型 的三要素:原子性.可见性.有序性,也就是大家常提到的并发编程三要素. 并发编程的三要素 1.原子性

  • 详解Java面试官最爱问的volatile关键字

    本文向大家分享的主要内容是Java面试中一个常见的知识点:volatile关键字.本文详细介绍了volatile关键字的方方面面,希望大家在阅读过本文之后,能完美解决volatile关键字的相关问题.  在Java相关的岗位面试中,很多面试官都喜欢考察面试者对Java并发的了解程度,而以volatile关键字作为一个小的切入点,往往可以一问到底,把Java内存模型(JMM),Java并发编程的一些特性都牵扯出来,深入地话还可以考察JVM底层实现以及操作系统的相关知识. 下面我们以一次假想的面试过

  • 详细分析java并发之volatile关键字

    Java面试中经常会涉及关于volatile的问题.本文梳理下volatile关键知识点. volatile字意为"易失性",在Java中用做修饰对象变量.它不是Java特有,在C,C++,C#等编程语言也存在,只是在其它编程语言中使用有所差异,但总体语义一致.比如使用volatile 能阻止编译器对变量的读写优化.简单说,如果一个变量被修饰为volatile,相当于告诉系统说我容易变化,编译器你不要随便优化(重排序,缓存)我. Happens-before 规范上,Java内存模型遵

随机推荐