Альтернатива спинлок - PullRequest
       7

Альтернатива спинлок

1 голос
/ 01 февраля 2010

Я использую следующий подход спин-блокировки:

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

setHasPerformedAction(false);

return getActionPerfomed();

это в основном ждет, пока пользователь выполнит действие, а затем вернет его. В настоящее время что-то запрашивает ответ у пользователя, прежде чем продолжить, поэтому я жду, пока не будет получен ввод. Однако мне было интересно, если это неэффективно, и если мы будем ждать некоторое время (то есть <= 30 секунд), это замедлит работу компьютера, на котором запущено это приложение. Существуют ли другие альтернативы, использующие этот подход, то есть блокировки, семафоры, если так, то каков синтаксис? </p>

Спасибо

Aly

Ответы [ 5 ]

9 голосов
/ 01 февраля 2010

На самом деле, это не только неэффективно, но даже не гарантировано, что оно работает, поскольку в коде, который вы показываете, нет края «происходит до». Чтобы создать ребро случай-до , вам нужно выполнить одно из:

  1. Доступ к изменяемой переменной
  2. Синхронизация на общем ресурсе
  3. Использовать одновременную блокировку утилит.

Как уже упоминалось в другом комментарии, самое простое решение - просто убедиться, что ваш флаг является переменной переменной, и просто бросить короткий сон в цикле.

Однако лучшее, что можно сделать, - это синхронизировать / ждать / уведомлять общую переменную.

Методы, о которых вам нужно прочитать: wait и notify . Для лучшего описания того, как их использовать, прочитайте эту статью . Пример кода приведен ниже;

Тема 1

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

Резьба 2

// shared was saved at the start of the thread
// do some stuff
markTaskAsDone();
synchronized (shared) {
  shared.notify();
}
2 голосов
/ 01 февраля 2010

В уроках Java есть хороший урок по параллелизму в Java:

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

Если вы собираетесь изменять пользовательский интерфейс из другого потока, вам нужно будет выполнить следующее:

SwingUtils.invokeLater(actionToInvoke);
2 голосов
/ 01 февраля 2010

То, что вы написали, называется занятым циклом, что вы никогда не должны делать.

Вы можете продолжать делать это, но, по крайней мере, немного поспать, чтобы не быть занятым зацикливанием, что все равно было бы не так здорово:

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

Еще один способ сделать это - поставить в очередь действия пользователя в очереди блокировки: тогда вы можете просто использовать queue.take , и реализация очереди позаботится о вас.

И еще один способ - использовать обратный вызов для уведомления о действиях пользователя.

1 голос
/ 01 февраля 2010

Есть несколько классов для этого в java.util.concurrent.locks. Посмотрите на класс LockSupport

С уважением, Майк

1 голос
/ 01 февраля 2010

В ваших тегах есть gui , поэтому я предполагаю, что действие выполняется в графическом интерфейсе.

«Рекомендуемый» способ сделать это - перевести основной поток в спящий режим (возможно, с использованием wait()), а для действия GUI notify() вернуть его в состояние бодрствования после выполнения действия. .

...