Ошибка, которая меня раздражает, такая же, как этот билет. В принципе, если вы измените часы ОС на дату в прошлом, весь поток, который спал во время изменения, не проснется.
Приложение, которое я разрабатываю, предназначено для работы 24/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
более простой реализацией. Это решает проблему для всех машин, кроме моих (я просто надеюсь, что моя машина является исключением больше, чем правило).