假设我有一个静态复杂对象,它由一个线程池定期更新,并在一个长时间运行的线程中或多或少地连续读取.对象本身总是不可变的,反映了最近的某种状态.
class Foo() { int a, b; }
static Foo theFoo;
void updateFoo(int newA, int newB) {
f = new Foo();
f.a = newA;
f.b = newB;
// HERE
theFoo = f;
}
void readFoo() {
Foo f = theFoo;
// use f...
}
Run Code Online (Sandbox Code Playgroud)
我至少不在乎我的读者是看到旧的还是新的Foo,但是我需要看到一个完全初始化的对象.IIUC,Java规范说没有HERE中的内存屏障,我可能会看到一个fb初始化但尚未提交到内存的对象.我的程序是一个真实世界的程序,它迟早会将内容提交到内存中,所以我不需要立即将新的值ofFoo提交到内存中(虽然它不会受到伤害).
您认为实现内存屏障最可读的方式是什么?如果需要,我愿意为了可读性而付出一点性能价格.我想我可以将赋值同步到Foo,这样可行,但是我不确定读取代码的人为什么这么做是非常明显的.我还可以同步新Foo的整个初始化,但这会引入更多实际需要的锁定.
你会如何编写它以使其尽可能可读?
对Scala版本的奖励荣誉:)
我有一个单例服务器实例,我很好奇我的代码是否是线程安全的.我已经阅读了不同的单例模式,我认为通常的方法是double-checked locking模式,如下所示:
public static Singleton getInstance() {
if(singleton == null) {
synchronized(Singleton.class) {
if(singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
Run Code Online (Sandbox Code Playgroud)
这被认为是设置/获取单身的有效线程安全方式.我读过,获取和设置单例的最简单方法是lazy instantiation,看起来像这样:
public static ClassicSingleton getInstance() {
if(instance == null) {
instance = new ClassicSingleton();
}
return instance;
}
Run Code Online (Sandbox Code Playgroud)
现在我想知道的是我的变体是否是线程安全的.我的代码:
public static void startServer(int listeningPortNumber) throws IOException {
if (server != null) {
throw new IOException("Connection exists");
}
server = new Server(listeningPortNumber);
}
Run Code Online (Sandbox Code Playgroud)
我的代码与上面的惰性实例化模式非常相似,但我看不出我的代码是如何不是线程安全的.有没有我没看到的东西,或者这是真正有效的代码?
参考: …
我需要在多线程环境中在Scala中缓存一些东西.
阅读scalaz,Memo我在不可变哈希映射备忘录的代码中找到了以下注释:
由于此备忘录使用单个var,因此它是线程安全的.
代码如下所示:
def immutableMapMemo[K, V](m: Map[K, V]): Memo[K, V] = {
var a = m
memo[K, V](f =>
k => {
a get k getOrElse {
val v = f(k)
a = a updated (k, v)
v
}
})
}
Run Code Online (Sandbox Code Playgroud)
说这是线程安全的,与我到目前为止所阅读和学到的关于JVM平台上的线程安全的内容相反; 参考更新可能是原子的,但正如我所理解的那样,如果您没有内存屏障,编译器可能会尝试进行某些优化来扰乱发生在之前的关系.例如,请参阅此帖和此内容.
但我确信那些scalaz人非常聪明.也许有关于范围的特别之处a.
评论声称是真的,如果是,为什么?