Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/342.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Scala中是否可以使用一个本地变量作为Volatile,因为在Java中这是不可能的?_Java_Multithreading_Scala_Jvm - Fatal编程技术网

在Scala中是否可以使用一个本地变量作为Volatile,因为在Java中这是不可能的?

在Scala中是否可以使用一个本地变量作为Volatile,因为在Java中这是不可能的?,java,multithreading,scala,jvm,Java,Multithreading,Scala,Jvm,据我所知,Java和Scala中标记为Volatile的字段提供了before关系 在Java中,不可能将方法中的局部变量设置为volatile。然而Scala编译器似乎允许这样的事情,如下面的代码: def test: Unit = { @volatile var doNotStop = true } 它的工作方式是否与Java中的工作方式相同?这些代码的语义是什么?在运行时,它在字节码和JVM中的外观如何 在Java中,如果给闭包这样的变量,它可以被另一个线程修改,因此,它必须是fi

据我所知,Java和Scala中标记为Volatile的字段提供了before关系

在Java中,不可能将方法中的局部变量设置为volatile。然而Scala编译器似乎允许这样的事情,如下面的代码:

def test: Unit = {
  @volatile var doNotStop = true 
}
它的工作方式是否与Java中的工作方式相同?这些代码的语义是什么?在运行时,它在字节码和JVM中的外观如何


在Java中,如果给闭包这样的变量,它可以被另一个线程修改,因此,它必须是final,对吗

TL;DR:当应用于局部变量时,
@volatile
注释看起来会被忽略,除非该变量可以在闭包内从此局部范围转义

为了确保这一点,我们可以签出与以下代码段对应的字节码

class Foo {
    def test: Unit = {
      @volatile var doNotStop: Boolean = true 
    }
}
使用
scalac
获得的类文件可以使用
javap-c-v-p
进行反编译。以下是
测试方法的相关部分:

public void test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=2, args_size=1
         0: iconst_1
         1: istore_1
         2: return
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            1       1     1 doNotStop   Z
      ...
请注意,没有与任何易失性访问相关的信息

如果我们选择将
doNotStop
声明为实例变量,则
javap
显示以下字段声明,并带有一个清晰的volatile标志:

private volatile boolean doNotStop;
  descriptor: Z
  flags: ACC_PRIVATE, ACC_VOLATILE
但是,您对局部变量超出其作用域的担心是完全正确的!让我们试试这个:

class Foo {
    def test = {
        var doNotStop: Boolean = true
        () => doNotStop = false
    }
}
使用
javap-p
(这次无需查看字节码或标志)为我们提供了以下定义:

public class Foo {
  public scala.Function0<scala.runtime.BoxedUnit> test();
  public static final void $anonfun$test$1(scala.runtime.BooleanRef);
  public Foo();
  private static java.lang.Object $deserializeLambda$(java.lang.invoke.SerializedLambda);
}
该类基本保持不变,但
$anonfun$test$1
现在需要
volatileboleanref
。猜猜它的内部
布尔值是如何实现的:

volatile public boolean elem;
这里的语义非常清楚:您的非局部
Boolean
变量在运行时表示为
BooleanRef
实例的字段。注释可能会将此字段标记为
volatile
。好了,
@volatile
毕竟在那里很有用


回答你的第二个问题:Java的闭包只关闭那些“实际上是最终的”值,这将不允许这种模式,
doNotStop
的值在闭包中发生变化。当然,您可以使用与此处相同的方法实现它,使用对
(Volatile)的“有效最终”引用BooleanRef
elem
可以通过闭包自由修改。

在Java中不可能的原因是一个Java线程无法从不同的线程访问局部变量。我不知道Scala,但我很确定,即使你能做到,这也不是一个好主意。你可以使用
scalac
编译代码,然后使用
javap
反编译回来。我会让你看一看发生了什么事。
volatile public boolean elem;