Ошибка, которая меня раздражает, такая же, как этот билет . По сути, если вы измените часы ОС на дату в прошлом, все потоки, которые спали в момент изменения, не будут активированы.
Приложение, которое я разрабатываю, должно работать 24 часа в сутки, и мы хотели бы иметь возможность изменять дату ОС, не останавливая ее (например, переключаться с летнего времени на зимнее время). На данный момент происходит то, что когда мы изменяем дату на прошлое, некоторые части приложения просто замирают. Я наблюдал это на нескольких машинах, в Windows XP и Linux 2.6.37, а также с недавней JVM (1.6.0.22).
Я пробовал много спящих примитивов Java, но все они ведут себя одинаково:
- Thread.sleep (длинный)
- Thread.sleep (long, int)
- Object.wait (длинный)
- Object.wait (long, int)
- Thread.join (длинный)
- Thread.join (long, int)
- LockSupport.parkNanos (длинный)
- java.util.Timer
- javax.swing.Timer
Теперь у меня нет идеи обойти эту проблему. Я думаю, что я ничего не могу сделать, чтобы предотвратить замерзание спящих нитей. Но я хотел бы, по крайней мере, предупредить пользователя при обнаружении опасного изменения системных часов.
Я создал поток мониторинга, который обнаруживает такие изменения:
Thread t = new Thread(new Runnable() {
@Override
public void run() {
long ms1 = System.currentTimeMillis();
long ms2;
while(true) {
ms2 = ms1;
ms1 = System.currentTimeMillis();
if (ms1 < ms2) {
warnUserOfPotentialFreeze();
}
Thread.yield();
}
}
});
t.setName("clock monitor");
t.setPriority(Thread.MIN_PRIORITY);
t.setDaemon(true);
t.start();
Проблема заключается в том, что это приводит к увеличению загрузки ЦП с 2% до 15% в режиме ожидания.
У вас есть идея обойти исходную проблему, или вы можете придумать другой способ контролировать появление замораживания потоков?
Редактировать
Инго предложил не трогать системные часы. Я согласен, что это вообще не нужно. Проблема в том, что мы не контролируем, что наши клиенты делают со своими компьютерами (мы планируем продавать сотни копий).
Хуже того: одна из наших машин демонстрирует эту проблему без какого-либо ручного вмешательства. Я предполагаю, что ОС (Windows XP) регулярно синхронизирует свои часы с часами RTC, и это заставляет часы ОС возвращаться во времени естественным образом.
Эпилог
Я обнаружил, что некоторые утверждения в моем вопросе были неверными. На самом деле есть две отдельные причины, связанные с моей первоначальной проблемой. Теперь я могу точно сказать две вещи:
Только на моем компьютере (archlinux с ядром 2.6.37 с OpenJDK 64 бит 1.6.0_22), Thread.sleep
, Object.wait
, Thread.join
, LockSupport.parkNanos
имеют ту же проблему: они просыпаются только когда системные часы достигают «целевого» времени пробуждения. Тем не менее, простой sleep
в моей оболочке не представляет проблемы.
На всех машинах, которые я тестировал (включая мою), java.util.Timer
и java.swing.Timer
имеют одинаковую проблему (они блокируются, пока не достигнуто «целевое» время).
Итак, я заменил все java Timer
на более простую реализацию. Это решает проблему для всех машин, кроме моей (я просто надеюсь, что моя машина - исключение, а не правило).