Java: Führen Sie eine Funktion nach einer bestimmten Anzahl von Sekunden aus

148

Ich habe eine bestimmte Funktion, die ich nach 5 Sekunden ausführen möchte. Wie kann ich das in Java machen?

Ich habe javax.swing.timer gefunden, kann aber nicht wirklich verstehen, wie man es benutzt. Es sieht so aus, als würde ich nach etwas suchen, das viel einfacher ist als diese Klasse.

Bitte fügen Sie ein einfaches Anwendungsbeispiel hinzu.

ufk
quelle
Möchten Sie 5 Sekunden warten und dann etwas ausführen oder möchten Sie in den 5 Sekunden etwas anderes tun?
whiskeysierra
Ich möchte weiterhin etwas anderes tun
ufk

Antworten:

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

BEARBEITEN:

Javadoc sagt:

Nachdem der letzte Live-Verweis auf ein Timer-Objekt verschwunden ist und alle ausstehenden Aufgaben ausgeführt wurden, wird der Taskausführungsthread des Timers ordnungsgemäß beendet (und unterliegt der Speicherbereinigung). Dies kann jedoch beliebig lange dauern.

Tangens
quelle
1
Wenn Sie diesen Code ausführen, werden Threads verloren gehen. Stellen Sie sicher, dass Sie den Timer bereinigen, wenn Sie fertig sind.
Skaffman
1
@skaffman: Ich habe eine Erklärung aus dem Javadoc hinzugefügt. Müssen Sie wirklich aufräumen, nachdem Sie den Zeitplan angerufen haben?
Tangens
1
Es könnte in Ordnung sein, aber dann könnte es nicht sein. Wenn Sie dieses Codefragment mehrmals ausführen, treten lose Threads auf, ohne dass Sie sie aufräumen können.
Skaffman
5
import java.util.Timer; import java.util.TimerTask;könnte es offensichtlicher machen, dass dies nicht ist javax.swing.Timer. / Hinweis: Wenn Sie Swing (und tatsächlich AWT) verwenden, sollten Sie nichts tun, um Komponenten in EDT-Threads (Non-Event Dispatch Thread) zu ändern ( java.util.TimerAufgaben schlecht; javax.swing.TimerAktionen gut).
Tom Hawtin - Tackline
2
@PaulAlexander Laut docs würde das Aufrufen der Timer- cancelMethode am Ende der Ausführungsmethode den Ausführungsthread der TimerTasks löschen.
Dandalf
58

Etwas wie das:

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

Es gibt verschiedene andere Factory-Methoden, Executordie Sie stattdessen verwenden können, wenn Sie mehr Threads im Pool wünschen.

Und denken Sie daran, es ist wichtig, den Executor herunterzufahren, wenn Sie fertig sind. Die shutdown()Methode fährt den Thread-Pool nach Abschluss der letzten Aufgabe sauber herunter und blockiert ihn, bis dies geschieht. shutdownNow()beendet den Thread-Pool sofort.

Skaffman
quelle
24

Anwendungsbeispiel 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!

Dieser Code wird nur einmal ausgeführt und erfolgt in 3000 ms (3 Sekunden).

Wie camickr erwähnt, sollten Sie für eine kurze Einführung nach "Verwendung von Swing-Timern " suchen .

zpon
quelle
6

Mein Code lautet wie folgt:

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
quelle
5

Als Variation von @tangens Antwort: Wenn Sie nicht warten können, bis der Garbage Collector Ihren Thread bereinigt, brechen Sie den Timer am Ende Ihrer Ausführungsmethode ab.

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
quelle
Sollte nicht Timer tdeklariert werden, finalda innerhalb einer inneren Klasse darauf zugegriffen wird?
Joshua Pinter
1
@JoshuaPinter Ja, es sollte als endgültig deklariert werden, aber es muss in mindestens Java 8 nicht explizit als endgültig deklariert werden. Es muss nur "effektiv endgültig" sein ( javarevisited.blogspot.com/2015/03/… )
Dandalf
4

Ihre ursprüngliche Frage erwähnt den "Swing Timer". Wenn Ihre Frage tatsächlich mit SWing zusammenhängt, sollten Sie den Swing-Timer und NICHT den util.Timer verwenden.

Weitere Informationen finden Sie im Abschnitt aus dem Swing-Tutorial zum Thema " Verwenden von Timern ".

camickr
quelle
4

Sie können die Thread.Sleep () -Funktion verwenden

Thread.sleep(4000);
myfunction();

Ihre Funktion wird nach 4 Sekunden ausgeführt. Dies kann jedoch das gesamte Programm anhalten ...

Tal
quelle
Und es garantiert nur, dass die Ausführung nach 4 Sekunden ausgeführt wird, was auch nach 10 Sekunden bedeuten kann!
Questzen
2
In Questzen werden Sie feststellen, dass alle Methoden hier dies tun. Selbst wenn Sie etwas auf Betriebssystemebene planen, können Sie im Allgemeinen nur eine minimale verstrichene Zeit vor einem Ereignis garantieren.
Ethan
Dies ist nicht die eigentliche Frage
Inder R Singh
Ich musste dies nur ablehnen - überhaupt keine Antwort auf die vorliegende Frage.
theMayer
OP sagte in einem Kommentar "Ich möchte weiterhin etwas anderes tun"; Dieser Code tut es offensichtlich nicht.
Abhijit Sarkar
3

ScheduledThreadPoolExecutor hat diese Fähigkeit, aber es ist ziemlich schwer.

Timer hat auch diese Fähigkeit, öffnet aber mehrere Threads, auch wenn sie nur einmal verwendet werden.

Hier ist eine einfache Implementierung mit einem Test (Signatur in der Nähe von Handler.postDelayed () von 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();
    }
}

Prüfung:

@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
quelle
es gibt Warnung Schlaf in einer Schleife
aufgerufen
Das whileist nur um Unterbrechung zu ignorieren.
AlikElzin-kilaka
2

Alle anderen Antworten müssen Ihren Code in einem neuen Thread ausführen. In einigen einfachen Anwendungsfällen möchten Sie möglicherweise nur ein wenig warten und die Ausführung innerhalb desselben Threads / Flusses fortsetzen.

Der folgende Code demonstriert diese Technik. Denken Sie daran, dass dies ähnlich ist wie java.util.Timer unter der Haube, aber leichter.

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-Implementierung

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
quelle
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.
quelle
2
Während dieser Code die Frage möglicherweise beantwortet, verbessert die Bereitstellung eines zusätzlichen Kontexts darüber, warum und / oder wie dieser Code die Frage beantwortet, ihren langfristigen Wert.
Mateus