仅为方法的第一次调用调用方法块

时间:2012-07-08 10:16:25

标签: java

我有一个方法,在这个方法中我有一个块:

public void method()
{
   [block instructions]
}

但是这个方法在我的程序中被调用了两次。我希望这个块只执行一次,并且只对第一次出现的方法执行。什么是最好和最优雅的方式呢?

6 个答案:

答案 0 :(得分:8)

private static final AtomicBoolean hasRunAtom = new AtomicBoolean();

public void method() {
  if (hasRunAtom.getAndSet(true)) return;
  [block instructions]
}

答案 1 :(得分:2)

冒着过度工程化的风险,我实际建议。基本上你有一个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();
}

答案 2 :(得分:1)

一个简单的解决方案是使用静态布尔标志:

static boolean flag = true;

public void method()
{  
  if (flag)
  {

      [block instructions]
      flag = false;  

  }
} 

答案 3 :(得分:0)

首先,如果你想简单快捷地使用一个简单的布尔标志(只是不要忘记并发问题并使用@Marko Topolnik解决方案)。

但如果我们已经开始进行理论讨论并谈论设计模式,而不是像@Tomasz Nurkiewicz那样使用状态模式,我会建议考虑(有人会说它更具反设计模式)以及如何只实现此类的一个实例,因此如果请求此类的实例,则只在第一次调用时调用构造函数。

如果你想要更多“开箱即用”的解决方案,你可以使用

答案 4 :(得分:0)

你应该重新设计你的方法。如果某个方法在第二次运行时执行不同的操作,那么试图理解您的程序的人会感到困惑。

第二次从程序中的其他地方调用它吗?如果是这种情况,最简单的方法是将重复的位提取到另一个方法中。

method() {
    // Do stuff that's run only the first time
    method2()
}

method2() {
    // Do stuff that's run both times
}

如果从同一个地方调用它,你应该问问自己为什么你的代码期望第二次发生不同的事情。

答案 5 :(得分:0)

Marko的答案在概念上很简单,但每次调用方法现在都需要对AtomicBoolean执行原子操作。如果通常调用method(),则会导致显着的性能损失。

这是我提出的另一个基于单例模式的线程安全解决方案。我希望这会显着降低性能开销。

public class MyClass {
    public void method() {
        BlockRunner.runIfFirst();
    }

    private static class BlockRunner {
        static {
            [block insturctions]
        }

        public static void runIfFirst() {}
    }
}

此解决方案基于Singleton lazy-init概念described here

如果我的理解是正确的,当首次通过调用runIfFirst()调用BlockRunner时,将调用静态代码块。将来对runIfFirst()的所有调用都将立即返回,而不会执行任何实际代码。从性能的角度来看,您将通过简单的分支返回操作替换重型原子操作。