Подтвердить что ты не робот

Thread.sleep() висит?

Здесь мой простой код для циклирования каждую секунду (не обязательно точный) и при необходимости начинайте работу:

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)
4b9b3361

Ответ 1

Работает ли ваше приложение в виртуальной среде? Я бы рекомендовал попробовать без VM.

Ответ 2

В дополнение к тому, что упоминалось в bdonlan, вы можете захотеть изучить ScheduledThreadPoolExecutor. Я работаю над очень похожим типом проекта, и этот объект облегчил мою жизнь благодаря этому небольшому фрагменту.

ScheduleAtFixedRate

Если какое-либо выполнение этой задачи занимает больше времени, чем ее период, последующие казни могут начинаться поздно, но не будут одновременно выполнить.

Надеюсь, это поможет!

Ответ 3

Зависит ли вы от количества циклов системы, чтобы увеличить монотонно?

Из того, что я слышал от кого-то, кто-то испытал это, иногда бывает, что системный тик идет назад одним или двумя тиками. Я еще не испытал этого, но если вы зависите от этого, может ли это объяснить, что происходит?

Edit:

Когда я сказал System.currentTimeMillis(), я считаю, что ошибся. Я думал, что System.currentTimeMillis() похож на функцию Windows GetTickCount() (т.е. Измеряет время, не зависящее от системного времени), но на самом деле это, похоже, не так. Поэтому, конечно, это может измениться, но это не моя точка зрения: по-видимому, количество отсчетов, измеренное системным таймером, также может идти назад по тику или два, даже игнорируя изменения системного времени. Не уверен, что это помогает, но благодаря Раэдвальду за то, что он указал на возможность изменения времени в системе, поскольку это не то, что я имел в виду.

Ответ 4

Я знаю, что вы смотрели в jconsole, но может быть полезно отправить сигнал 3 в процесс (т.е. kill -3) и опубликовать здесь больше данных о дате загрузки потока. Или, если вы действительно хотите вдаваться в детали, вы можете подумать о том, чтобы быстро или быстро выбрать один или несколько стайков pstack/jstack для зависания, чтобы показать, где действительно существуют потоки. Информация доступна в Интернете о том, как соотнести эту информацию с дампом потока java.

Также, на "одном из наших серверов", вы говорите, что проблема воспроизводится на одном сервере, но это никогда не происходит на других серверах? Это указывает на проблему с этим сервером. Убедитесь, что на серверах все одинаково и что на этом оборудовании нет проблем.

Наконец, это может быть не проблема Java как таковая. Thread.sleep(long) - это собственный метод (отображается непосредственно на управление потоками операционной системы), поэтому проверьте, что ваша ОС обновлена.

Ответ 5

Считаете ли вы использование 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.

Какая из них лучше вместо Thread.sleep()? Что вызывает другой вопрос. Я предлагаю вам взглянуть в главе concurrency из книги Effective Java.

Ответ 6

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;
    }

  }
}

Ответ 7

Возможно, вы можете попробовать другой инструмент, отличный от Jconsole, чтобы сначала подтвердить, что он является блоком в api sleep.

Например, вручную попробуйте использовать jstack, чтобы печатать его в файл много раз и проверить результат.

Или используйте лучший инструмент, такой как Youkit (commercail), если ваша организация имеет лицензию для глубокого профилирования приложения или удаленной отладки (возможно, не может быть произведена)

ИЛИ Вы можете проверить, выполняется ли код "//check db for new jobs" во время. путем проверки регистрации или профиля или любого другого метода зависит от вашего приложения........ Если проверка db очень быстрая, а затем спящий 1 секунда, если очень вероятно, что вы всегда видите сон в трассировке стека просто потому что сравниваемая вероятность....