Java中的易变关键字 – 澄清

我真的很困惑我读了关于在Java中的volatile关键字的应用程序。

  1. 以下说法正确吗? “写入到一个易失性字段发生在每个后续读取相同的字段”

  2. 理想情况下,何时应该使用volatile关键字

  3. 有什么区别:

    class TestClass { private int x; synchronized int get(){return x;} synchronized void set(int x){this.x = x;} } 

 class TestClass { private volatile int x; int get(){return x;} void set(int x){this.x = x;} } 

volatile是一个字段修饰符同步修改代码块方法 。 所以我们可以使用这两个关键字指定一个简单访问器的三个变体:

  int i1; int geti1() {return i1;} volatile int i2; int geti2() {return i2;} int i3; synchronized int geti3() {return i3;} 

geti1()访问当前线程中当前存储在i1中的值。 线程可以有variables的本地副本,数据不必与其他线程中保存的数据相同。特别是,另一个线程可能在其线程中更新了i1 ,但是当前线程中的值可能不同于那更新的价值。 事实上,Java有一个“主”内存的概念,这是为variables保存当前“正确”值的内存。 线程可以有自己的variables副本,线程副本可以不同于“主”内存。 所以事实上,对于i1 ,“主”存储器的值可能是1,对于i1 ,如果thread1thread2都更新了,则thread1对于i1具有值2,对于i1具有值3 i1但这些更新的值尚未传播到“主”内存或其他线程。

另一方面, geti2()有效地从“main”内存访问i2的值。 一个volatilevariables不允许有一个variables的本地副本,这个variables与当前保存在“main”内存中的值不同。 实际上,一个声明为volatile的variables必须使数据在所有线程中保持同步,以便每当访问或更新任何线程中的variables时,所有其他线程立即看到相同的值。 一般来说,volatilevariables比“plain”variables具有更高的访问和更新开销。 一般来说,线程可以拥有自己的数据副本,以提高效率。

volitile和synchronized有两个区别。

首先同步获取并释放监视器上的锁,一次只能强制一个线程执行代码块。 这是众所周知的同步方面。 但同步也同步内存。 实际上,同步将整个线程内存与“主”内存同步。 所以执行geti3()会执行以下操作:

  1. 线程获取监视器上对象的锁。
  2. 线程内存刷新其所有variables,即它的所有variables都能从“主”内存中有效地读取。
  3. 代码块被执行(在这种情况下,将返回值设置为i3的当前值,可能刚从“主”存储器复位)。
  4. (对variables的任何更改现在通常会写入“主”内存,但对于geti3(),我们没有任何更改。)
  5. 线程释放监视器上的锁对象this。

因此,volatile只在同步线程内存和“main”内存之间的一个variables的值时,同步所有variables在线程内存和“main”内存之间的同步,并locking和释放一个监视器来引导。 明显的同步可能会有更多的开销比易变。

http://javaexp.blogspot.com/2007/12/difference-between-volatile-and.html

volatile保证从variables读取总是反映最新的更新值。 运行时可以通过各种方式实现,包括在值更改时不caching或刷新caching。

bwawok躲过去了,但是volatile关键字只是为了内存的可见性。 在Java 1.5发布之前,volatile关键字声明了这个字段会每次点击主内存来获取对象的最新值,以便读取和刷新写入。

今天的易变关键字是两个非常重要的事情:

  1. 不要担心如何,但知道,当阅读一个易变的领域,你将永远拥有最新的价值。
  2. 编译器不能重新命令易失性读/写来保持程序的顺序。

从客户端的angular度来看,私有易失性字段对公共接口是隐藏的,而同步方法则更加可见。

回答你的问题的第三部分,部分是第二部分。

synchronizedvolatile样本之间没有function差异。

然而,每个人在性能方面都有自己的缺点。 在某些情况下, volatile性能可能比使用java.util.concurrent synchronized或其他基元更糟糕。 对于这个讨论请参阅 – > 为什么Java中的variables默认是volatile? 。

通过回答KeremBaydoğan是完全正确的。 我只想举一个关于volatile关键字提供给我们的例子。

首先,我们有一个柜台,像这样

 public class Counter { private int x; public int getX() { return x; } public void increment() { x++; } } 

还有一些增加x值的Runnable任务

 @Override public void run() { for (N) { int oldValue = counter.getX(); counter.increment(); int new value = counter.getX(); } } } 

没有同步会有线程之间的干扰 ,只是不会工作

最简单的方法来解决这个问题:

 public class Counter { private int x; public synchronized int getX() { return x; } public synchronized void increment() { x++; } } 

其实为了迫使系统破解,我在读写x之前做了一个Thread.sleep ,试想一下是BD还是一个巨大的任务来处理。


现在什么是volatile有用的? 那里有很多好的文章: 易变的文章或这个问题

同步对公共资源的访问不是答案,但是保持标志停止线程是一个不错的select

我是我们的先行者 例如,假设我们想将variables增加到100,一个简单的方法可能是一个volatile boolean标志。 例:

 private volatile boolean stop; @Override public void run() { while(!stop) { int oldValue = counter.getX(); if (oldValue == 100) { stop = true; } else { counter.increment(); int new value = counter.getX(); } } } 

这工作正常,但是,如果您从标志中删除volatile关键字,可能会遇到和无限循环。