当前位置: 首页 > 面试题库 >

挥发性变量和其他变量

罗伟兆
2023-03-14
问题内容

以下是经典文章Concurency in Practice:

当线程A写入易失性变量,随后线程B读取相同的变量时,在写入易失性变量之前A可见的所有变量的值,在读取易失性变量后B可见。

我不确定我是否真的能理解这一说法。例如,在这种情况下,所有变量的含义是什么?这是否意味着使用volatile还会对非易失性变量的使用产生副作用?
在我看来,该声明具有我无法理解的一些微妙含义。
有什么帮助吗?


问题答案:

您的问题的答案在JLS#17.4.5中:

在随后每次对该字段进行读取之前,都会写入一个易失字段(第8.3.1.4节)。

所以如果在一个线程中

aNonVolatileVariable = 2 //w1
aVolatileVariable = 5 //w2

然后在另一个线程中:

someVariable = aVolatileVariable //r1
anotherOne = aNonVolatileVariable //r2

anotherOne即使该变量不是volatile,您也可以保证等于2。因此,是的,使用volatile对使用非易失性变量也有副作用。

更详细地讲,这是由于同一部分中的Java内存模型(JMM)提供了2个其他保证:线程内顺序和可传递性(hb(x,y)表示x发生在y之前):

如果x和y是同一线程的动作,并且x按程序顺序位于y之前,则hb(x,y)。
[…]
如果hb(x,y)和hb(y,z),则hb(x,z)。

在我的示例中:

  • hb(w1,w2)和hb(r1,r2)(线程内语义)
  • hb(w2,r1)由于易失性保证
    因此可以通过传递性得出hb(w1,r2)的结论。

而且,JMM保证,如果程序与事前发生的关系正确同步,则该程序的所有执行将保持顺序一致(即看起来好像没有任何重排序)。因此,在这种特定情况下,可以保证非易失性读取可以看到非易失性写入的效果。



 类似资料:
  • 以下是经典的实践中的一致性: 当线程A写入一个易失性变量,随后线程B读取相同的变量时,A在写入易失性变量之前可见的所有变量的值在读取易失性变量后变得对B可见。 我不确定我真的能理解这句话。例如,在这种情况下,所有变量的含义是什么?这是否意味着使用对使用非volatile变量也有副作用<在我看来,这句话有一些我无法理解的微妙含义<有什么帮助吗?

  • 变量可以很简单地定义成可变(var)和不可变(val)的变量。这个与Java中使用的final很相似。但是不可变在Kotlin(和其它很多现代语言)中是一个很重要的概念。 一个不可变对象意味着它在实例化之后就不能再去改变它的状态了。如果你需要一个这个对象修改之后的版本,那就会再创建一个新的对象。这个让编程更加具有健壮性和预估性。在Java中,大部分的对象是可变的,那就意味着任何可以访问它这个对象的

  • 问题内容: JVM是否保证不缓存非可变变量? 程序员是否可以依赖JVM始终为每个线程本地缓存非易失性变量。 或JVM可能会或可能不会这样做,因此程序员不应为此而依赖JVM。 预先感谢您的回答。 问题答案: 否。JVM不能保证“缓存”非易失性字段。JVM保证的实现是 可变字段应如何表现 。字段的缓存是非标准的(未指定),并且因JVM的实现而异。因此,您不应该真正依赖它(即使通过某种方式发现某些数据正

  • 在Kotlin中,一切都是对象。没有像Java中那样的原始基本类型。这个是非常有帮助的,因为我们可以使用一致的方式来处理所有的可用的类型。

  • 问题内容: 我需要在其他班上变数。我怎样才能做到这一点? 所以我尝试在Textcl.class中使用,但是得到了。 问题答案: 您将得到空值,因为inString从未按Robert Kilar在注释中正确指出的那样进行初始化。 您可以通过使用类名来引用静态变量。 示例ClassName.variablename。就你而言 运行您的主类。当您运行inString时,将在该类的构造函数中对其进行初始化

  • 属性与Java中的字段是相同的,但是更加强大。属性做的事情是字段加上getter加上setter。我们通过一个例子来比较他们的不同之处。这是Java中字段安全访问和修改所需要的代码: public class Person { private String name; public String getName() { return name; }