Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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
java-确保只有一个线程初始化对象_Java_Multithreading - Fatal编程技术网

java-确保只有一个线程初始化对象

java-确保只有一个线程初始化对象,java,multithreading,Java,Multithreading,我有一个小问题,就是确保对象的初始化是由一个线程完成的,并且只执行一次,即下面给出的代码片段: AtomicBoolean initialize = new AtomicBoolean(); CountDownLoatch latch = new CountDownLatch(1); void init(){ if(initialize.compareAndSwap(false,true)) { someMethod() // this can throw so

我有一个小问题,就是确保对象的初始化是由一个线程完成的,并且只执行一次,即下面给出的代码片段:

AtomicBoolean initialize = new AtomicBoolean();
CountDownLoatch latch = new CountDownLatch(1);

void init(){
     if(initialize.compareAndSwap(false,true)) { 
          someMethod() // this can throw some exception
          latch.countDown();
      }
      else{
          latch.await();
      }
}

我可以将倒计时包装在finally块中,因为如果发生异常,线程可能会被卡住。但是,即使使用finally块,线程也将被释放,系统将处于未初始化状态。是否有一种模式可以遵循以正确地实现这一点?

难道你就不能这样做:

private static boolean initialized = false;

public synchronized void init() {
  if(initialized){return}
  if(initialize.compareAndSwap(false,true)) { 
      someMethod() // this can throw some exception
      latch.countDown();
  }
  else{
      latch.await();
  }
  initialized = true;
}

我建议从一个简单正确的解决方案开始。如果性能真的很重要,您可以在以后对其进行优化。一个简单的解决方案可能如下所示:

private final Object lock = new Object();
private boolean initialized = false;

void init() {
    synchronized (lock) {
        if (!initialized) {
            someMethod();
            initialized = true;
        }
    }
}
如果性能很重要,您可以添加对布尔变量的附加检查,该检查使用易失性变量而不是同步块。这种模式称为双重检查锁定:


在Java中,您可能希望使用“按需初始化持有者习惯用法”


初始化状态的无锁方法可以使用保存状态的原子引用:

private static AtomicReference<Object> LAZY_INITIALIZED = new AtomicReference<>();

public static Object getLazyInitialized() {
    Object result = LAZY_INITIALIZED.get();
    if (result != null)
        return result;
    result = new Object(...); // all initialization takes place here
    if (LAZY_INITIALIZED.compareAndSet(null, result)) {
        return result;
    } else {
        // another thread beat us to it, throw away our state and use the
        // state that finished construction first
        return LAZY_INITIALIZED.get();
    }
}

您可能希望将getter保留在此处的原因是,您可以稍后改变主意,使用另一个惯用法。

如果
someMethod()
抛出异常,您希望该行为是什么?另一个线程是否可以再次尝试?在初始化块上同步。它是静态块吗?如果不是,不同的线程是否从不同的对象调用此代码?在任何一种情况下,另一个线程都不知道另一个线程中的错误-我必须将其存储在某个易失性/原子变量中,然后重试/失败,我猜..其他线程是否也需要访问此对象,假设它是由一个线程正确初始化的?如果是,这看起来像是Singleton的作业,IMO。在我的示例中,NoSign将使用状态,直到初始化的线程调用latch.countdown并向其他线程发出信号表明它已完成
private static AtomicReference<Object> LAZY_INITIALIZED = new AtomicReference<>();

public static Object getLazyInitialized() {
    Object result = LAZY_INITIALIZED.get();
    if (result != null)
        return result;
    result = new Object(...); // all initialization takes place here
    if (LAZY_INITIALIZED.compareAndSet(null, result)) {
        return result;
    } else {
        // another thread beat us to it, throw away our state and use the
        // state that finished construction first
        return LAZY_INITIALIZED.get();
    }
}
   private static final EAGER_INITIALIZED = new Object(...);

   public static getState() {
       return EAGER_INITIALIZED;
   }