Ответ 1
Работает ли ваше приложение в виртуальной среде? Я бы рекомендовал попробовать без VM.
Здесь мой простой код для циклирования каждую секунду (не обязательно точный) и при необходимости начинайте работу:
while (true) {
// check db for new jobs and
// kick off thread if necessary
try {
Thread.sleep(1000);
} catch(Throwable t) {
LOG.error("", t);
}
}
Этот код работал отлично в течение нескольких месяцев. Только вчера у нас начались проблемы, когда один из наших серверов, похоже, висел в методе Thread.sleep(1000). IOW - прошло более одного дня, а Thread.sleep не вернулся. Я запустил jconsole и получил эту информацию о потоке.
Name: Thread-3
State: TIMED_WAITING
Total blocked: 2 Total waited: 2,820
Stack trace:
java.lang.Thread.sleep(Native Method)
xc.mst.scheduling.Scheduler.run(Scheduler.java:400)
java.lang.Thread.run(Thread.java:662)
Scheduler.java:400 - это строка Thread.sleep выше. Выход jconsole не увеличивает "Total waited" каждую секунду, как я ожидал. На самом деле это совсем не меняется. Я даже закрыл jconsole и начал его резервное копирование в надежде, что, возможно, это заставит обновить, но снова получит одинаковые цифры. Я не знаю, какое другое объяснение могло бы быть, кроме того, что jvm неправильно висел в команде сна. В мои годы, однако, у меня было так мало проблем с jvm, что я предполагаю, что это должно быть надзором с моей стороны.
note: Другая вещь, которую следует отметить, - это то, что никакой другой поток не активен. IOW - процессор почти не работает. Я где-то читал, что Thread.sleep может быть законно голоден, если другой поток активен, но здесь это не так.
версия солярия:
$ uname -a
SunOS xcmst 5.10 Generic_141415-08 i86pc i386 i86pc
версия java:
$ java -version
java version "1.6.0_26"
Java(TM) SE Runtime Environment (build 1.6.0_26-b03)
Java HotSpot(TM) Server VM (build 20.1-b02, mixed mode)
Работает ли ваше приложение в виртуальной среде? Я бы рекомендовал попробовать без VM.
В дополнение к тому, что упоминалось в bdonlan, вы можете захотеть изучить ScheduledThreadPoolExecutor. Я работаю над очень похожим типом проекта, и этот объект облегчил мою жизнь благодаря этому небольшому фрагменту.
Если какое-либо выполнение этой задачи занимает больше времени, чем ее период, последующие казни могут начинаться поздно, но не будут одновременно выполнить.
Надеюсь, это поможет!
Зависит ли вы от количества циклов системы, чтобы увеличить монотонно?
Из того, что я слышал от кого-то, кто-то испытал это, иногда бывает, что системный тик идет назад одним или двумя тиками. Я еще не испытал этого, но если вы зависите от этого, может ли это объяснить, что происходит?
Когда я сказал System.currentTimeMillis()
, я считаю, что ошибся. Я думал, что System.currentTimeMillis()
похож на функцию Windows GetTickCount()
(т.е. Измеряет время, не зависящее от системного времени), но на самом деле это, похоже, не так. Поэтому, конечно, это может измениться, но это не моя точка зрения: по-видимому, количество отсчетов, измеренное системным таймером, также может идти назад по тику или два, даже игнорируя изменения системного времени. Не уверен, что это помогает, но благодаря Раэдвальду за то, что он указал на возможность изменения времени в системе, поскольку это не то, что я имел в виду.
Я знаю, что вы смотрели в jconsole, но может быть полезно отправить сигнал 3 в процесс (т.е. kill -3) и опубликовать здесь больше данных о дате загрузки потока. Или, если вы действительно хотите вдаваться в детали, вы можете подумать о том, чтобы быстро или быстро выбрать один или несколько стайков pstack/jstack для зависания, чтобы показать, где действительно существуют потоки. Информация доступна в Интернете о том, как соотнести эту информацию с дампом потока java.
Также, на "одном из наших серверов", вы говорите, что проблема воспроизводится на одном сервере, но это никогда не происходит на других серверах? Это указывает на проблему с этим сервером. Убедитесь, что на серверах все одинаково и что на этом оборудовании нет проблем.
Наконец, это может быть не проблема Java как таковая. Thread.sleep(long) - это собственный метод (отображается непосредственно на управление потоками операционной системы), поэтому проверьте, что ваша ОС обновлена.
Считаете ли вы использование Timer и TimerTask.
Вот простой фрагмент, который может помочь.
import java.util.Calendar;
import java.util.Timer;
import java.util.TimerTask;
public class Example {
public static void main(String args[]) {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
Calendar instance = Calendar.getInstance();
System.out.println("time: " + instance.getTime() + " : " + instance.getTimeInMillis());
// check db for new jobs and
// kick off thread if necessary
}
};
int startingDelay = 0; // timer task will be started after startingDelay
int period = 1000; // you are using it as sleeping time in your code
timer.scheduleAtFixedRate(task, startingDelay, period);
}
}
ИЗМЕНИТЬ
В соответствии с обсуждениями, которые я изучил, Thread.sleep() is the sign of poorly designed code.
Причины
Какая из них лучше вместо Thread.sleep()? Что вызывает другой вопрос. Я предлагаю вам взглянуть в главе concurrency из книги Effective Java
.
Thread.sleep() не является хорошей практикой в программировании на Java. Просто Google "Is Thread.sleep() плохо?" и вы увидите мою мысль.
Во-первых, он делает текущий поток недоступным для других частей программы, особенно если он многопоточен. Возможно, именно поэтому вы испытываете завивку.
Во-вторых, было бы катастрофично, если текущий поток будет EDT (Event Dispatch Thread), а приложение имеет Swing GUI.
Лучшей альтернативой может быть Object.wait():
final Object LOCK = new Object();
final long SLEEP = 1000;
public void run() {
while (true) {
// check db for new jobs and
// kick off thread if necessary
try {
synchronize (LOCK) {
LOCK.wait(SLEEP);
}
} catch (InterruptedException e) {
// usually interrupted by other threads e.g. during program shutdown
break;
}
}
}
Возможно, вы можете попробовать другой инструмент, отличный от Jconsole, чтобы сначала подтвердить, что он является блоком в api sleep.
Например, вручную попробуйте использовать jstack, чтобы печатать его в файл много раз и проверить результат.
Или используйте лучший инструмент, такой как Youkit (commercail), если ваша организация имеет лицензию для глубокого профилирования приложения или удаленной отладки (возможно, не может быть произведена)
ИЛИ Вы можете проверить, выполняется ли код "//check db for new jobs" во время. путем проверки регистрации или профиля или любого другого метода зависит от вашего приложения........ Если проверка db очень быстрая, а затем спящий 1 секунда, если очень вероятно, что вы всегда видите сон в трассировке стека просто потому что сравниваемая вероятность....