我有一个方法,在这个方法里面我有一个块:
public void method()
{
[block instructions]
}
但是这个方法在我的程序中被调用了两次。我希望这个块只执行一次,并且只在方法的第一次出现时执行。什么是最好和优雅的方式来做到这一点?
我有一个方法,在这个方法里面我有一个块:
public void method()
{
[block instructions]
}
但是这个方法在我的程序中被调用了两次。我希望这个块只执行一次,并且只在方法的第一次出现时执行。什么是最好和优雅的方式来做到这一点?
private static final AtomicBoolean hasRunAtom = new AtomicBoolean();
public void method() {
if (hasRunAtom.getAndSet(true)) return;
[block instructions]
}
冒着过度设计的风险,我实际上建议使用 state-pattern。本质上你有一个State
抽象:
interface State extends Runnable {}
有两种实现:
class FirstState extends State {
public void run() {
//[block of code]
state = new SecondState();
}
}
class SecondState extends State {
public void run() {
//[block instructions]
}
}
FirstState
开关state
电流:
private State state = new FirstState();
您method()
现在没有条件逻辑:
public void method()
{
state.run();
}
然而,在 99% 的情况下,boolean
标志就足够了……
更新:上面的解决方案不是线程安全的。如果你需要它,简单AtomicReference<State> state
惯于就足够了(请参阅下面的Marko Topolnik评论)或者您需要同步整个method()
:
public synchronized void method()
{
state.run();
}
一个简单的解决方案是使用静态布尔标志:
static boolean flag = true;
public void method()
{
if (flag)
{
[block instructions]
flag = false;
}
}
您可能应该重新设计您的方法。如果一个方法在第二次运行时做了不同的事情,这会让试图理解你的程序的人感到困惑。
它是第二次从程序中的不同位置调用吗?如果是这种情况,最简单的方法是将复制的位提取到另一种方法中。
method() {
// Do stuff that's run only the first time
method2()
}
method2() {
// Do stuff that's run both times
}
如果它是从同一个地方调用的,你应该问自己为什么你的代码期望第二次发生不同的事情。
Marko 的回答在概念上很简单,但现在每次调用方法都需要对 AtomicBoolean 执行原子操作。如果 method() 被非常普遍地调用,这将导致显着的性能损失。
这是我提出的另一个基于单例模式的线程安全解决方案。我希望这会显着减少性能开销。
public class MyClass {
public void method() {
BlockRunner.runIfFirst();
}
private static class BlockRunner {
static {
[block insturctions]
}
public static void runIfFirst() {}
}
}
此解决方案基于此处描述的 Singleton 惰性初始化概念。
如果我的理解是正确的,当 BlockRunner 第一次通过调用 runIfFirst() 调用时,静态代码块将被调用。以后对 runIfFirst() 的所有调用都将立即返回,而不会执行任何实际代码。从性能的角度来看,您正在用简单的分支和返回操作替换繁重的原子操作。