Bir iş parçacığı zaman aşımı nasıl yapılır


255

Sabit bir süre için bir iş parçacığı çalıştırmak istiyorum. Bu süre içinde tamamlanmazsa, onu öldürmek, bir istisna atmak veya bir şekilde idare etmek istiyorum. Nasıl yapılabilir?

Bu iş parçacığından anladım bunu yapmanın bir yolu iş parçacığının run () yöntemi içinde bir TimerTask kullanmaktır.

Bunun için daha iyi çözümler var mı?

 
DÜZENLEME: Daha net bir cevaba ihtiyaç duyduğum için bir ödül eklemek. Aşağıda verilen ExecutorService kodu sorunumu gidermiyor. Neden yürüttükten sonra uyku () (bazı kod - bu kod parçası üzerinde hiçbir kolu var)? Kod tamamlanırsa ve sleep () kesilirse, bu nasıl bir timeOut olabilir?

Yürütülmesi gereken görev benim kontrolümde değil. Herhangi bir kod parçası olabilir. Sorun, bu kod parçasının sonsuz bir döngüye girebilmesidir. Bunun olmasını istemiyorum. Bu görevi sadece ayrı bir iş parçacığında çalıştırmak istiyorum. Ana iş parçacığı, iş parçacığının bitmesini ve görevin durumunu bilmesini beklemek zorundadır (yani zaman aşımına uğramış veya bir istisna oluşmuşsa veya bir başarı olup olmadığı). Görev sonsuz bir döngüye girerse, ana iş parçam süresiz olarak beklemeye devam eder, bu ideal bir durum değildir.


EDIT: Ben daha net bir cevap gerekiyordu gibi bir lütuf eklemek. Aşağıda verilen ExecutorService kodu sorunumu gidermiyor. Kodumu çalıştırdıktan sonra neden uyku () yapmalıyım? Kod tamamlanırsa ve sleep () kesilirse, bu nasıl bir timeOut olabilir?
java_geek

7
Bu sleep()sadece "uzun süredir devam eden görevi" temsil eden bir saplama idi. Sadece gerçek görevinizle değiştirin;)
BalusC

1
... interrupt()iş parçacığındaki çağrılara yanıt veren bir "uzun süre çalışan görev" ... cevabımda işaret etmeye çalıştığım gibi, tüm "engelleme" çağrıları yapmaz. İptal etmeye çalıştığınız görevin ayrıntıları, kullanılması gereken yaklaşımda büyük bir fark yaratır. Görev hakkında daha fazla bilgi yardımcı olacaktır.
erickson

Bu cevaplar sorunu çözmüyorsa, daha fazla ayrıntı / kodun cevaplamaya yardımcı olacağını düşünüyorum.
Elister

Zaman sınırlaması yapmak istediğiniz bu iş parçacıkları; onlar engelleme çağrıları yapıyorlar, ya da bırakma zamanı olup olmadığını görmek için bazı değişkenleri kolayca kontrol edebileceğiniz bir döngü içinde mi?
Scott Smith

Yanıtlar:


376

Nitekim ziyade kullanmak ExecutorServiceyerine Timer, burada bir var SSCCE :

package com.stackoverflow.q2275443;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class Test {
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(new Task());

        try {
            System.out.println("Started..");
            System.out.println(future.get(3, TimeUnit.SECONDS));
            System.out.println("Finished!");
        } catch (TimeoutException e) {
            future.cancel(true);
            System.out.println("Terminated!");
        }

        executor.shutdownNow();
    }
}

class Task implements Callable<String> {
    @Override
    public String call() throws Exception {
        Thread.sleep(4000); // Just to demo a long running task of 4 seconds.
        return "Ready!";
    }
}

Yöntemdeki timeoutargümanla biraz oynayın Future#get(), örneğin 5'e yükseltin ve iş parçacığının bittiğini göreceksiniz. Bloktaki zaman aşımını kesebilirsiniz catch (TimeoutException e).

Güncelleme: kavramsal bir yanlış anlaşılmayı düzeltmek, sleep()bir değil gerekli. Sadece SSCCE / tanıtım amaçlı kullanılır. Sadece yapmak senin yerine orada uzun çalışan görev sleep(). Uzun süren görevinizin içinde, iş parçacığının aşağıdaki gibi kesintiye uğramadığını kontrol etmelisiniz :

while (!Thread.interrupted()) {
    // Do your long running task here.
}

24
Thread.sleep(4000)Uzun süren başka bir deyimle değiştirin ve örnek çalışmaz. Başka bir deyişle, bu örnek yalnızca durum değişikliğini Taskanlamak için tasarlanmışsa işe yarar Thread.isInterrupted().
yegor256

@BalusC Konularımı sonlandırmak için bu yaklaşımı denedim ama işe yaramadı. Buradan kontrol edebilirsiniz: stackoverflow.com/questions/35553420/…
syfantid

InterruptedException, future.cancel (true) tarafından nasıl ele alınır?
bolei

1
n kişi sayısı paket adı hakkında yorum yaptı ve işte bunun için başka bir +1. Bu emilmek için çok güzel bir yetenek. Teşekkürler!
Ashwin Tumma

@BalusC Geleceğin eşzamanlı olarak yürütülüp yürütülmeyeceğinden ve önceden tanımlanmış bir süreden daha uzun sürerse, feshedileceğinden şüphe duyuyorum. Aksi takdirde gelecekte biraz daha çalışacak bu arada zamana güveniyoruz ... Teşekkürler
Adeel Ahmad

49

Eski bir görev için bunu yapmanın% 100 güvenilir bir yolu yoktur. Görev bu yetenek göz önünde bulundurularak yazılmalıdır.

Çalışan iş parçacığında çağrılarla ExecutorServiceeşzamansız görevleri iptal etmek gibi temel Java kitaplıkları interrupt(). Bu nedenle, örneğin, görev bir tür döngü içeriyorsa , her yinelemede kesme durumunu kontrol etmelisiniz . Görev G / Ç işlemleri yapıyorsa, bunlar da kesilebilir olmalıdır ve bu ayarı yapmak zor olabilir. Her durumda, kodun kesintileri aktif olarak kontrol etmesi gerektiğini unutmayın; bir kesinti ayarlamak mutlaka bir şey yapmaz.

Tabii ki, göreviniz basit bir döngü ise, her yinelemede geçerli saati kontrol edebilir ve belirli bir zaman aşımı süresi dolduğunda vazgeçebilirsiniz. Bu durumda çalışan bir iş parçacığına gerek yoktur.


Deneyimlerime göre, kesintiye başlamak için tepki vermeyen tek kod yerel kodu (işletim sistemini beklemek) engellemektir.
Thorbjørn Ravn Andersen

@ ThorbjørnRavnAndersen Kabul ediyorum, ama bu çok fazla kod. Demek istediğim, bunun için genel amaçlı bir mekanizma yok; görevin kesinti politikasını anlamalısınız.
erickson

@erickson, katılıyorum. Bu noktaya kadar, her görev için tanımlanmış bir iptal politikası olmalı, eğer bu şekilde durdurmak istiyorsanız. Veya iş parçacığı kesildiğinde ne yapması gerektiğinin farkında olmalıdır. Sonuçta, herhangi bir iş parçacığının kesilmesi ve durdurulması, yalnızca hedef iş parçacığının kabul edebileceği veya reddedebileceği bir istektir, bu nedenle bunu akılda tutarak görev yazmak daha iyidir.
AKS

can execratorservice arama iş parçacığında görevi çalıştırmak için tercih? Ayrıca yöneticiler hizmet gelecekte bir zamanda yürütmek için tercih edebilir?
filthy_wizard

@ user1232726 execute()Üst arabirimin yöntemi, çağıran evrede Executorbir görev çalıştırabilir. Bu dönüş örneklerinin submit()yöntemleri için benzer bir ifade yoktur . Hizmetin anlamı, kapatma yoluyla temizlenmesi gereken çalışan iş parçacıkları olması ve görevlerin zaman uyumsuz olarak yürütülmesi. Bununla birlikte, sözleşmede , gönderen iş parçacığında görevleri yürütmesinin yasak olduğunu söyleyen hiçbir şey yoktur ; bu garantiler fabrikalar gibi uygulama API'larından gelir . ExecutorServiceFutureExecutorServiceExecutors
erickson

13

ExecutorService örneğini kullanmayı düşünün . Hem invokeAll()ve invokeAny()yöntemleri mevcuttur timeoutparametresi.

Görevler normal olarak tamamlandığı veya zaman aşımına ulaşıldığı için, geçerli iş parçacığı yöntem tamamlanana kadar (bunun istenip istenmediğinden emin değilim) engellenir. FutureNe olduğunu belirlemek için iade edilenleri kontrol edebilirsiniz .


9

İş parçacığı kodunun sizin kontrolünüz dışında olduğunu varsayarsak:

Yukarıda belirtilen Java belgelerinden :

Bir iş parçacığı Thread.interrupt'a yanıt vermezse ne olur?

Bazı durumlarda, uygulamaya özel hileler kullanabilirsiniz. Örneğin, bir iş parçacığı bilinen bir sokette bekliyorsa, iş parçacığının hemen dönmesini sağlamak için soketi kapatabilirsiniz. Ne yazık ki, genel olarak çalışan herhangi bir teknik yoktur. Bekleyen bir iş parçacığının Thread.interrupt'a yanıt vermediği tüm durumlarda, Thread.stop'a da yanıt vermediğine dikkat edilmelidir. Bu gibi durumlar, kasıtlı hizmet reddi saldırılarını ve thread.stop ve thread.interrupt öğelerinin düzgün çalışmadığı G / Ç işlemlerini içerir.

Sonuç olarak:

Tüm iş parçacıklarının yarıda kesilebildiğinden emin olun, aksi takdirde ayarlanacak bir bayrağa sahip olmak gibi iş parçacığı hakkında özel bilgiye ihtiyacınız vardır. Belki de görevin size durdurulması için gereken kodla birlikte verilmesini isteyebilirsiniz - bir stop()yöntemle bir arabirim tanımlayın . Ayrıca bir görevi durduramadığınızda da uyarı alabilirsiniz.


8

BalusC şunları söyledi:

Güncelleme: kavramsal bir yanlış anlaşılmayı açıklığa kavuşturmak için uyku () gerekmez. Sadece SSCCE / tanıtım amaçlı kullanılır. Sadece uzun süren görevinizi orada uyku yerine yapın ().

Ancak bununla değiştirirseniz Thread.sleep(4000);, for (int i = 0; i < 5E8; i++) {}derlenmez, çünkü boş döngü bir atmaz InterruptedException.

Ve ipliğin kesilebilir olması için bir atması gerekir InterruptedException.

Bu benim için ciddi bir sorun gibi görünüyor. Bu cevabı uzun süren genel bir görevle çalışmak için nasıl uyarlayacağımı göremiyorum.

Eklemek için düzenlendi: Bunu yeni bir soru olarak yeniden düşündüm: [ sabit bir süre sonra bir iş parçacığını kesintiye uğratmak, InterruptedException atmak zorunda mı? ]


Bunu yapma yolu, ortak Sınıf <T> çağrısı {} yöntemine bir ´throws İstisnası´ eklemektir
Roberto Linares

5

Bence uygun eşzamanlılık işleme mekanizmalarına bir göz atmalısınız (sonsuz döngülere giren iplikler kendiliğinden iyi gelmiyor, btw). Konuları "öldürme" veya "durdurma" konusunu biraz okuduğunuzdan emin olun .

Tanımladığınız şey, bir "buluşma" gibi çok ses çıkarır, bu nedenle CyclicBarrier'a bir göz atmak isteyebilirsiniz .

Sorununuzu çözebilecek başka yapılar da olabilir ( örneğin CountDownLatch kullanmak gibi ) (bir iş parçacığı için zaman aşımı ile bekleyen bir iş parçacığı, diğeri işini tamamladığında mandalı geriye doğru saymalıdır; zaman aşımı veya mandal geri sayımı çağrıldığında).

Bu alanda genellikle iki kitap öneririm: Java'da Eşzamanlı Programlama ve Pratikte Java Eşzamanlılığı .


5

Bir süre önce bunun için bir yardımcı sınıf oluşturdum. Harika çalışıyor:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
 * TimeOut class - used for stopping a thread that is taking too long
 * @author Peter Goransson
 *
 */
public class TimeOut {

    Thread interrupter;
    Thread target;
    long timeout;
    boolean success;
    boolean forceStop;

    CyclicBarrier barrier;

    /**
     * 
     * @param target The Runnable target to be executed
     * @param timeout The time in milliseconds before target will be interrupted or stopped
     * @param forceStop If true, will Thread.stop() this target instead of just interrupt() 
     */
    public TimeOut(Runnable target, long timeout, boolean forceStop) {      
        this.timeout = timeout;
        this.forceStop = forceStop;

        this.target = new Thread(target);       
        this.interrupter = new Thread(new Interrupter());

        barrier = new CyclicBarrier(2); // There will always be just 2 threads waiting on this barrier
    }

    public boolean execute() throws InterruptedException {  

        // Start target and interrupter
        target.start();
        interrupter.start();

        // Wait for target to finish or be interrupted by interrupter
        target.join();  

        interrupter.interrupt(); // stop the interrupter    
        try {
            barrier.await(); // Need to wait on this barrier to make sure status is set
        } catch (BrokenBarrierException e) {
            // Something horrible happened, assume we failed
            success = false;
        } 

        return success; // status is set in the Interrupter inner class
    }

    private class Interrupter implements Runnable {

        Interrupter() {}

        public void run() {
            try {
                Thread.sleep(timeout); // Wait for timeout period and then kill this target
                if (forceStop) {
                  target.stop(); // Need to use stop instead of interrupt since we're trying to kill this thread
                }
                else {
                    target.interrupt(); // Gracefully interrupt the waiting thread
                }
                System.out.println("done");             
                success = false;
            } catch (InterruptedException e) {
                success = true;
            }


            try {
                barrier.await(); // Need to wait on this barrier
            } catch (InterruptedException e) {
                // If the Child and Interrupter finish at the exact same millisecond we'll get here
                // In this weird case assume it failed
                success = false;                
            } 
            catch (BrokenBarrierException e) {
                // Something horrible happened, assume we failed
                success = false;
            }

        }

    }
}

Buna şöyle denir:

long timeout = 10000; // number of milliseconds before timeout
TimeOut t = new TimeOut(new PhotoProcessor(filePath, params), timeout, true);
try {                       
  boolean sucess = t.execute(); // Will return false if this times out
  if (!sucess) {
    // This thread timed out
  }
  else {
    // This thread ran completely and did not timeout
  }
} catch (InterruptedException e) {}  

3

Size sorunu çözmenin bir yolunu gösteren bir kod parçası gönderiyorum. Örnek olarak bir dosya okuyorum. Bu yöntemi başka bir işlem için kullanabilirsiniz, ancak ana işlemin kesilmesi için kill () yöntemini uygulamanız gerekir.

Umarım yardımcı olur


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

/**
 * Main class
 * 
 * @author el
 * 
 */
public class Main {
    /**
     * Thread which perform the task which should be timed out.
     * 
     * @author el
     * 
     */
    public static class MainThread extends Thread {
        /**
         * For example reading a file. File to read.
         */
        final private File fileToRead;
        /**
         * InputStream from the file.
         */
        final private InputStream myInputStream;
        /**
         * Thread for timeout.
         */
        final private TimeOutThread timeOutThread;

        /**
         * true if the thread has not ended.
         */
        boolean isRunning = true;

        /**
         * true if all tasks where done.
         */
        boolean everythingDone = false;

        /**
         * if every thing could not be done, an {@link Exception} may have
         * Happens.
         */
        Throwable endedWithException = null;

        /**
         * Constructor.
         * 
         * @param file
         * @throws FileNotFoundException
         */
        MainThread(File file) throws FileNotFoundException {
            setDaemon(false);
            fileToRead = file;
            // open the file stream.
            myInputStream = new FileInputStream(fileToRead);
            // Instantiate the timeout thread.
            timeOutThread = new TimeOutThread(10000, this);
        }

        /**
         * Used by the {@link TimeOutThread}.
         */
        public void kill() {
            if (isRunning) {
                isRunning = false;
                if (myInputStream != null) {
                    try {
                        // close the stream, it may be the problem.
                        myInputStream.close();
                    } catch (IOException e) {
                        // Not interesting
                        System.out.println(e.toString());
                    }
                }
                synchronized (this) {
                    notify();
                }
            }
        }

        /**
         * The task which should be timed out.
         */
        @Override
        public void run() {
            timeOutThread.start();
            int bytes = 0;
            try {
                // do something
                while (myInputStream.read() >= 0) {
                    // may block the thread.
                    myInputStream.read();
                    bytes++;
                    // simulate a slow stream.
                    synchronized (this) {
                        wait(10);
                    }
                }
                everythingDone = true;
            } catch (IOException e) {
                endedWithException = e;
            } catch (InterruptedException e) {
                endedWithException = e;
            } finally {
                timeOutThread.kill();
                System.out.println("-->read " + bytes + " bytes.");
                isRunning = false;
                synchronized (this) {
                    notifyAll();
                }
            }
        }
    }

    /**
     * Timeout Thread. Kill the main task if necessary.
     * 
     * @author el
     * 
     */
    public static class TimeOutThread extends Thread {
        final long timeout;
        final MainThread controlledObj;

        TimeOutThread(long timeout, MainThread controlledObj) {
            setDaemon(true);
            this.timeout = timeout;
            this.controlledObj = controlledObj;
        }

        boolean isRunning = true;

        /**
         * If we done need the {@link TimeOutThread} thread, we may kill it.
         */
        public void kill() {
            isRunning = false;
            synchronized (this) {
                notify();
            }
        }

        /**
         * 
         */
        @Override
        public void run() {
            long deltaT = 0l;
            try {
                long start = System.currentTimeMillis();
                while (isRunning && deltaT < timeout) {
                    synchronized (this) {
                        wait(Math.max(100, timeout - deltaT));
                    }
                    deltaT = System.currentTimeMillis() - start;
                }
            } catch (InterruptedException e) {
                // If the thread is interrupted,
                // you may not want to kill the main thread,
                // but probably yes.
            } finally {
                isRunning = false;
            }
            controlledObj.kill();
        }
    }

    /**
     * Start the main task and wait for the end.
     * 
     * @param args
     * @throws FileNotFoundException
     */
    public static void main(String[] args) throws FileNotFoundException {
        long start = System.currentTimeMillis();
        MainThread main = new MainThread(new File(args[0]));
        main.start();
        try {
            while (main.isRunning) {
                synchronized (main) {
                    main.wait(1000);
                }
            }
            long stop = System.currentTimeMillis();

            if (main.everythingDone)
                System.out.println("all done in " + (stop - start) + " ms.");
            else {
                System.out.println("could not do everything in "
                        + (stop - start) + " ms.");
                if (main.endedWithException != null)
                    main.endedWithException.printStackTrace();
            }
        } catch (InterruptedException e) {
            System.out.println("You've killed me!");
        }
    }
}

Saygılarımızla


3

İşte Java kod parçasını çalıştırmak veya çağırmak için yardımcı sınıfı kullanmak benim gerçekten basit :-)

Bu mükemmel dayanmaktadır cevap dan BalusC

package com.mycompany.util.concurrent;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * Calling {@link Callable#call()} or Running {@link Runnable#run()} code
 * with a timeout based on {@link Future#get(long, TimeUnit))}
 * @author pascaldalfarra
 *
 */
public class CallableHelper
{

    private CallableHelper()
    {
    }

    public static final void run(final Runnable runnable, int timeoutInSeconds)
    {
        run(runnable, null, timeoutInSeconds);
    }

    public static final void run(final Runnable runnable, Runnable timeoutCallback, int timeoutInSeconds)
    {
        call(new Callable<Void>()
        {
            @Override
            public Void call() throws Exception
            {
                runnable.run();
                return null;
            }
        }, timeoutCallback, timeoutInSeconds); 
    }

    public static final <T> T call(final Callable<T> callable, int timeoutInSeconds)
    {
        return call(callable, null, timeoutInSeconds); 
    }

    public static final <T> T call(final Callable<T> callable, Runnable timeoutCallback, int timeoutInSeconds)
    {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        try
        {
            Future<T> future = executor.submit(callable);
            T result = future.get(timeoutInSeconds, TimeUnit.SECONDS);
            System.out.println("CallableHelper - Finished!");
            return result;
        }
        catch (TimeoutException e)
        {
            System.out.println("CallableHelper - TimeoutException!");
            if(timeoutCallback != null)
            {
                timeoutCallback.run();
            }
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        catch (ExecutionException e)
        {
            e.printStackTrace();
        }
        finally
        {
            executor.shutdownNow();
            executor = null;
        }

        return null;
    }

}

2

Aşağıdaki snippet ayrı bir iş parçacığında bir işlem başlatır, ardından işlemin tamamlanması için 10 saniye kadar bekleyin. İşlem zamanında tamamlanmazsa, kod işlemi iptal etmeye çalışır, ardından neşeli yoluna devam eder. İşlem kolayca iptal edilemese bile, ana iş parçacığı alt iş parçacığının sonlanmasını beklemez.

ExecutorService executorService = getExecutorService();
Future<SomeClass> future = executorService.submit(new Callable<SomeClass>() {
    public SomeClass call() {
        // Perform long-running task, return result. The code should check
        // interrupt status regularly, to facilitate cancellation.
    }
});
try {
    // Real life code should define the timeout as a constant or
    // retrieve it from configuration
    SomeClass result = future.get(10, TimeUnit.SECONDS);
    // Do something with the result
} catch (TimeoutException e) {
    future.cancel(true);
    // Perform other error handling, e.g. logging, throwing an exception
}

getExecutorService()Yöntem bir dizi yolla uygulanabilir. Herhangi bir özel gereksiniminiz yoksa, Executors.newCachedThreadPool()iş parçacığı sayısı üzerinde üst sınır olmadan iş parçacığı havuzlamayı arayabilirsiniz .


Gerekli ithalat nedir? Nedir SomeClassve Future?
ADTC

2

Bahsetmediğim bir şey, iplik öldürmenin genellikle Kötü Bir Fikir olmasıdır. Dişli yöntemleri temiz bir şekilde düşürebilir hale getirmek için teknikler vardır , ancak bu sadece bir zaman aşımından sonra bir iş parçacığını öldürmekten farklıdır.

Önerdiğiniz şeyle ilgili risk, muhtemelen ipliği öldürdüğünüzde iş parçacığının hangi durumda olacağını bilmemenizdir - bu nedenle kararsızlığa neden olabilirsiniz. Daha iyi bir çözüm, iş parçacığı kodunuzun kendini asmamasını veya iptal talebine iyi yanıt vermesini sağlamaktır.


Bağlam olmadan sizinki gibi bir ifade çok kısıtlayıcı geliyor. Akademik ortamda çok sık zaman aşımına kadar bir şeyi test etme ihtiyacım var ve gerçekleştiğinde zaman aşımının gerçekleştiği tüm hesaplamayı bırakıp kaydediyorum. Muhtemelen sektörde nadirdir, ama yine de ...
Alessandro S.

@AlessandroS: Bu makul bir nokta, OP "daha iyi çözümler" istedi, ancak bununla birlikte kaba kuvvet yerine sağlamlık ve güvenilirliğin tercih edildiğini kastediyorum.
Dan Puzey

2

BalusC'den büyük cevap:

ancak sadece zaman aşımının kendisinin iş parçacığının kendisini kesmediğini eklemek için. görevinizde while (! Thread.interrupted ()) ile kontrol ediyor olsanız bile. iş parçacığının durdurulduğundan emin olmak istiyorsanız, zaman aşımı istisnası yakalandığında future.cancel () işlevinin çağrıldığından da emin olmalısınız.

package com.stackoverflow.q2275443; 

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;


public class Test { 
    public static void main(String[] args) throws Exception {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(new Task());

        try { 
            System.out.println("Started..");
            System.out.println(future.get(3, TimeUnit.SECONDS));
            System.out.println("Finished!");
        } catch (TimeoutException e) {
            //Without the below cancel the thread will continue to live 
            // even though the timeout exception thrown.
            future.cancel();
            System.out.println("Terminated!");
        } 

        executor.shutdownNow();
    } 
} 

class Task implements Callable<String> {
    @Override 
    public String call() throws Exception {
      while(!Thread.currentThread.isInterrupted()){
          System.out.println("Im still running baby!!");
      }          
    } 
} 

0

Cevabın esas olarak görevin kendisine bağlı olduğunu düşünüyorum.

  • Tek bir görevi tekrar tekrar mı yapıyor?
  • Zaman aşımı süresinin çalışmakta olan bir görevi sona erdikten hemen sonra kesmesi gerekli midir?

İlk cevap evet ve ikincisi hayır ise, bu kadar basit tutabilirsiniz:

public class Main {

    private static final class TimeoutTask extends Thread {
        private final long _timeoutMs;
        private Runnable _runnable;

        private TimeoutTask(long timeoutMs, Runnable runnable) {
            _timeoutMs = timeoutMs;
            _runnable = runnable;
        }

        @Override
        public void run() {
            long start = System.currentTimeMillis();
            while (System.currentTimeMillis() < (start + _timeoutMs)) {
                _runnable.run();
            }
            System.out.println("execution took " + (System.currentTimeMillis() - start) +" ms");
        }

    }

    public static void main(String[] args) throws Exception {
        new TimeoutTask(2000L, new Runnable() {

            @Override
            public void run() {
                System.out.println("doing something ...");
                try {
                    // pretend it's taking somewhat longer than it really does
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();
    }
}

Bu bir seçenek değilse, lütfen gereksinimlerinizi daraltın veya bir kod gösterin.


0

Ben onun tarafından yürütülen tüm zaman aşımına uğramış Runnables kesebilecek bir ExecutorService arıyordu, ama hiçbiri bulunamadı. Birkaç saat sonra aşağıdaki gibi bir tane oluşturdum. Bu sınıf sağlamlığı artırmak için değiştirilebilir.

public class TimedExecutorService extends ThreadPoolExecutor {
    long timeout;
    public TimedExecutorService(int numThreads, long timeout, TimeUnit unit) {
        super(numThreads, numThreads, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(numThreads + 1));
        this.timeout = unit.toMillis(timeout);
    }

    @Override
    protected void beforeExecute(Thread thread, Runnable runnable) {
        Thread interruptionThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // Wait until timeout and interrupt this thread
                    Thread.sleep(timeout);
                    System.out.println("The runnable times out.");
                    thread.interrupt();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        interruptionThread.start();
    }
}

Kullanımı:

public static void main(String[] args) {

    Runnable abcdRunnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("abcdRunnable started");
            try {
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                // logger.info("The runnable times out.");
            }
            System.out.println("abcdRunnable ended");
        }
    };

    Runnable xyzwRunnable = new Runnable() {
        @Override
        public void run() {
            System.out.println("xyzwRunnable started");
            try {
                Thread.sleep(20000);
            } catch (InterruptedException e) {
                // logger.info("The runnable times out.");
            }
            System.out.println("xyzwRunnable ended");
        }
    };

    int numThreads = 2, timeout = 5;
    ExecutorService timedExecutor = new TimedExecutorService(numThreads, timeout, TimeUnit.SECONDS);
    timedExecutor.execute(abcdRunnable);
    timedExecutor.execute(xyzwRunnable);
    timedExecutor.shutdown();
}

0

Şimdi böyle bir sorunla karşılaşıyorum. Resmin kodunu çözer. Kod çözme işlemi ekranın siyah kalması için çok fazla zaman alır. Bir zaman kontrolörü ekliyorum: zaman çok uzun olduğunda, geçerli Konudan açılır. Farkı aşağıdadır:

   ExecutorService executor = Executors.newSingleThreadExecutor();
   Future<Bitmap> future = executor.submit(new Callable<Bitmap>() {
       @Override
       public Bitmap call() throws Exception {
       Bitmap bitmap = decodeAndScaleBitmapFromStream(context, inputUri);// do some time consuming operation
       return null;
            }
       });
       try {
           Bitmap result = future.get(1, TimeUnit.SECONDS);
       } catch (TimeoutException e){
           future.cancel(true);
       }
       executor.shutdown();
       return (bitmap!= null);

0

Ben de aynı problemi yaşadım. Ben de böyle basit bir çözüm buldum.

public class TimeoutBlock {

 private final long timeoutMilliSeconds;
    private long timeoutInteval=100;

    public TimeoutBlock(long timeoutMilliSeconds){
        this.timeoutMilliSeconds=timeoutMilliSeconds;
    }

    public void addBlock(Runnable runnable) throws Throwable{
        long collectIntervals=0;
        Thread timeoutWorker=new Thread(runnable);
        timeoutWorker.start();
        do{ 
            if(collectIntervals>=this.timeoutMilliSeconds){
                timeoutWorker.stop();
                throw new Exception("<<<<<<<<<<****>>>>>>>>>>> Timeout Block Execution Time Exceeded In "+timeoutMilliSeconds+" Milli Seconds. Thread Block Terminated.");
            }
            collectIntervals+=timeoutInteval;           
            Thread.sleep(timeoutInteval);

        }while(timeoutWorker.isAlive());
        System.out.println("<<<<<<<<<<####>>>>>>>>>>> Timeout Block Executed Within "+collectIntervals+" Milli Seconds.");
    }

    /**
     * @return the timeoutInteval
     */
    public long getTimeoutInteval() {
        return timeoutInteval;
    }

    /**
     * @param timeoutInteval the timeoutInteval to set
     */
    public void setTimeoutInteval(long timeoutInteval) {
        this.timeoutInteval = timeoutInteval;
    }
}

Blok zaman sınırı dahilinde yürütülmezse garanti eder. süreç sona erecek ve bir istisna atacaktır.

misal :

try {
        TimeoutBlock timeoutBlock = new TimeoutBlock(10 * 60 * 1000);//set timeout in milliseconds
        Runnable block=new Runnable() {

            @Override
            public void run() {
                //TO DO write block of code 
            }
        };

        timeoutBlock.addBlock(block);// execute the runnable block 

    } catch (Throwable e) {
        //catch the exception here . Which is block didn't execute within the time limit
    }

0

BalusC tarafından verilen çözümde , ana iplik zaman aşımı süresi boyunca bloke kalacaktır. Birden fazla iş parçacığı olan bir iş parçacığı havuzunuz varsa, zaman aşımı süresini aşarsa iş parçacığını beklemek ve kapatmak için Future.get (uzun zaman aşımı, TimeUnit birimi) engelleme çağrısını kullanacak aynı sayıda ek iş parçacığına ihtiyacınız olacaktır .

Bu soruna genel bir çözüm, zaman aşımı işlevselliğini ekleyebilecek bir ThreadPoolExecutor Decorator oluşturmaktır. Bu Decorator sınıfı, ThreadPoolExecutor öğesinin sahip olduğu kadar çok iş parçacığı oluşturmalı ve tüm bu iş parçacıkları yalnızca ThreadPoolExecutor'unu beklemek ve kapatmak için kullanılmalıdır.

Genel sınıf aşağıdaki gibi uygulanmalıdır:

import java.util.List;
import java.util.concurrent.*;

public class TimeoutThreadPoolDecorator extends ThreadPoolExecutor {


    private final ThreadPoolExecutor commandThreadpool;
    private final long timeout;
    private final TimeUnit unit;

    public TimeoutThreadPoolDecorator(ThreadPoolExecutor threadpool,
                                      long timeout,
                                      TimeUnit unit ){
        super(  threadpool.getCorePoolSize(),
                threadpool.getMaximumPoolSize(),
                threadpool.getKeepAliveTime(TimeUnit.MILLISECONDS),
                TimeUnit.MILLISECONDS,
                threadpool.getQueue());

        this.commandThreadpool = threadpool;
        this.timeout=timeout;
        this.unit=unit;
    }

    @Override
    public void execute(Runnable command) {
        super.execute(() -> {
            Future<?> future = commandThreadpool.submit(command);
            try {
                future.get(timeout, unit);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } catch (ExecutionException | TimeoutException e) {
                throw new RejectedExecutionException(e);
            } finally {
                future.cancel(true);
            }
        });
    }

    @Override
    public void setCorePoolSize(int corePoolSize) {
        super.setCorePoolSize(corePoolSize);
        commandThreadpool.setCorePoolSize(corePoolSize);
    }

    @Override
    public void setThreadFactory(ThreadFactory threadFactory) {
        super.setThreadFactory(threadFactory);
        commandThreadpool.setThreadFactory(threadFactory);
    }

    @Override
    public void setMaximumPoolSize(int maximumPoolSize) {
        super.setMaximumPoolSize(maximumPoolSize);
        commandThreadpool.setMaximumPoolSize(maximumPoolSize);
    }

    @Override
    public void setKeepAliveTime(long time, TimeUnit unit) {
        super.setKeepAliveTime(time, unit);
        commandThreadpool.setKeepAliveTime(time, unit);
    }

    @Override
    public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
        super.setRejectedExecutionHandler(handler);
        commandThreadpool.setRejectedExecutionHandler(handler);
    }

    @Override
    public List<Runnable> shutdownNow() {
        List<Runnable> taskList = super.shutdownNow();
        taskList.addAll(commandThreadpool.shutdownNow());
        return taskList;
    }

    @Override
    public void shutdown() {
        super.shutdown();
        commandThreadpool.shutdown();
    }
}

Yukarıdaki dekoratör aşağıdaki gibi kullanılabilir:

import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Main {

    public static void main(String[] args){

        long timeout = 2000;

        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3, 10, 0, TimeUnit.MILLISECONDS, new SynchronousQueue<>(true));

        threadPool = new TimeoutThreadPoolDecorator( threadPool ,
                timeout,
                TimeUnit.MILLISECONDS);


        threadPool.execute(command(1000));
        threadPool.execute(command(1500));
        threadPool.execute(command(2100));
        threadPool.execute(command(2001));

        while(threadPool.getActiveCount()>0);
        threadPool.shutdown();


    }

    private static Runnable command(int i) {

        return () -> {
            System.out.println("Running Thread:"+Thread.currentThread().getName());
            System.out.println("Starting command with sleep:"+i);
            try {
                Thread.sleep(i);
            } catch (InterruptedException e) {
                System.out.println("Thread "+Thread.currentThread().getName()+" with sleep of "+i+" is Interrupted!!!");
                return;
            }
            System.out.println("Completing Thread "+Thread.currentThread().getName()+" after sleep of "+i);
        };

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