SchedAtFixedRate vs schedWithFixedDelay


118

Arasındaki temel fark nedir scheduleAtFixedRateve scheduleWithFixedDelayyöntemleri 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);

tam olarak aynı anda yazdırıyorlar, tam olarak aynı aralıkta yürütülüyor gibi görünüyorlar.

Yanıtlar:


207

Yönteminize bir Thread.sleep(1000);çağrı eklemeyi deneyin run()... Temel olarak, bir şeyi zamanlama arasındaki fark, önceki yürütmenin ne zaman bitip ne zaman (mantıksal olarak) başladığına bağlı olarak belirlenir .

Örneğin, saatte bir sabit hızla çalacak bir alarm programladığımı ve her çaldığında 10 dakika süren bir fincan kahvem olduğunu varsayalım . Bunun gece yarısı başladığını varsayalım, ben:

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

Bir saatlik sabit bir gecikmeyle planlama yaparsam:

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

Hangisini istediğiniz, görevinize bağlıdır.


18
Sabit Oran senaryosunda kahve yapmak bir saatten fazla sürerse ne olur?
Brett VanderVeen

5
@BrettVanderVeen: Bunun söz konusu uygulayıcıya bağlı olduğuna inanıyorum. Bu edilecek planlanan zamanında - ama bu olmadığını yürüten bir iş parçacığı bu uygulamakla kullanılabilir olup olmamasına bağlıdır. Bunun çeşitli senaryolarda nasıl çalıştığını görmenizi öneririm.
Jon Skeet

8
@BrettVanderVeen Dokümantasyondan , "Bu görevin herhangi bir şekilde yürütülmesi süresinden daha uzun sürerse, sonraki yürütmeler geç başlayabilir, ancak eşzamanlı olarak çalışmayacaktır." Diğer bir deyişle, uyumlu bir uygulama, bir önceki uygulama bitene kadar bir sonrakinin yürütülmesine izin vermeyecektir.
M. Justin

Benim gibi bir acemi için gösterilen çıktı (kahve) için bir çalışma kodu sağlayabilir misiniz?
MuneshSingh

@MuneshSingh: Sabit bir hızda planlama ile sabit bir gecikmeyle programlama arasındaki farkın ne olduğunu açıklamayı isteyen bu soruda değil. Yine de bunu kendiniz uygulamazsınız - yerleşik yürütücüleri kullanırsınız.
Jon Skeet

57

Çağırma scheduleAtFixedRateyönteminin zaman serilerini görselleştirin . Sonuncusu süreden uzun sürerse sonraki infazlar hemen başlayacaktır. Aksi takdirde, dönem süresinden sonra başlayacaktır.

çağırma çizelgesi zaman serisiAtFixedRate yöntemi

Çağırma scheduleWithFixedDelayyönteminin zaman serisi . Bir sonraki yürütme, yürütme zamanına bakılmaksızın, bir yürütmenin sonlandırılması ile bir sonrakinin başlaması arasındaki gecikme süresinden sonra başlayacaktır.

çağırma çizelgesi zaman serisiWithFixedDelay yöntemi

Umut sana yardımcı olabilir


SchedAtFixedRate zaman serisi diyagramında belirtilen "ekstra" kelimesini anlayamadım.
MuneshSingh

1
@MuneshSingh Görevin yürütme süresinin planlanandan daha uzun olduğunu, bu nedenle "fazladan" zaman aldığını ve bir sonraki yürütmenin hemen başladığını göstermek içindir.
Viorel

@Viorel, açıkladığınız için teşekkürler. Bu, "süre" nin iki ardışık yürütme arasında tam olarak sabit bir zaman gecikmesi olmadığı anlamına mı geliyor?
MuneshSingh

1
@MuneshSingh Periyot sabittir, ancak mevcut görevi bir kez geçtikten sonra durdurmaz, bu çalıştırma ile bir sonraki arasında gecikme olmaz. Bir "zaman aşımı" oluşturmak istiyorsanız, Geleceği saklamak ve farklı bir yürütücüde iptal etmek isteyebilirsiniz. Basit bir deyişle, ilk yürütmeyi başlat ve bir sonraki "dönem" süresi geçtikten sonra mümkün olan en kısa sürede başlar diyor .
Viorel

4

scheduleAtFixedRate()Yöntem, uygulamakla için her dönem yeni bir görev ve başvurularını bunu oluşturur bakılmaksızın önceki görev bitmiş olsun veya olmasın ait .

Öte yandan, scheduleWithFixedDelay()yöntem önceki görev bittikten sonra yeni bir görev oluşturur .


İki kez yazdın scheduleAtFixedRate:)
Vlad

3

Java Dokümanını okursanız daha net olacaktır

ScheduledFuture schedAtFixedRate (Runnable komutu, uzun ilkGecikme, uzun dönem, Zaman Birimi birimi) Verilen ilk gecikmeden sonra ve daha sonra verilen süre ile birlikte etkinleştirilen periyodik bir eylem oluşturur ve yürütür; yani çalıştırmalar ilk Gecikmeden sonra ilk Gecikme + döneminden, sonra ilk Gecikme + 2 * döneminden sonra başlayacaktır.

ScheduledFuture schedWithFixedDelay (Runnable komutu, uzun ilkGecikme, uzun gecikme, Zaman Birimi birimi) Verilen ilk gecikmeden sonra ve ardından bir yürütmenin sona ermesi ile bir sonrakinin başlaması arasında verilen gecikme ile ilk olarak etkinleştirilen periyodik bir eylem oluşturur ve yürütür.


1

İlk iş parçacığı çok uzun sürüyorsa ve verilen süre içinde sona ermediyse, çizelgeAtFixedRate'de bir yakalama var, daha sonra ikinci bağlantılı iş parçacığı, ilk görev tamamlandıktan sonra başlamayacak ve ilk iş parçacığı görevlerini tamamlayıp süreyi tamamladığında hemen başlamayacaktır. geçti. JVM Bir sonraki görevin ne zaman yürütüleceğine karar verecektir.

Bunun yöntem seçmenize yardımcı olacağını düşünüyorum çünkü bundan dolayı büyük bir problemim var


1
Ne? JVM karar verecek mi? Bu ne anlama geliyor? Çalıştırılabilir belgelerin kendisiyle eşzamanlı olarak çalıştırılmayacağı doğrudur, ancak yürütücü tarafından kararlaştırılır, bu özel VEYA standart olabilir ScheduledThreadPoolExecutor(ve ikincisi iyi tanımlanmış bir davranışa sahiptir)
Ordous

Hayır, uygulamamda 15 dakika aralık verdiğim ve ilk görev 15 dakika içinde bitmiyor ve 15.30 saniye sürüyor, bu nedenle ikinci görev hemen başlamadı, 5 dakika sonra ve bir süre sonra başlamadı 8 dakika ve bu davranışı kontrol edip edemeyeceğimizin farkında değilim çünkü bu standart bir davranış değil.
user1047873

Bu, ders kitabı görev kuyruğuna benziyor.
Ordous

Evet, bu sadece uygulayıcınızdaki tüm iş parçacıklarının zaten bir şeyler yapmakla meşgul olduğu ve görevinizin yapılacak işler sırasına konulduğu anlamına gelir. ( NOT Bunu söz konusu kuyruğa bakarak veya yürütücü iş parçacıklarının ne yaptığına bakarak onaylamanız gerekir). Bunu nasıl kontrol edeceğiniz, ne tür bir uygulayıcıya sahip olduğunuza bağlıdır. Yalnızca bu belirli görev için ayrı bir 1-iş parçacığı yürütücü yapmak isteyebilirsiniz, o zaman hiçbir şey beklemeyecektir. Veya mevcut uygulayıcınıza daha fazla iş parçacığı verin. Veya stratejisini değiştirin.
Ordous

0

Basit bir program yazalım:

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)

Ve sonuçları görün:

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

DİKKAT yürütme süresi beklemekten daha uzun

scheduleWithFixedDelay gecikme tutar
scheduleAtFixedRate kaldırır gecikme


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

Sadece uygula ve farkı anlayacaksın. teşekkür ederim


1
Lütfen kodun OP'nin problemini nasıl çözdüğünü de açıklayın. :)
Yash
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.