我有一个方法,在这个方法中我有一个块:
public void method()
{
[block instructions]
}
但是这个方法在我的程序中被调用了两次。我希望这个块只执行一次,并且只对第一次出现的方法执行。什么是最好和最优雅的方式呢?
答案 0 :(得分:8)
private static final AtomicBoolean hasRunAtom = new AtomicBoolean();
public void method() {
if (hasRunAtom.getAndSet(true)) return;
[block instructions]
}
答案 1 :(得分:2)
冒着过度工程化的风险,我实际建议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();
}
答案 2 :(得分:1)
一个简单的解决方案是使用静态布尔标志:
static boolean flag = true;
public void method()
{
if (flag)
{
[block instructions]
flag = false;
}
}
答案 3 :(得分:0)
首先,如果你想简单快捷地使用一个简单的布尔标志(只是不要忘记并发问题并使用@Marko Topolnik解决方案)。
但如果我们已经开始进行理论讨论并谈论设计模式,而不是像@Tomasz Nurkiewicz那样使用状态模式,我会建议考虑singleton(有人会说它更具反设计模式)以及如何只实现此类的一个实例,因此如果请求此类的实例,则只在第一次调用时调用构造函数。
如果你想要更多“开箱即用”的解决方案,你可以使用aop
答案 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()的所有调用都将立即返回,而不会执行任何实际代码。从性能的角度来看,您将通过简单的分支返回操作替换重型原子操作。