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


148

У мене є певна функція, яку я хочу виконати через 5 секунд. Як я можу це зробити на Java?

Я знайшов javax.swing.timer, але я не можу зрозуміти, як ним користуватися. Схоже, я шукаю щось простіше, ніж цей клас.

Додайте простий приклад використання.


Ви хочете зачекати 5 секунд, а потім виконати щось або ви хочете продовжувати робити щось ще протягом 5 секунд?
віскісієра

Я хочу продовжувати робити щось інше
ufk

Відповіді:


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

Редагувати:

javadoc каже:

Після того, як остання посилання на об'єкт «Таймер» в реальному часі закінчується, і всі невиконані завдання завершено, потік виконання завдання таймера граціозно припиняється (і стає предметом збирання сміття). Однак це може тривати довільно довго.


1
Якщо ви запустите цей код, ви протікаєте потоки. Обов’язково очистіть таймер, коли закінчите.
скафман

1
@skaffman: Я додав заяву від javadoc. Вам справді потрібно прибиратись після розкладу дзвінків?
tangens

1
Це може бути нормально, але тоді це може бути не так. Якщо ви запустите цей фрагмент коду кілька разів, у вас з’являться розпущені нитки, не виправляючи їх.
скафман

5
import java.util.Timer; import java.util.TimerTask;може зробити більш очевидним, що це не так javax.swing.Timer. / Зауважте, якщо ви використовуєте Swing (а насправді AWT), ви не повинні нічого робити для зміни компонентів у потоках відправки Discatch Thread (EDT) без подій ( java.util.Timerзавдання погані; javax.swing.Timerдії хороші).
Том Хотін - тайклін

2
@PaulAlexander Згідно з cancelметодом docs - виклик таймера в кінці методу запуску очистить порядок виконання програми 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()негайно припинить пул потоків.


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, для короткого ознайомлення вам слід знайти " Як користуватися таймерами ".


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

5

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

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

Чи не Timer tслід задекларувати, finalоскільки це доступ до внутрішнього класу?
Джошуа Пінтер

1
@JoshuaPinter Так, його слід оголосити остаточним, але його не потрібно чітко оголошувати остаточним принаймні на Java 8. Це просто має бути "ефективно остаточним" ( javarevisited.blogspot.com/2015/03/… )
Dandalf

4

У вашому оригінальному запитанні згадується "Таймер гойдалки". Якщо насправді ваше питання пов'язане з SWing, то вам слід скористатися таймером Swing, а НЕ util.Timer.

Прочитайте розділ підручника Swing на тему " Як користуватися таймерами " для отримання додаткової інформації.


4

ви можете використовувати функцію Thread.Sleep ()

Thread.sleep(4000);
myfunction();

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


І це лише гарантує, що виконання буде запущено через 4 сек, що може означати і через 10 секунд!
квестен

2
questzen, ви побачите, що всі методи тут роблять це. Насправді, навіть якщо ви плануєте щось на рівні ОС, ви, як правило, можете гарантувати лише мінімальний час, який пройшов до події.
Етан

Це не те, що було актуальним
Inder R Singh

Мені просто довелося дати це зворотне запитання - зовсім не відповідь на відповідне питання.
theMayer

ОП сказав у коментарі "я хочу продовжувати робити щось інше"; цей код, очевидно, не робить.
Абхіджіт Саркар

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

це дає попереджувальний сон, викликаний у циклі
shareef

Це whileпросто ігнорувати переривання.
AlikElzin-kilaka

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

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
Хоча цей код може відповісти на питання, надаючи додатковий контекст стосовно того, чому та / або як цей код відповідає на питання, покращує його довгострокове значення.
Матеус
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.