java: uruchamia funkcję po określonej liczbie sekund

148

Mam określoną funkcję, którą chcę wykonać po 5 sekundach. Jak mogę to zrobić w Javie?

Znalazłem javax.swing.timer, ale naprawdę nie rozumiem, jak go używać. Wygląda na to, że szukam czegoś prostszego niż ta klasa.

Dodaj prosty przykład użycia.

ufk
źródło
Czy chcesz poczekać 5 sekund, a następnie coś wykonać, czy chcesz kontynuować wykonywanie czegoś innego w ciągu 5 sekund?
whiskeysierra
chcę dalej robić coś innego
ufk

Odpowiedzi:

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

EDYTOWAĆ:

javadoc mówi:

Po zniknięciu ostatniego odniesienia na żywo do obiektu Timer i zakończeniu wykonywania wszystkich zaległych zadań wątek wykonania zadania czasomierza kończy się wdzięcznie (i podlega wyrzucaniu elementów bezużytecznych). Jednak może to zająć dowolnie długi czas.

tangens
źródło
1
Uruchomienie tego kodu spowoduje wyciek wątków. Po zakończeniu pamiętaj o wyczyszczeniu timera.
skaffman
1
@skaffman: Dodałem oświadczenie z javadoc. Czy naprawdę musisz posprzątać po rozmowie telefonicznej?
tangens
1
Może być w porządku, ale może nie być. Jeśli uruchomisz ten fragment kodu wiele razy, będziesz mieć luźne wątki bez możliwości ich uporządkowania.
skaffman
5
import java.util.Timer; import java.util.TimerTask;może uczynić bardziej oczywistym, że tak nie jest javax.swing.Timer. / Uwaga, jeśli używasz Swinga (a właściwie AWT), nie powinieneś robić nic w celu zmiany komponentów w wątkach niezwiązanych z wysyłaniem zdarzeń (EDT) ( java.util.Timerzadania są złe; javax.swing.Timerdziałania dobre).
Tom Hawtin - tackline
2
@PaulAlexander Zgodnie z dokumentacją - wywołanie cancelmetody timera na końcu metody run wyczyściłoby wątek wykonania TimerTasks.
Dandalf
58

Coś takiego:

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

Istnieje wiele innych metod fabrycznych, Executorktórych możesz użyć zamiast tego, jeśli chcesz mieć więcej wątków w puli.

I pamiętaj, ważne jest, aby zamknąć executor po zakończeniu. shutdown()Metoda czysto zamknąć puli wątków, gdy ostatnie zadanie jest zakończone i będzie blokować aż tak się dzieje. shutdownNow()natychmiast zakończy pulę wątków.

skaffman
źródło
24

Przykład użycia 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!

Ten kod zostanie wykonany tylko raz, a wykonanie zajmie 3000 ms (3 sekundy).

Jak wspomina Camickr, powinieneś sprawdzić „ Jak używać zegarów Swing ”, aby uzyskać krótkie wprowadzenie.

zpon
źródło
6

Mój kod wygląda następująco:

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
źródło
5

Jako odmiana @tangens odpowiedź: jeśli nie możesz czekać, aż moduł odśmiecania pamięci wyczyści twój wątek, anuluj licznik czasu na końcu metody uruchamiania.

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
źródło
Nie powinno Timer tbyć zadeklarowane, finalponieważ jest uzyskiwane wewnątrz klasy wewnętrznej?
Joshua Pinter
1
@JoshuaPinter Tak, powinien być uznany za ostateczny, ale nie musi być jawnie ogłaszany jako ostateczny w przynajmniej Javie 8. Musi być tylko „efektywnie ostateczny” ( javarevisited.blogspot.com/2015/03/… )
Dandalf
4

Twoje pierwotne pytanie dotyczy „Swing Timer”. Jeśli w rzeczywistości twoje pytanie dotyczy SWing, powinieneś używać Swing Timer, a NIE util.Timer.

Przeczytaj sekcję z samouczka Swing na temat „ Jak używać timerów ”, aby uzyskać więcej informacji.

camickr
źródło
4

możesz użyć funkcji Thread.Sleep ()

Thread.sleep(4000);
myfunction();

Twoja funkcja zostanie wykonana po 4 sekundach. Może to jednak spowodować wstrzymanie całego programu ...

dołek
źródło
I to tylko gwarantuje, że wykonanie będzie działać po 4 sekundach, co może oznaczać również po 10 sekundach!
questzen
2
questzen, przekonasz się, że wszystkie opisane tutaj metody to robią. W rzeczywistości, nawet jeśli planujesz coś na poziomie systemu operacyjnego, generalnie możesz zagwarantować tylko minimalny czas, który upłynął przed wydarzeniem.
Ethan
Nie o to chodziło w rzeczywistości
Inder R Singh
Po prostu musiałem oddać temu głos przeciw - wcale nie odpowiadając na zadane pytanie.
Mayer
OP powiedział w komentarzu "Chcę dalej robić coś innego"; ten kod oczywiście nie.
Abhijit Sarkar
3

ScheduledThreadPoolExecutor ma tę umiejętność, ale jest dość ciężki.

Timer ma również tę zdolność, ale otwiera kilka wątków, nawet jeśli zostanie użyty tylko raz.

Oto prosta implementacja z testem (sygnatura zbliżona do Handler.postDelayed () systemu Android ):

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:

@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
źródło
daje ostrzegawczy sen wywoływany w pętli
shareef
Ma whileto na celu zignorowanie przerw.
AlikElzin-kilaka
2

Wszystkie inne odpowiedzi wymagają uruchomienia kodu w nowym wątku. W niektórych prostych przypadkach możesz po prostu trochę poczekać i kontynuować wykonywanie w tym samym wątku / przepływie.

Poniższy kod demonstruje tę technikę. Należy pamiętać, że jest to podobne do tego, co java.util.Timer robi pod maską, ale jest lżejsze.

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

Implementacja 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
źródło
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);
        }
    }
Amol K.
źródło
2
Chociaż ten kod może odpowiedzieć na pytanie, zapewnia dodatkowy kontekst dotyczący tego, dlaczego i / lub jak ten kod odpowiada, poprawia jego długoterminową wartość.
Mateus