scheduleAtFixedRate vs scheduleWithFixedDelay

117

Apa perbedaan utama antara scheduleAtFixedRatedan scheduleWithFixedDelaymetode ScheduledExecutorService ?

scheduler.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
        System.out.println("scheduleAtFixedRate:    " + new Date());
    }
}, 1, 3L , SECONDS);

scheduler.scheduleWithFixedDelay(new Runnable() {
    @Override
    public void run() {
        System.out.println("scheduleWithFixedDelay: " + new Date());
    }
}, 1, 3L , SECONDS);

mereka mencetak tepat pada waktu yang sama, tampaknya dijalankan pada interval yang sama persis.

Penggergaji
sumber

Jawaban:

206

Coba tambahkan Thread.sleep(1000);panggilan dalam run()metode Anda ... Pada dasarnya ini adalah perbedaan antara menjadwalkan sesuatu berdasarkan kapan eksekusi sebelumnya berakhir dan kapan itu (secara logis) dimulai .

Misalnya, saya menjadwalkan alarm untuk berbunyi dengan tarif tetap sekali dalam satu jam, dan setiap kali alarm berbunyi, saya minum secangkir kopi, yang memakan waktu 10 menit. Misalkan dimulai pada tengah malam, saya akan memiliki:

00:00: Start making coffee
00:10: Finish making coffee
01:00: Start making coffee
01:10: Finish making coffee
02:00: Start making coffee
02:10: Finish making coffee

Jika saya menjadwalkan dengan penundaan tetap selama satu jam, saya memiliki:

00:00: Start making coffee
00:10: Finish making coffee
01:10: Start making coffee
01:20: Finish making coffee
02:20: Start making coffee
02:30: Finish making coffee

Yang mana yang Anda inginkan tergantung pada tugas Anda.

Jon Skeet
sumber
18
Apa yang terjadi dalam skenario fixedRate jika perlu lebih dari satu jam untuk membuat kopi?
Brett VanderVeen
5
@BrettVanderVeen: Saya yakin itu tergantung pada pelaksana yang bersangkutan. Ini akan dijadwalkan tepat waktu - tetapi apakah itu dijalankan tergantung pada apakah utas tersedia atau tidak untuk pelaksana itu. Saya sarankan Anda bereksperimen untuk melihat bagaimana ini bekerja dalam berbagai skenario.
Jon Skeet
8
@BrettVanderVeen Dari dokumentasi , "Jika eksekusi apa pun dari tugas ini membutuhkan waktu lebih lama dari periodenya, maka eksekusi selanjutnya dapat dimulai terlambat, tetapi tidak akan dijalankan secara bersamaan." Dengan kata lain, implementasi yang sesuai tidak akan memungkinkan implementasi berikutnya hingga implementasi sebelumnya selesai.
M. Justin
Bisakah Anda memberikan kode yang berfungsi untuk output yang ditampilkan (kopi) untuk pemula seperti saya?
MuneshSingh
@MuneshSingh: Tidak dalam pertanyaan ini, yang menanyakan untuk menjelaskan apa perbedaan antara penjadwalan pada tarif tetap dan penjadwalan pada penundaan tetap. Anda tidak akan mengimplementasikannya sendiri - Anda akan menggunakan eksekutor bawaan.
Jon Skeet
57

Visualisasikan deret waktu scheduleAtFixedRatemetode pemanggilan . Eksekusi berikutnya akan segera dimulai jika yang terakhir membutuhkan waktu lebih lama dari periode. Jika tidak, itu akan dimulai setelah waktu periode.

rangkaian waktu metode scheduleAtFixedRate permintaan

Rangkaian waktu scheduleWithFixedDelaymetode pemanggilan . Eksekusi berikutnya akan dimulai setelah waktu tunda antara penghentian satu eksekusi dan dimulainya eksekusi berikutnya, terlepas dari waktu eksekusinya

rangkaian waktu metode scheduleWithFixedDelay permintaan

Semoga dapat membantu Anda

Ken Block
sumber
Saya tidak dapat memahami kata "ekstra" yang disebutkan dalam diagram deret waktu scheduleAtFixedRate.
MuneshSingh
1
@MuneshSingh Ini dimaksudkan untuk menunjukkan bahwa waktu eksekusi tugas lebih lama dari yang dijadwalkan, sehingga membutuhkan waktu "ekstra" dan eksekusi berikutnya segera dimulai.
Viorel
@Viorel terima kasih telah mengklarifikasi. Apakah itu berarti "periode" bukanlah penundaan waktu yang tepat antara dua eksekusi yang berurutan.
MuneshSingh
1
@MuneshSingh Periode telah ditetapkan, tetapi tidak akan menghentikan tugas saat ini setelah melewatinya, tidak akan ada penundaan antara proses ini dan berikutnya. Jika Anda ingin membuat "batas waktu", Anda mungkin ingin mempertahankan Future dan membatalkannya di eksekutor yang berbeda. Dengan kata sederhana, ia mengatakan mulai eksekusi pertama dan eksekusi berikutnya sesegera mungkin setelah "periode" berlalu .
Viorel
4

The scheduleAtFixedRate()Metode menciptakan tugas baru dan menyerahkan ke eksekutor setiap periode, terlepas dari apakah atau tidak tugas sebelumnya selesai .

Di sisi lain, scheduleWithFixedDelay()metode ini membuat tugas baru setelah tugas sebelumnya selesai .

Imar
sumber
Anda menulis dua kali scheduleAtFixedRate:)
Vlad
3

Jika Anda membaca Java Doc itu akan lebih jelas

ScheduledFuture scheduleAtFixedRate (Perintah Runnable, long initialDelay, periode panjang, unit TimeUnit) Membuat dan menjalankan tindakan periodik yang diaktifkan pertama setelah penundaan awal yang diberikan, dan selanjutnya dengan periode yang diberikan; Artinya, eksekusi akan dimulai setelah initialDelay lalu initialDelay + period, lalu initialDelay + 2 * periode, dan seterusnya.

ScheduledFuture scheduleWithFixedDelay (perintah Runnable, long initialDelay, long delay, unit TimeUnit) Membuat dan menjalankan tindakan periodik yang diaktifkan pertama setelah penundaan awal yang diberikan, dan kemudian dengan penundaan yang diberikan antara penghentian satu eksekusi dan dimulainya eksekusi berikutnya.

shazin
sumber
1

Ada satu batasan dalam scheduleAtFixedRate jika thread pertama memakan waktu terlalu lama dan tidak berakhir dalam durasi yang ditentukan, maka thread konsutif kedua tidak akan dimulai setelah tugas pertama selesai dan tidak akan segera dimulai saat thread pertama menyelesaikan tugas dan durasi yang diberikan telah berlalu. JVM akan memutuskan kapan tugas berikutnya akan dijalankan.

Saya pikir itu akan membantu Anda memilih metode karena saya mendapat masalah besar

pengguna1047873
sumber
1
Apa? JVM akan memutuskan? Apa maksudnya itu? Memang benar bahwa runnable tidak akan dieksekusi secara bersamaan dengan dirinya sendiri sesuai dokumen, tetapi diputuskan oleh pelaksana, yang mungkin khusus ATAU standar ScheduledThreadPoolExecutor(dan yang terakhir memiliki perilaku yang terdefinisi dengan baik)
Biasa
Tidak, saya telah menemukan masalah serupa di aplikasi saya di mana saya telah memberikan interval 15 menit dan tugas pertama tidak selesai dalam 15 menit dan memakan waktu 15.30 detik sehingga tugas kedua tidak segera dimulai beberapa kali mulai setelah 5 menit dan beberapa waktu setelahnya 8 menit dan saya tidak menyadari apakah kita dapat mengontrol perilaku ini karena ini bukan perilaku standar.
pengguna1047873
Kedengarannya seperti antrian tugas buku teks.
Biasa
Ya, itu hanya berarti bahwa semua utas di pelaksana Anda sudah sibuk melakukan sesuatu, dan tugas Anda dimasukkan ke dalam antrean untuk dilakukan. ( CATATAN Anda perlu mengkonfirmasi ini dengan melihat antrian tersebut atau melihat apa yang dilakukan thread pelaksana). Bagaimana Anda mengontrol ini tergantung pada jenis pelaksana yang Anda miliki. Anda mungkin ingin membuat eksekutor 1-utas terpisah untuk tugas khusus ini saja, maka itu tidak akan menunggu apa pun. Atau berikan lebih banyak utas kepada eksekutor Anda saat ini. Atau ubah strateginya.
Biasa
0

Mari menulis program sederhana:

import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit

var time = 0L
var start = System.currentTimeMillis()
val executor = Executors.newScheduledThreadPool(1)
executor.scheduleWithFixedDelay({
    if (time >= 12_000L) {
        executor.shutdown()
    } else {
        Thread.sleep(2000L)
        val now = System.currentTimeMillis()
        time += now - start
        System.out.println("Total $time delay ${now - start}\n")
        start = now
    }
}, 0L, 1000L, TimeUnit.MILLISECONDS)

Dan lihat hasilnya:

| scheduleWithFixedDelay |   scheduleAtFixedRate  |
|:----------------------:|:----------------------:|
| Total 2001 delay 2001  | Total 2003 delay 2003  |
| Total 5002 delay 3001  | Total 4004 delay 2001  |
| Total 8003 delay 3001  | Total 6004 delay 2000  |
| Total 11003 delay 3000 | Total 8004 delay 2000  |
| Total 14003 delay 3000 | Total 10005 delay 2001 |
|          ---           | Total 12005 delay 2000 |

PERHATIKAN waktu eksekusi lebih lama dari menunggu

scheduleWithFixedDelay menjaga delay
scheduleAtFixedRate menghapus penundaan

Vlad
sumber
-1
scheduledExecutorService.scheduleAtFixedRate(() -> {
        System.out.println("runnable start"); try { Thread.sleep(5000);  System.out.println("runnable end");} catch
     (InterruptedException e) { // TODO Auto-generated catch block
      e.printStackTrace(); }}, 2, 7, TimeUnit.SECONDS);



     scheduledExecutorService.scheduleWithFixedDelay(() -> {
     System.out.println("runnable start"); try { Thread.sleep(5000); System.out.println("runnable end");} catch
     (InterruptedException e) { // TODO Auto-generated catch block
     e.printStackTrace(); } }, 2, 7, TimeUnit.SECONDS);

Jalankan saja, dan Anda akan tahu perbedaannya. Terima kasih

teknologi logi
sumber
1
Tolong jelaskan juga bagaimana kode tersebut memecahkan masalah OP. :)
Yash