Альтернатива Thread.Sleep в Java
Мне сказали, что с помощью Thread.Sleep()
порой это плохое решение, когда кто-то захочет создать некоторый интервал времени в цикле действий в синхронизированном методе.
С другой стороны, у меня есть два разных потока, которые активны на протяжении всего времени выполнения моей программы, а также один общий объект, и когда я использую Object.wait (long) в этом общем объекте, это приводит к зависанию моего GUI на некоторое время.
что будет лучшим решением для этой проблемы?
Обновление Эта часть кода включает в себя один из потоков, который запускается в графическом интерфейсе:
class temperatureUp extends Thread
{
@Override
public void run()
{
while(true)
{
try
{
GBC.increaseTemp();
updateSystemStatus();
}
catch(Exception ex)
{
StringWriter w = new StringWriter();
ex.printStackTrace(new PrintWriter(w));
txtLog.setText(w + "\n" + txtLog.getText());
}
}
}
};
и это синхронизированный метод в общем объекте, GBC:
public synchronized void increaseTemp() throws InterruptedException{
// don't increase the temperature if the boiler
// is not turned on...
while (!isBoilerOn)
wait();
// increase the current temperature
if ((currentTemp + 1) < MAX_TEMP && currentTemp < desiredTemp) {
Thread.sleep(2000); ///what should put here if not thread sleep?
currentTemp ++;
updateGasBoilerStatus();
}
}
5 ответов
Не спите внутри синхронизированного метода! Не ждите в обработчиках событий GUI / методах!
Разделите синхронизированные действия так, чтобы вызов Sleep() не вызывался в контексте потока GUI.
Может быть, использовать InvokeLater() для второго бита.
Вы могли бы уменьшить масштаб synchronize
заявление. Например, если вы синхронизируете весь метод
public synchronized void foo()
Вы можете удалить модификатор и использовать вместо него синхронизированный блок
synchronized (this) {
// ...
}
и переместить Thread.sleep()
за пределами этого блока, если это возможно. Синхронизировать только те операторы, которые изменяют состояния общих данных.
Многие проблемы с потоками, относящиеся к Swing, связаны с потоком диспетчера событий и могут быть легко решены с его помощью. Я рекомендую вам прочитать это.
Немного предыстории, почему не стоит звонить Thread.sleep()
внутри блока синхронизации:
Спать или ждать, держа замок. Вызов Thread.sleep с удерживаемой блокировкой может препятствовать продвижению других потоков в течение длительного времени и, следовательно, представляет собой потенциально серьезную опасность для жизни. Вызов Object.wait или Condition.await с двумя удерживаемыми блокировками представляет подобную опасность. [JCIP]
Всегда держите свой поток диспетчера событий (EDT), который отвечает за обработку вашего GUI, подальше от любой работы, не связанной с пользовательским интерфейсом. Кроме того, не синхронизируйте весь метод, но синхронизируйте атомарные операторы
synchronized(this){
//...
}
Я хотел бы использовать мониторы: http://www.artima.com/insidejvm/ed2/threadsynch4.html Может быть, с уведомить или уведомить все вы можете решить это. Удачи!
Вы можете попробовать этот следующий код:
public static void delay(int waitTime) {
long endTime = System.currentTimeMillis() + (waitTime * 1000);
while (System.currentTimeMillis() < endTime) {}
}
Звоните как задержка (5). И контроль будет ждать 5 секунд.