0

This is my situation:

I have a loop,

inside that loop I need to verify a condition

if the condition is verified call 2 methods (the methods need to be called only once)

Since the application is having strange behaviors I suspect the loop is too fast, and the methods might be called more than once

Please how to avoid this??

@Override
    public void loop() {
        Thread.sleep(1000);
        if (thisIsTrue()) {                //Condition checked
            setThisFalse();                 //Set the condition above false
            thanDoSomethingElse();         //Method to executed ONLY ONCE
        }
    }
Lisa Anne
  • 4,482
  • 17
  • 83
  • 157

3 Answers3

3

Since this is tagged as concurrency, I suggest introducing a synchronized block:

private Object conditionSync = new Object();

@Override
public void loop() {
    Thread.sleep(1000);
    synchronized(conditionSync) {
        if (thisIsTrue()) {                //Condition checked
            setThisFalse();                 //Set the condition above false
            thanDoSomethingElse();         //Method to executed ONLY ONCE
        }
    }
}

However, make sure that all methods that access or modify the variable used in thisIsTrue() and setThisFalse() also access it in a synchronized way. It might be better to redesign the application and introduce a single method that checks and modifies the variable.

Another option is the use of AtomicBoolean.compareAndSet() [Oracle]

Community
  • 1
  • 1
Thomas Weller
  • 55,411
  • 20
  • 125
  • 222
  • 1
    This may not work. It is possible that setThisFalse() is called from another class etc so we need to synchronize all modifications to the underlying variable. – Ashwinee K Jha Feb 18 '15 at 12:04
  • ... but `setThisFalse` sets to false whatever `thisIsTrue` checks, all in the same thread. No concurrency involved. – Marko Topolnik Feb 18 '15 at 12:17
  • @MarkoTopolnik: not at this place, but when two different threads enter the method, thread 1 can call thisIsTrue() and thread 2 can do the same before thread 1 was able to update the value. That's where concurrency comes into play. – Thomas Weller Feb 18 '15 at 12:20
  • @MarkoTopolnik Marko, but if more that one thread is going in the loop()? I think that could be possible (I do not know how the class works, because it's not mine) – Lisa Anne Feb 18 '15 at 12:20
  • @LisaAnne You said the problem was that the loop "runs too fast", but that can't explain the behavior. In fact, if many threads were involved then a problem would be with code which *runs too slow*, so there's time for other threads to overwrite the value. Whatever a specific thread writes, it is guaranteed to see that value in a later read---unless another thread jumped in and overwrote it. – Marko Topolnik Feb 18 '15 at 12:22
  • @MarkoTopolnik Marko I guess that must be the case...:-( – Lisa Anne Feb 18 '15 at 12:25
  • In fact, I now see I have overlooked that your `loop` method isn't actually a loop, so the problem may be happening when outside code calls `loop` from different threads. I thought you had a problem where the next step through the loop does not observe the write done in the step before. That would not be plausible. – Marko Topolnik Feb 18 '15 at 12:32
0

I hope by strange behaviors you mean sometimes there is no problem while at other times there are random changes in state which are not reproducible.

If yes then most likely you are having problems related to multiple threads modifying state at same time. In such situation the final outcome depends on timing of operations which is not predictable.

You can synchronize the access to the variable 'thisIsTrue' method is evaluating and make sure that checking the value and modifying the value happen atomically. If you are not familiar with synchronization constructs, you can go through oracle's tutorials on java synchronization.

Ashwinee K Jha
  • 9,187
  • 2
  • 25
  • 19
0

You can guard your method call with an AtomicBoolean.

Here is a sample code:

final AtomicBoolean executed = new AtomicBoolean(false); 
// this is not a variable defined in a method. If your code will be called by 
// multiple threads, those threads must have access to this variable. 

if (executed.compareAndSet(false, true)) {
     // call your method here. It is guaranteed to be called only once. 
}

If number of threads that concurrently call your method is high, this may perform poorly.

Basri Kahveci
  • 391
  • 3
  • 7