2012-08-14 13 views
9

Bazen tekrarlanan görevin süresi, süresinden daha uzundur (Benim durumumda, bu, saatlerce olabilir) . Çalıştırmak için 7 dakika süren ve her 10 dakikada bir çalışacak şekilde planlanan tekrarlanan bir görev düşünün, ancak her koşuda birkaç saat için bazen 15 dakika sürün.Java'da tek bir iş parçacığının yinelenen yinelenen zamanlamasını programlayın, ancak önceki çalışma bitmemişse, geçerli koşuyu atlayın

Zamanlayıcı ve ScheduledThreadPoolExecutor sınıflarının her ikisi de genellikle bu tür işlevler için kullanılan bir ScheduleAtFixedRate yöntemine sahiptir. Ancak, her ikisi de 'geride kaldıklarında onları yakalamaya çalıştıkları' karakteristiğine sahiptir. Başka bir deyişle, bir Zamanlayıcı birkaç infaz tarafından geride kalırsa, görevlerin hiçbiri daha uzun sürmüyorsa gerçekleşecek olan çalışma sayısına geri dönene kadar sürekli çalışacak bir kuyruk kuyruğu oluşturur. belirtilen süre. Bir önceki çalışma tamamlanmadığında mevcut yürütmeyi atlayarak bu davranıştan kaçınmak istiyorum.

Havuzlanmış bir yürütücünün AfterExecution yöntemiyle uğraşmak, bir gecikmeyi yeniden hesaplamak ve yeni gecikme ile yeniden çalıştırmayı yeniden zamanlamayı içeren bir çözümüm var, ancak daha basit bir yöntem olup olmadığını veya bu işlev zaten varsa bir yerlerde ortak bir kütüphane. Sabit bir süre yerine sabit bir gecikmeyle zamanlamayı bildiğimi biliyorum, ancak bu, işleri sabit zamanlarında yürütmeyi denemenin önemli olduğu için benim için işe yaramayacaktır. AfterExecution çözümümden daha basit seçenekler var mı?

+3

Çalışmakta olan başka bir örnek olup olmadığını kontrol etmenin en kolay yolu, ve eğer öyleyse, hemen kendini çekmektir. –

+0

@Hot Licks: ScheduledExecutorService aslında onları paralel olarak çalıştırmaz. –

+0

Peki burada anahtar gereksinim nedir? Bu sadece ve her zaman bir ** 10 dakika arayla, bir cevapsız olup olmadığına bakılmaksızın başlar? Eğer öyleyse, bir oran hakkında konuşmuyorsunuz. –

cevap

13

Bence istediğin şey, uzun süren görev için ScheduledExecutorService'nin kendisinde değil, arka plan iş parçacığının içinde koşmaktır. Daha sonra sabit oranlı görev her zaman hızlı bir şekilde tamamlanacaktır, çünkü sadece asıl görevi arka planda başlatıp başlamayacağınızı kontrol etmek için kullanılır (ya da hala son kez çalışıyorsa).

ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); 
final Runnable actualTask = null; 

executorService.scheduleAtFixedRate(new Runnable() { 
    private final ExecutorService executor = Executors.newSingleThreadExecutor(); 
    private Future<?> lastExecution; 
    @Override 
    public void run() { 
     if (lastExecution != null && !lastExecution.isDone()) { 
      return; 
     } 
     lastExecution = executor.submit(actualTask); 
    } 
}, 10, 10, TimeUnit.MINUTES); 
+0

Bu seçenekten bahsetmiştim. – jonderry

+0

@jonderry: Üzgünüz, son cümlenizi kaçırdınız. Başka bir fikrim var, eminim ki daha temiz olacaklar. –

+0

@jonderry: Tamam, gönderdiğim son öneri iyi bir fikir. Cevabımı temizledim, diğer önerilerin düzenleme geçmişini görebilirsiniz. –

1

Üçüncü bir sınıf oluşturun, Koordinator denir. Koordinatör, isRunning değerini true olarak ayarlayan ve başka bir iş parçacığı zaten çalışmıyorsa, true olarak döndürülen bir senkronize startRunning() yöntemine sahiptir. Ayrıca, isRunning öğesini false olarak ayarlayan senkronize bir stopRunning yöntemi de olmalıdır. Bir runnable zaten çalışıyorsa, true değerini döndürür. Bu sınıfın tek bir örneğini yaparsınız ve oluşturduğunuz tüm çalışma değişkenlerine bir başvuru iletirsiniz. Runnable'ın çalıştırma yönteminde ilk önce startRunning öğesini çağırırsınız ve başka birinin daha önce çalışmadığını doğrulamak için dönüşü kontrol edin. Sonunda denemede kodu() çalıştırdığınızdan emin olun ve sonuncu bloğun içinden stopRunning komutunu arayın.