我有一些代码,我想要进行一次初始化。但是这段代码没有明确的生命周期,所以在我的初始化完成之前,我的逻辑可能被多个线程调用。所以,我基本上要确保我的逻辑代码“等待”,直到初始化完成。
这是我的第一次削减。
public class MyClass {
private static final AtomicBoolean initialised = new AtomicBoolean(false);
public void initialise() {
synchronized(initialised) {
initStuff();
initialised.getAndSet(true);
initialised.notifyAll();
}
}
public void doStuff() {
synchronized(initialised) {
if (!initialised.get()) {
try {
initialised.wait();
} catch (InterruptedException ex) {
throw new RuntimeException("Uh oh!", ex);
}
}
}
doOtherStuff();
}
}
我基本上想确保这会做我认为它会做的事情 - 阻止doStuff直到初始化为真,并且我没有错过doStuff可能卡在Object上的竞争条件。等待()永远不会到来。
编辑:
我无法控制线程。我希望能够控制所有初始化的时间,这就是doStuff()无法调用initialise()的原因。
我使用了AtomicBoolean,因为它是值持有者和我可以同步的对象的组合。我本可以简单地使用“public static final Object lock = new Object();”和一个简单的布尔标志。 AtomicBoolean方便地给了我两个。无法修改布尔值。
CountDownLatch正是我想要的。我还考虑过使用含有0许可证的Sempahore。但CountDownLatch非常适合这项任务。
答案 0 :(得分:6)
这是库和内置并发控件的奇怪组合。这样的事情要干净得多:
public class MyClass {
private static final CountDownLatch latch = new CountDownLatch(1);
public void initialise() {
initStuff();
latch.countDown();
}
public void doStuff() {
try {
latch.await();
} catch (InterruptedException ex) {
throw new RuntimeException("Uh oh!", ex);
}
doOtherStuff();
}
}
答案 1 :(得分:2)
synchronized
块会自动阻止其他线程。只需使用一个简单的锁定对象+状态变量:
public class MyClass {
private static boolean initialised;
private static final Object lockObject = new Object();
public void initialise() {
synchronized (lockObject) {
if (!initialised) {
initStuff();
initialised = true;
}
}
}
public void doStuff() {
initialise();
doOtherStuff();
}
}
答案 2 :(得分:1)
最好的方法是使用静态初始化程序(如SB所述):
public class MyClass {
public static void doInitialize() {
...
}
public void doStuff() {
doOtherStuff();
}
static {
doInitialize();
}
}
在允许调用任何其他代码之前,这将执行一次。如果在使用该类的任何时候总是必须初始化,那么没有性能损失,因为在使用该类之前不会加载该类。有关详细信息,请参阅this question的答案。
答案 3 :(得分:0)
您始终在同步块内使用AtomicBoolean
。没有太多意义,因为只有一个线程可以访问它。原子变量旨在用于无锁解决方案 - 您可以将该值设置为不间断单元。
我猜你正在寻找一个无锁解决方案,一旦发生了这种情况:
public class MyClass {
private static final AtomicBoolean initialised = new AtomicBoolean(false);
public void initialise() {
if (!intialized.get())
{
synchornized (this)
{
if (!initialized.getAndSet(true))
doInitialize();
}
}
}
public void doStuff() {
initialize();
doOtherStuff();
}
您也可以使用简单的volatile boolean
执行此操作,这实际上比AtomicBoolean更有效。
答案 4 :(得分:0)
启动时这是正确的,为什么不等待初始化完成之前启动其他线程?
此外,您可以执行线程同步的IsComplete布尔值,该布尔值设置为false,直到初始化例程将其设置为true。