仅为方法的第一次调用调用方法块
我有一个方法,在这个方法里面我有一个块:
public void method() { [block instructions] }
但是这个方法在我的程序中被调用了两次。 我希望这个块只执行一次,并且只对第一次出现的方法执行。 最好和最优雅的方法是什么?
private static final AtomicBoolean hasRunAtom = new AtomicBoolean(); public void method() { if (hasRunAtom.getAndSet(true)) return; [block instructions] }
冒着过度工程化的风险,我实际上建议使用状态模式 。 基本上你有一个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
惯于 就足够了(请参阅下面的Marko Topolnik评论)或者您需要同步整个method()
:
public synchronized void method() { state.run(); }
一个简单的解决方案是使用静态布尔标志:
static boolean flag = true; public void method() { if (flag) { [block instructions] flag = false; } }
首先,如果您想要简单快捷的方法,请使用简单的布尔标志(只是不要忘记并发问题并使用@Marko Topolnik解决方案)。
但是如果我们已经开始进行理论讨论并谈论设计模式,而不是像@Tomasz Nurkiewicz那样使用状态模式,我建议考虑单身 (有些人会说它更具反设计模式)以及如何只实现一个此类的实例,因此如果请求此类的实例,则仅在第一次调用中调用构造函数。
如果你想要更多的“开箱即用”解决方案,你可以使用aop
你可能应该重新设计你的方法。 如果某个方法在第二次运行时执行了不同的操作,那么试图理解您的程序的人会感到困惑。
是第二次从程序中的其他地方调用它吗? 如果是这种情况,最简单的方法是将重复的位提取到另一个方法中。
method() { // Do stuff that's run only the first time method2() } method2() { // Do stuff that's run both times }
如果从同一个地方调用它,你应该问问自己为什么你的代码期望第二次发生不同的事情。
Marko的答案在概念上很简单,但每次调用方法现在都需要对AtomicBoolean执行primefaces操作。 如果通常调用method(),则会导致显着的性能损失。
这是我提出的另一个基于单例模式的线程安全解决方案。 我希望这会降低性能开销。
public class MyClass { public void method() { BlockRunner.runIfFirst(); } private static class BlockRunner { static { [block insturctions] } public static void runIfFirst() {} } }
此解决方案基于此处描述的Singleton lazy-init概念。
如果我的理解是正确的,当首次通过调用runIfFirst()调用BlockRunner时,将调用静态代码块。 将来对runIfFirst()的所有调用都将立即返回,而不会执行任何实际代码。 从性能角度来看,您将通过简单的分支返回操作替换重型primefaces操作。