3

我有一个方法,在这个方法里面我有一个块:

public void method()
{
   [block instructions]
}

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

4

6 回答 6

8
private static final AtomicBoolean hasRunAtom = new AtomicBoolean();

public void method() {
  if (hasRunAtom.getAndSet(true)) return;
  [block instructions]
}
于 2012-07-08T10:17:48.017 回答
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();
}
于 2012-07-08T10:28:32.657 回答
1

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

static boolean flag = true;

public void method()
{  
  if (flag)
  {

      [block instructions]
      flag = false;  

  }
} 
于 2013-06-27T16:20:30.023 回答
0

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

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

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

于 2012-07-08T11:07:02.940 回答
0

您可能应该重新设计您的方法。如果一个方法在第二次运行时做了不同的事情,这会让试图理解你的程序的人感到困惑。

它是第二次从程序中的不同位置调用吗?如果是这种情况,最简单的方法是将复制的位提取到另一种方法中。

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

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

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

于 2012-07-08T15:06:24.803 回答
0

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() 的所有调用都将立即返回,而不会执行任何实际代码。从性能的角度来看,您正在用简单的分支和返回操作替换繁重的原子操作。

于 2015-12-30T21:08:43.270 回答