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.