ron*_*ron 8 concurrency scala immutability
正如我所读到的,Scala immutable 由于各种原因val
不会被转换为Java final
.这是否意味着val
必须保护从其他线程访问来保护同步以保证可见性?
Pao*_*lla 12
从多线程的角度来看,对val本身的赋值很好,因为你在声明它时必须给val赋值,并且以后不能改变这个值(所以如果你这样做val s="hello"
,s是"你好" "从诞生之日起:没有线程会读到另一个值.但是有一些警告:
1 - 如果将可变类的实例分配给val,则val本身不会"保护"类的内部状态不发生变化.
class Foo(s:String) { var thisIsMutable=s }
// you can then do this
val x = new Foo("hello")
x.thisIsMutable="goodbye"
// note that val guarantees that x is still the same instance of Foo
// reassigning x = new Foo("goodbye") would be illegal
Run Code Online (Sandbox Code Playgroud)
2 - 您(或您的某个库......)可以通过反射更改val.如果发生这种情况,两个线程确实可以为您的val读取不同的值
import java.lang.reflect.Field
class Foo { val foo=true } // foo is immutable
object test {
def main(args: Array[String]) {
val f = new Foo
println("foo is " + f.foo) // "foo is true"
val fld = f.getClass.getDeclaredField("foo")
fld.setAccessible(true)
fld.setBoolean(f, false)
println("foo is " + f.foo) // "foo is false"
}
}
Run Code Online (Sandbox Code Playgroud)
作为对象成员,一旦初始化,val
s就永远不会在对象的生命周期中更改它们的值.因此,只要对象的引用没有在构造函数中转义,所以保证它们的值对所有线程都可见.事实上,他们获得了Java final
修饰符,如下所示:
object Obj {
val r = 1
def foo {
val a = 1
def bar = a
bar
}
}
Run Code Online (Sandbox Code Playgroud)
使用javap:
...
private final int r;
...
public void foo();
...
0: iconst_1
1: istore_1
2: aload_0
3: iload_1
4: invokespecial #31; //Method bar$1:(I)I
7: pop
...
private final int bar$1(int);
...
0: iload_1
1: ireturn
...
Run Code Online (Sandbox Code Playgroud)
作为方法本地,它们仅在方法中使用,或者它们作为参数传递给嵌套方法或闭包(参见bar$1
上文提到的).闭包可能会传递给另一个线程,但它只有一个带有local值的final字段val
.因此,从创建它们到所有其他线程,它们是可见的,并且不需要同步.
请注意,这并没有说明val
指向的对象- 它本身可能是可变的并且需要同步.
在大多数情况下,不能通过反射来违反上述内容 - Scala val
成员声明实际上会生成一个具有相同名称的getter和一个getter访问的私有字段.尝试使用反射来修改字段将导致NoSuchFieldException
.修改它的唯一方法是在类中添加一个specialized
注释,使专用字段受到保护,从而可以进行反射.我目前无法想到任何其他情况可能会改变宣称为val
...
归档时间: |
|
查看次数: |
1581 次 |
最近记录: |