我正在用 scala 编写一个计算库。我将类似的功能分组到包含一堆过程和一些为 O(1) 时间数据静态分配的内存的原生 scala 单例对象中。
这种方法适合单线程使用。但是同时从不同的线程调用库函数可能会覆盖临时数据并给调用者错误的答案。
我可以通过在函数本地空间中移动所有静态分配的内存来复制这个库并编写线程安全版本。但我更喜欢通过定义线程局部变量来避免它。
在斯卡拉有可能吗?
我正在用 scala 编写一个计算库。我将类似的功能分组到包含一堆过程和一些为 O(1) 时间数据静态分配的内存的原生 scala 单例对象中。
这种方法适合单线程使用。但是同时从不同的线程调用库函数可能会覆盖临时数据并给调用者错误的答案。
我可以通过在函数本地空间中移动所有静态分配的内存来复制这个库并编写线程安全版本。但我更喜欢通过定义线程局部变量来避免它。
在斯卡拉有可能吗?
只需使用 Java 的java.lang.ThreadLocal
类来存储变量。
val tl = new ThreadLocal[String]
tl.set("fish")
tl.get // "fish"
请注意,这样做会带来非零的性能损失(我记得大约 6 ns)。如果您正在做真正轻量级的事情(例如增加索引),您可能会注意到速度上的差异。
自 Java 8 发布以来,有更多的声明方式来初始化ThreadLocal
:
斯卡拉:
val local = ThreadLocal.withInitial[String](() => "init value");
Java中的类比:
ThreadLocal<String> local = ThreadLocal.withInitial(() -> "init value");
在 Java 8 发布之前,您必须执行以下操作:
斯卡拉:
val local = new ThreadLocal[String]{
override def initialValue = "init value"
}
Java中的类比:
ThreadLocal<String> local = new ThreadLocal<String>(){
@Override
protected String initialValue() {
return "init value";
}
};
注意:
评估是惰性的,因为您传递的java.util.function.Supplier
lambda 在被调用时只评估一次,ThreadLocal#get
但之前没有评估过值。