如何保证一段代码在多线程环境下只执行一次?
How to ensure a block of code is executed only once in a multithreaded environment?
我有一个非单例 actor,它正在创建一个我只想创建一次的对象。这是如何实现的?演员可以是单身吗?如果是,如何?
class NonSingletonActor extends UntypedActor {
public static onReceive(Object arg) throws Exception {
*block of code that needs to be executed once!*
} }
您可以使用同步块,同步 class 本身并使用布尔标志,如:
class NonSingletonActor extends UntypedActor {
private static volatile boolean executed;
public static onReceive(Object arg) throws Exception {
if (executed)
return;
synchronized (NonSingletonActor.class) {
if (executed)
return;
executed= true;
*block of code that needs to be executed once!*
}
}
}
如果您可以在代码块中遇到异常并希望能够再次执行它,那么您可以仅在成功创建对象时将标志设置为 true。
AtomicBoolean
非常适合这个,尤其是它的 compareAndSet
方法。该方法有两个参数:一个 "expected" 值和一个新值。它以原子方式做三件事:(a) 检查当前值是否等于预期值,(b) 如果是,则将当前值更新为新值,以及 (c) returns true iff 更新发生(也就是说,如果预期值和旧值相同)。
private static final AtomicBoolean hasRun = new AtomicBoolean(false);
...
if (hasRun.compareAndSet(false, true)) {
// your code here
}
此代码将检查 hasRun
是否具有 "false" 值(这是其初始状态)。如果是这样,它将自己设置为 "true" 和 运行 if
的块;否则,它将保持其当前状态而不是 运行 if
的块。至关重要的是,检查和设置是原子的(正如 class 名称所暗示的那样),这意味着没有两个线程可以同时看到假值;其中一个将看到 false 值并将其设置为 true,而另一个线程无法在这两个操作之间 "sneak in"。
这些其他答案似乎忽略了这样一个事实,即您的问题是在 Akka 演员的背景下提出的。
如果您有一个对象需要从多个参与者引用但只创建一次,您应该将这些操作委托给另一个参与者——将创建和管理相关对象的参与者——然后共享引用给那个演员。
当一个NonSingletonActor
需要对该对象进行操作时,它会向包含该对象的actor发送消息。我会非常犹豫将 Akka 与此处显示的其他解决方案混合使用,我希望您会看到一些意想不到的行为。
我有一个非单例 actor,它正在创建一个我只想创建一次的对象。这是如何实现的?演员可以是单身吗?如果是,如何?
class NonSingletonActor extends UntypedActor {
public static onReceive(Object arg) throws Exception {
*block of code that needs to be executed once!*
} }
您可以使用同步块,同步 class 本身并使用布尔标志,如:
class NonSingletonActor extends UntypedActor {
private static volatile boolean executed;
public static onReceive(Object arg) throws Exception {
if (executed)
return;
synchronized (NonSingletonActor.class) {
if (executed)
return;
executed= true;
*block of code that needs to be executed once!*
}
}
}
如果您可以在代码块中遇到异常并希望能够再次执行它,那么您可以仅在成功创建对象时将标志设置为 true。
AtomicBoolean
非常适合这个,尤其是它的 compareAndSet
方法。该方法有两个参数:一个 "expected" 值和一个新值。它以原子方式做三件事:(a) 检查当前值是否等于预期值,(b) 如果是,则将当前值更新为新值,以及 (c) returns true iff 更新发生(也就是说,如果预期值和旧值相同)。
private static final AtomicBoolean hasRun = new AtomicBoolean(false);
...
if (hasRun.compareAndSet(false, true)) {
// your code here
}
此代码将检查 hasRun
是否具有 "false" 值(这是其初始状态)。如果是这样,它将自己设置为 "true" 和 运行 if
的块;否则,它将保持其当前状态而不是 运行 if
的块。至关重要的是,检查和设置是原子的(正如 class 名称所暗示的那样),这意味着没有两个线程可以同时看到假值;其中一个将看到 false 值并将其设置为 true,而另一个线程无法在这两个操作之间 "sneak in"。
这些其他答案似乎忽略了这样一个事实,即您的问题是在 Akka 演员的背景下提出的。
如果您有一个对象需要从多个参与者引用但只创建一次,您应该将这些操作委托给另一个参与者——将创建和管理相关对象的参与者——然后共享引用给那个演员。
当一个NonSingletonActor
需要对该对象进行操作时,它会向包含该对象的actor发送消息。我会非常犹豫将 Akka 与此处显示的其他解决方案混合使用,我希望您会看到一些意想不到的行为。