3

I have a method and inside this method I have a block:

public void method()
{
   [block instructions]
}

But this method is called twice in my program. I would like this block to be executed only one time and only for the first occurrence of the method. What would be the best and elegant way to do that?

Avery
  • 2,270
  • 4
  • 33
  • 35
user1508419
  • 333
  • 1
  • 4
  • 14

6 Answers6

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

public void method() {
  if (hasRunAtom.getAndSet(true)) return;
  [block instructions]
}
Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • For concurrency. See updated answer, my first solution wouldn't behave well if two threads wanted to run the method at the same time. – Marko Topolnik Jul 08 '12 at 10:21
2

At the risk of greatly over-engineering I actually suggest . Essentially you have a State abstraction:

interface State extends Runnable {}

with two implementations:

class FirstState extends State {
    public void run() {
        //[block of code]
        state = new SecondState();
    }
}

class SecondState extends State {
    public void run() {
        //[block instructions]
    }
}

The FirstState switches current state:

private State state = new FirstState();

Your method() now has no conditional logic:

public void method()
{
    state.run();
}

However in 99% of cases boolean flag is enough...

UPDATE: the solution above is not thread-safe. If you need it, simple AtomicReference<State> state won't will be enough (see Marko Topolnik comment below) or you need to synchronize the whole method():

public synchronized void method()
{
    state.run();
}
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • This has education value, if nothing else. However, it suffers from non-thread-safety. An overengineered solution should at least cover all the angles, don't you agree? – Marko Topolnik Jul 08 '12 at 10:44
  • 1
    @MarkoTopolnik: you are right, I forgot to mention about it (however OP is not mentioning about thread-safe requirement as well). Nevertheless I will include it in my answer, thanks! – Tomasz Nurkiewicz Jul 08 '12 at 10:56
  • You could start `FirstState.run` with `if (state.getAndSet(new SecondState()) == this)`. Then you wouldn't need to synchronize. – Marko Topolnik Jul 08 '12 at 11:01
  • @MarkoTopolnik: correct, I would only cache `new SecondState()` somewhere in `FirstState` (`nextState`?) to avoid creating it over and over. – Tomasz Nurkiewicz Jul 08 '12 at 11:33
  • Or have a more elaborate prolog. `if (state.get() == this && state.getAndSet(new SecondState()) == this)`. Keep in mind that you wouldn't be creating it over and over anyway since you immediately replace the code that will be executed the next time. – Marko Topolnik Jul 08 '12 at 11:40
1

A simple solution would be to use a static boolean flag:

static boolean flag = true;

public void method()
{  
  if (flag)
  {

      [block instructions]
      flag = false;  

  }
} 
0

First of all, if you want to easy and quick way, use a simple boolean flag (just don't forget the concurrency issue and use @Marko Topolnik solution).

But if we already opened a theoretical discussion and talked about design pattern, rather than using the state-pattern like @Tomasz Nurkiewicz mention, I would suggest to think of (some will say it's more anti design pattern) and how to achieve only one instance of this class, so if requesting an instance of this class, the constructor will be called only in the first call.

if you altentivly want more "outside the box" solution, you can use

shem
  • 4,686
  • 2
  • 32
  • 43
  • The code to properly implement a lazily-initialized singleton is quite involved (unless just throwing `synchronized` at it -- lame). – Marko Topolnik Jul 08 '12 at 11:51
  • You are absolutely right, but if you're using java you can just use enum- a classic and easy to write singleton. – shem Jul 08 '12 at 11:55
  • `enum` is good only for an eagerly-initialized singleton, this doesn't fit OP's scenario. – Marko Topolnik Jul 08 '12 at 12:25
0

You should probably redesign your method. It's confusing for someone trying to understand your program if a method does something different the second time it's run.

Is it called from a different place in your program, the second time? If that's the case, the easiest thing to do is to extract the bit that's duplicated into another method.

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

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

If it's called from the SAME place, you should ask yourself why your code is expecting something different to happen the second time.

artbristol
  • 32,010
  • 5
  • 70
  • 103
0

Marko's answer is simple conceptually, but every call to method now needs to perform an atomic operation on the AtomicBoolean. If method() is very commonly called, this will incur a significant performance penalty.

Here's another thread-safe solution I came up with, based on the singleton pattern. I expect this to have significantly less performance overhead.

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

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

        public static void runIfFirst() {}
    }
}

This solution is based on the Singleton lazy-init concept described here.

If my understanding is correct, when BlockRunner is first invoked by calling runIfFirst(), the static block of code will get invoked. All future calls to runIfFirst() will simply just return immediately, without any real code being executed. From a performance perspective, you're replacing a heavy atomic operation, with a simple branch-and-return operation.

Community
  • 1
  • 1
RvPr
  • 1,074
  • 1
  • 9
  • 26