Java: запустить функцию через определенное количество секунд

148

У меня есть особая функция, которую я хочу выполнить через 5 секунд. Как я могу сделать это на Java?

Я нашел javax.swing.timer, но я не могу понять, как его использовать. Похоже, я ищу что-то более простое, чем этот класс.

Пожалуйста, добавьте простой пример использования.

УФК
источник
Вы хотите подождать 5 секунд, а затем выполнить что-то или вы хотите продолжить делать что-то еще в течение 5 секунд?
вискисьерра
я хочу продолжать делать что-то еще
UFK

Ответы:

230
new java.util.Timer().schedule( 
        new java.util.TimerTask() {
            @Override
            public void run() {
                // your code here
            }
        }, 
        5000 
);

РЕДАКТИРОВАТЬ:

Джавадок говорит:

После того, как последняя действующая ссылка на объект Timer исчезнет, ​​и все нерешенные задачи завершат выполнение, поток выполнения задач таймера завершится изящно (и станет объектом сбора мусора). Однако это может произойти как угодно долго.

Тангенс
источник
1
Если вы запустите этот код, вы пропустите потоки. Не забудьте очистить таймер, когда вы закончите.
Скаффман
1
@skaffman: я добавил заявление от Javadoc. Вы действительно должны убирать после графика звонков?
тангенс
1
Это может быть хорошо, но тогда это не может быть. Если вы запустите этот фрагмент кода несколько раз, у вас будут рваться свободные потоки, без возможности привести их в порядок.
Скаффман
5
import java.util.Timer; import java.util.TimerTask;может сделать это более очевидным, что это не так javax.swing.Timer. / Обратите внимание: если вы используете Swing (и фактически AWT), вам не нужно ничего делать для изменения компонентов в потоках не-Event Dispatch Thread (EDT) ( java.util.Timerзадачи плохие; javax.swing.Timerхорошие действия).
Том Хотин - tackline
2
@PaulAlexander В соответствии с документами - вызов cancelметода таймера в конце метода run очистит поток выполнения TimerTasks.
Дэндальф
58

Что-то вроде этого:

// When your program starts up
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();

// then, when you want to schedule a task
Runnable task = ....    
executor.schedule(task, 5, TimeUnit.SECONDS);

// and finally, when your program wants to exit
executor.shutdown();

Существуют различные другие фабричные методы, Executorкоторые вы можете использовать вместо этого, если вам нужно больше потоков в пуле.

И помните, важно завершить работу исполнителя, когда вы закончите. shutdown()Метод будет чисто закрыть пул потоков , когда последняя задача завершена, и будет блокироваться , пока это не произойдет. shutdownNow()немедленно прекратит пул потоков.

skaffman
источник
24

Пример использования javax.swing.Timer

Timer timer = new Timer(3000, new ActionListener() {
  @Override
  public void actionPerformed(ActionEvent arg0) {
    // Code to be executed
  }
});
timer.setRepeats(false); // Only execute once
timer.start(); // Go go go!

Этот код будет выполнен только один раз, а выполнение происходит за 3000 мс (3 секунды).

Как упоминает camickr, вам следует поискать « Как использовать Swing Timers » для краткого введения.

zpon
источник
6

Мой код выглядит следующим образом:

new java.util.Timer().schedule(

    new java.util.TimerTask() {
        @Override
        public void run() {
            // your code here, and if you have to refresh UI put this code: 
           runOnUiThread(new   Runnable() {
                  public void run() {
                            //your code

                        }
                   });
        }
    }, 
    5000 
);
user2885850
источник
5

Как вариант ответа @tangens: если вы не можете дождаться, когда сборщик мусора очистит ваш поток, отмените таймер в конце вашего метода run.

Timer t = new java.util.Timer();
t.schedule( 
        new java.util.TimerTask() {
            @Override
            public void run() {
                // your code here
                // close the thread
                t.cancel();
            }
        }, 
        5000 
);
Dandalf
источник
Не должен Timer tбыть объявлен, finalтак как к нему обращаются внутри внутреннего класса?
Джошуа Пинтер
1
@JoshuaPinter Да, он должен быть объявлен финальным, но его не нужно явно объявлять финальным, по крайней мере, в Java 8. Он просто должен быть «эффективно финальным» ( javarevisited.blogspot.com/2015/03/… )
Dandalf
4

Ваш оригинальный вопрос упоминает «Таймер качания». Если на самом деле ваш вопрос связан с SWing, то вам следует использовать Swing Timer, а НЕ util.Timer.

Прочтите раздел из руководства по Swing « Как использовать таймеры » для получения дополнительной информации.

camickr
источник
4

Вы можете использовать функцию Thread.Sleep ()

Thread.sleep(4000);
myfunction();

Ваша функция будет выполнена через 4 секунды. Однако это может приостановить всю программу ...

дол
источник
И это только гарантирует, что выполнение будет выполнено через 4 секунды, что может означать и через 10 секунд!
Questzen
2
questzen, вы обнаружите, что все методы здесь делают это. На самом деле, даже если вы планируете что-то на уровне ОС, вы, как правило, можете гарантировать только минимальное время, прошедшее до события.
Итан
Это не то, что был фактический вопрос
Inder R Singh
Я просто должен был дать это отрицательное голосование - совсем не ответ на поставленный вопрос.
The Mayer
ОП сказал в комментарии: «Я хочу продолжать делать что-то еще»; этот код, очевидно, не.
Абхиджит Саркар
3

ScheduledThreadPoolExecutor имеет эту способность, но она довольно тяжелая.

Timer также имеет эту способность, но открывает несколько потоков, даже если используется только один раз.

Вот простая реализация с тестом (подпись близка к Android Handler.postDelayed () ):

public class JavaUtil {
    public static void postDelayed(final Runnable runnable, final long delayMillis) {
        final long requested = System.currentTimeMillis();
        new Thread(new Runnable() {
            @Override
            public void run() {
                // The while is just to ignore interruption.
                while (true) {
                    try {
                        long leftToSleep = requested + delayMillis - System.currentTimeMillis();
                        if (leftToSleep > 0) {
                            Thread.sleep(leftToSleep);
                        }
                        break;
                    } catch (InterruptedException ignored) {
                    }
                }
                runnable.run();
            }
        }).start();
    }
}

Тест:

@Test
public void testRunsOnlyOnce() throws InterruptedException {
    long delay = 100;
    int num = 0;
    final AtomicInteger numAtomic = new AtomicInteger(num);
    JavaUtil.postDelayed(new Runnable() {
        @Override
        public void run() {
            numAtomic.incrementAndGet();
        }
    }, delay);
    Assert.assertEquals(num, numAtomic.get());
    Thread.sleep(delay + 10);
    Assert.assertEquals(num + 1, numAtomic.get());
    Thread.sleep(delay * 2);
    Assert.assertEquals(num + 1, numAtomic.get());
}
AlikElzin-kilaka
источник
он выдает предупреждение, что сон вызывается в цикле
shareef
whileПросто игнорировать прерывание.
Алик Эльзин-килака
2

Все остальные ответы требуют запуска вашего кода в новом потоке. В некоторых простых случаях вы можете просто немного подождать и продолжить выполнение в том же потоке / потоке.

Код ниже демонстрирует эту технику. Имейте в виду, что это похоже на то, что java.util.Timer делает под капотом, но более легкий.

import java.util.concurrent.TimeUnit;
public class DelaySample {
    public static void main(String[] args) {
       DelayUtil d = new DelayUtil();
       System.out.println("started:"+ new Date());
       d.delay(500);
       System.out.println("half second after:"+ new Date());
       d.delay(1, TimeUnit.MINUTES); 
       System.out.println("1 minute after:"+ new Date());
    }
}

Реализация DelayUtil

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class DelayUtil {
    /** 
    *  Delays the current thread execution. 
    *  The thread loses ownership of any monitors. 
    *  Quits immediately if the thread is interrupted
    *  
    * @param duration the time duration in milliseconds
    */
   public void delay(final long durationInMillis) {
      delay(durationInMillis, TimeUnit.MILLISECONDS);
   }

   /** 
    * @param duration the time duration in the given {@code sourceUnit}
    * @param unit
    */
    public void delay(final long duration, final TimeUnit unit) {
        long currentTime = System.currentTimeMillis();
        long deadline = currentTime+unit.toMillis(duration);
        ReentrantLock lock = new ReentrantLock();
        Condition waitCondition = lock.newCondition();

        while ((deadline-currentTime)>0) {
            try {
                lock.lockInterruptibly();    
                waitCondition.await(deadline-currentTime, TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            } finally {
                lock.unlock();
            }
            currentTime = System.currentTimeMillis();
        }
    }
}
Valchkou
источник
2
public static Timer t;

public synchronized void startPollingTimer() {
        if (t == null) {
            TimerTask task = new TimerTask() {
                @Override
                public void run() {
                   //Do your work
                }
            };

            t = new Timer();
            t.scheduleAtFixedRate(task, 0, 1000);
        }
    }
Амол К
источник
2
Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, почему и / или как этот код отвечает на вопрос, повышает его долгосрочную ценность.
Матеус