Question

I am using the following spinlock approach:

while(!hasPerformedAction()){
    //wait for the user to perform the action
    //can add timer here too
}

setHasPerformedAction(false);

return getActionPerfomed();

this basically waits for a user to perform an action and then returns it. Currently something requests an answer from the user before continuing, this is why I wait until input is received. However I was wondering if this is inefficient and if we are waiting for a while (i.e. <= 30 secs) will it slow down the pc that is running this app. Are there any other alternatives using this approach i.e. locks, semaphores if so what is the syntax?

Thanks,

Aly

Was it helpful?

Solution

In fact, not only is this inefficient, it is not even guaranteed to work, since there is no "happens-before" edge in the code that you are showing. To create a happens-before edge you need to do one of:

  1. Access a volatile variable
  2. Synchronise on a shared resource
  3. Use a concurrent utils lock.

As mentioned in another comment, the easiest solution, is simply to ensure that your flag is a volatile variable, and simply throw a short sleep in your loop.

However, the best thing to do would be to synchronize/wait/notify on a shared variable.

The methods that you need to read up on are wait and notify. For a better description on how to use these, read this article. An example code snippet is shown below;

Thread 1

Object shared = new Object();
startThread2(shared);
synchronized (shared) {
  while (taskNotDone())
    shared.wait();
}

Thread 2

// shared was saved at the start of the thread
// do some stuff
markTaskAsDone();
synchronized (shared) {
  shared.notify();
}

OTHER TIPS

What you've written is called busy looping, which you should never do.

You may want to keep doing that, but at least sleep a bit as to not be busy looping, which still wouldn't be that great:

while( !hasPerformedAction() ) {
    (sleep a bit here)
}

Another way to do it would to enqueue the user actions on a blocking queue: then you could simply be using a queue.take and the queue implementation would take care of the issue for you.

And another way would be to use a callback to be notified of the user actions.

The java tutorials have a good lesson on concurrency in java:

http://java.sun.com/docs/books/tutorial/essential/concurrency/

If you are going to be modifying UI from another thread, you will want to remember to do:

SwingUtils.invokeLater(actionToInvoke);

There's a gui in your tags, so I'll assume that the action is done in the GUI.

The "recommended" way to do this kind of thing is for the main thread to put itself to sleep (perhaps using wait()) and for the GUI action to notify() it back into wakefulness once the action has been performed.

There are some classes for that in java.util.concurrent.locks. Have a look at Class LockSupport

Regards Mike

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top