首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无锁和无等待线程安全的延迟初始化

无锁和无等待线程安全的延迟初始化
EN

Stack Overflow用户
提问于 2015-05-15 17:27:22
回答 5查看 4.1K关注 0票数 26

要执行无锁和无等待的惰性初始化,我执行以下操作:

代码语言:javascript
复制
private AtomicReference<Foo> instance = new AtomicReference<>(null);  

public Foo getInstance() {
   Foo foo = instance.get();
   if (foo == null) {
       foo = new Foo();                       // create and initialize actual instance
       if (instance.compareAndSet(null, foo)) // CAS succeeded
           return foo;
       else                                   // CAS failed: other thread set an object 
           return instance.get();             
   } else {
       return foo;
   }
}

它运行得很好,除了一件事:如果两个线程看到实例null,它们都创建了一个新对象,只有一个幸运地通过CAS操作来设置它,这导致了资源的浪费。

有没有人建议另一种无锁惰性初始化模式,它通过两个并发线程减少创建两个昂贵对象的可能性?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2015-05-15 18:42:12

如果你想要真正的锁-自由,你将不得不做一些旋转。你可以有一个线程‘胜利’创作权,但其他必须旋转,直到它准备好。

代码语言:javascript
复制
private AtomicBoolean canWrite = new AtomicBoolean(false);  
private volatile Foo foo; 
public Foo getInstance() {
   while (foo == null) {
       if(canWrite.compareAndSet(false, true)){
           foo = new Foo();
       }
   }
   return foo;
}

这显然存在忙于旋转的问题(您可以在其中安睡或屈服),但我可能仍然推荐按需初始化

票数 22
EN

Stack Overflow用户

发布于 2015-05-15 18:55:14

我认为您需要对对象创建本身进行一些同步。我会这样做:

代码语言:javascript
复制
// The atomic reference itself must be final!
private final AtomicReference<Foo> instance = new AtomicReference<>(null);
public Foo getInstance() {
  Foo foo = instance.get();
  if (foo == null) {
    synchronized(instance) {
      // You need to double check here
      // in case another thread initialized foo
      Foo foo = instance.get();
      if (foo == null) {
        foo = new Foo(); // actual initialization
        instance.set(foo);
      }
    }
  }
  return foo;
}

这是一种非常常见的模式,特别是对于懒惰的单身汉。二次检查锁定最小化了实际执行synchronized块的次数。

票数 4
EN

Stack Overflow用户

发布于 2015-05-27 14:38:30

我可能会采用懒惰的init Singleton模式:

代码语言:javascript
复制
private Foo() {/* Do your heavy stuff */}

private static class CONTAINER {
 private static final Foo INSTANCE = new Foo();
}

public static Foo getInstance() {
 return CONTAINER.INSTANCE;
}

实际上,我没有看到使用AtomicReference成员字段的任何理由。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30265427

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档