Alternative to spinlock

2019-03-22 07:00发布

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

5条回答
放我归山
2楼-- · 2019-03-22 07:34

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

Regards Mike

查看更多
Anthone
3楼-- · 2019-03-22 07:37

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.

查看更多
做自己的国王
4楼-- · 2019-03-22 07:40

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);
查看更多
【Aperson】
5楼-- · 2019-03-22 07:45

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.

查看更多
We Are One
6楼-- · 2019-03-22 07:52

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();
}
查看更多
登录 后发表回答