java: menjalankan fungsi setelah sejumlah detik tertentu

148

Saya memiliki fungsi spesifik yang ingin saya jalankan setelah 5 detik. Bagaimana saya bisa melakukannya di Jawa?

Saya menemukan javax.swing.timer, tapi saya tidak bisa mengerti cara menggunakannya. Sepertinya saya mencari sesuatu yang lebih sederhana daripada kelas ini.

Silakan tambahkan contoh penggunaan sederhana.

Uhk
sumber
Apakah Anda ingin menunggu 5 detik dan kemudian menjalankan sesuatu atau Anda ingin terus melakukan sesuatu yang lain dalam 5 detik?
whiskeysierra
saya ingin terus melakukan sesuatu yang lain
ufk

Jawaban:

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

EDIT:

javadoc mengatakan:

Setelah referensi langsung terakhir ke objek Timer hilang dan semua tugas luar biasa telah menyelesaikan eksekusi, utas eksekusi tugas timer berakhir dengan anggun (dan menjadi sasaran pengumpulan sampah). Namun, ini bisa memakan waktu lama untuk terjadi.

tangens
sumber
1
Jika Anda menjalankan kode itu, Anda akan membocorkan utas. Pastikan untuk membersihkan penghitung waktu setelah Anda selesai.
skaffman
1
@skaffman: Saya menambahkan pernyataan dari javadoc. Apakah Anda benar-benar harus membersihkan setelah menelepon jadwal?
tangens
1
Mungkin baik-baik saja, tapi mungkin juga tidak. Jika Anda menjalankan fragmen kode itu beberapa kali, Anda akan memiliki untaian longgar tanpa bermaksud merapikannya.
skaffman
5
import java.util.Timer; import java.util.TimerTask;mungkin membuatnya lebih jelas bahwa ini bukan javax.swing.Timer. / Catatan, jika Anda menggunakan Swing (dan sebenarnya AWT), Anda tidak boleh melakukan apa pun untuk mengganti komponen pada utas Non-Event Dispatch Thread (EDT) ( java.util.Timertugas buruk; javax.swing.Timertindakan baik).
Tom Hawtin - tackline
2
@PaulAlexander Menurut dokumen - memanggil cancelmetode pencatat waktu di akhir metode jalankan akan membersihkan utas eksekusi TimerTasks.
Dandalf
58

Sesuatu seperti ini:

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

Ada berbagai metode pabrik lain Executoryang dapat Anda gunakan sebagai gantinya, jika Anda menginginkan lebih banyak utas di kolam.

Dan ingat, penting untuk mematikan eksekutor ketika Anda selesai. The shutdown()Metode akan bersih menutup kolam thread ketika tugas terakhir telah selesai, dan akan memblokir sampai ini terjadi. shutdownNow()akan segera mengakhiri kolam utas.

skaffman
sumber
24

Contoh penggunaan 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!

Kode ini hanya akan dieksekusi sekali, dan eksekusi terjadi dalam 3000 ms (3 detik).

Seperti yang disebutkan camickr, Anda harus mencari " Cara Menggunakan Pengatur Waktu Ayunan " untuk pengantar singkat.

zpon
sumber
6

Kode saya adalah sebagai berikut:

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 
);
pengguna2885850
sumber
5

Sebagai variasi jawaban @tangens: jika Anda tidak sabar menunggu pengumpul sampah untuk membersihkan utas Anda, batalkan penghitung waktu di akhir metode jalankan Anda.

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 
);
Ketombe
sumber
Tidak Timer tboleh dideklarasikan finalkarena sedang diakses di dalam kelas batin?
Joshua Pinter
1
@ JoshuaPinter Ya, harus dinyatakan final tetapi tidak perlu secara eksplisit dinyatakan final setidaknya di Jawa 8. Hanya perlu "efektif final" ( javarevisited.blogspot.com/2015/03/... )
Dandalf
4

Pertanyaan awal Anda menyebutkan "Timer Ayun". Jika sebenarnya pertanyaan Anda terkait dengan SWing, maka Anda harus menggunakan Timer Swing dan BUKAN util.Timer.

Baca bagian dari tutorial Swing tentang " Cara Menggunakan Pengatur Waktu " untuk informasi lebih lanjut.

camickr
sumber
4

Anda bisa menggunakan fungsi Thread.Sleep ()

Thread.sleep(4000);
myfunction();

Fungsi Anda akan dieksekusi setelah 4 detik. Namun ini dapat menghentikan sementara seluruh program ...

lembah
sumber
Dan itu hanya menjamin bahwa eksekusi akan berjalan setelah 4 detik, yang bisa berarti setelah 10 detik juga!
questzen
2
questzen, Anda akan menemukan bahwa semua metode di sini melakukan itu. Bahkan, bahkan jika Anda menjadwalkan sesuatu di tingkat OS, Anda biasanya hanya dapat menjamin waktu berlalu minimum sebelum suatu peristiwa.
Ethan
Ini bukan pertanyaan sebenarnya
Inder R Singh
Saya hanya harus memberikan ini downvote - sama sekali tidak jawaban untuk pertanyaan yang ada.
theMayer
OP mengatakan dalam komentar "Saya ingin terus melakukan sesuatu yang lain"; kode ini jelas, tidak.
Abhijit Sarkar
3

ScheduledThreadPoolExecutor memiliki kemampuan ini, tetapi cukup kelas berat.

Timer juga memiliki kemampuan ini tetapi membuka beberapa utas meskipun hanya digunakan sekali.

Berikut ini adalah implementasi sederhana dengan tes (tanda tangan dekat dengan Handler.postDelayed 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();
    }
}

Uji:

@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
sumber
itu memberi peringatan tidur disebut dalam satu lingkaran
shareef
The whilehanya untuk mengabaikan interupsi.
AlikElzin-kilaka
2

Semua unswers lain perlu menjalankan kode Anda di dalam utas baru. Dalam beberapa kasus penggunaan sederhana, Anda mungkin hanya ingin menunggu sedikit dan melanjutkan eksekusi dalam utas / aliran yang sama.

Kode di bawah ini menunjukkan teknik itu. Perlu diingat ini mirip dengan apa yang java.util.Timer lakukan di bawah tenda tetapi lebih ringan.

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

Implementasi 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
sumber
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
sumber
2
Sementara kode ini dapat menjawab pertanyaan, memberikan konteks tambahan tentang mengapa dan / atau bagaimana kode ini menjawab pertanyaan meningkatkan nilai jangka panjangnya.
Mateus