Эффективность с помощью Thread.sleep()

#java #multithreading #thread-sleep #coding-efficiency

#java #многопоточность #поток-сон #кодирование-эффективность

Вопрос:

Здесь у меня есть немного кода, который работает так, как я хочу. Все, что это — обратный отсчет в секундах до определенной даты, которую я определяю в коде. Я использую Thread.currentThread().sleep(1000); для обновления JLabel с текущим временем, оставшимся до даты. Проблема в том, что JLabel не обновляется каждую секунду, как предполагалось. Иногда он обновляется каждые 2 секунды, в других случаях для обновления требуется целых 10 секунд. Я считаю, что это как-то связано с тем, как я вызываю свои методы, но я не совсем уверен, как сделать это более эффективным.

Вот основной метод, который вызывает метод для обновления JLabel в потоке:

 public static void main(String args[])
{
    initUI();
    try
    {
        while(true)
        {
            Thread.currentThread().sleep(1000);
            getTime();
        }
    } catch(Exception e){System.out.println("An error has occured...");}
}
  

Вот метод, вызываемый методом, вызываемым методом main . Этот метод в конечном итоге отправляет переменную, оставшуюся в секундах, в 3-й метод:

 public static void getTime()
{
    Calendar c = Calendar.getInstance();
    // Gets abstract current time in ms
    long now = c.getTimeInMillis();

    c.set(Calendar.HOUR_OF_DAY, 0);
    c.set(Calendar.MINUTE, 0);
    c.set(Calendar.SECOND, 0);
    c.set(Calendar.MILLISECOND, 0);

    // Gets current time in ms
    long msPassed = now - c.getTimeInMillis();
    // There are 86,400,000 milliseconds in a day
    // Gets the seconds remaining in the day
    long secRemaining = (86400000 - msPassed) / 1000;

    //-----------------------------------------------------// 
    // Creates a new calendar for today
    Calendar cal = Calendar.getInstance();
    int currentDayOfYear = cal.get(Calendar.DAY_OF_YEAR);

    // Creates a calendar for November 20th, 2016
    Calendar aniv = new GregorianCalendar(2016,10,20);
    aniv.set(Calendar.MONTH, 10);
    aniv.set(Calendar.DAY_OF_MONTH, 20);
    int aniversary = aniv.get(Calendar.DAY_OF_YEAR);

    remaining = ((aniversary - currentDayOfYear) * 24 * 60 * 60)   secRemaining;
    setTextOnScreen(remaining);
}
  

И, наконец, это метод, который перезаписывает JLabel (вызывается описанным выше методом):

 public static void setTextOnScreen(long num)
{
    text.setForeground(Color.GREEN);
    text.setLocation((int)width/2 - 150, 50);
    text.setFont(new Font("Monospaced", Font.BOLD, 48));
    text.setSize(300,150);

    text.setText(""   num);
    panel.add(text);
}
  

Я не включаю остальную часть кода, потому что это должно быть неактуальным, но если вы тоже хотите это увидеть, просто дайте мне знать.

Комментарии:

1. Ваш сон длится 2 секунды

Ответ №1:

Две проблемы:

  1. Вы вызываете text.setSomething() и panel.add из фонового потока, который не является потоком пользовательского интерфейса, который вы должны использовать. Попробуйте использовать SwingUtils.invokeLater() или SwingUtils.invokeAndWait() и вызвать код, который касается пользовательского интерфейса.

  2. После вызова ваших set методов вы также должны вызвать text.invalidate() сигнал о том, что компоненты пользовательского интерфейса необходимо обновить … в противном случае поток пользовательского интерфейса не заметит, что компонент необходимо переизмерить и перерисовать.

Ответ №2:

Вы должны обновлять компоненты GUI только в цикле событий. Если вы попытаетесь обновить их в других потоках, вы можете получить непредсказуемые результаты. Я предлагаю использовать таймер переключения для периодических задач, которые будут выполняться в цикле событий GUI.

Ответ №3:

Вы могли бы попробовать использовать Timer

У него есть метод #scheduleAtFixedRate , который примет задачу для выполнения, время для начала ее выполнения и интервал, с которого он должен выполнить задачу.

Оберните запланированные действия в класс, который расширяется TimerTask для использования с этим методом.

Вот javadocs для этого класса в Java 7 https://docs.oracle.com/javase/7/docs/api/java/util/Timer.html