5 Stimmen

Wie erreicht man den FutureTask-Ausführungsstatus?

Ich habe einen singleThreadExecutor, um die Aufgaben, die ich ihm übergebe, in serieller Reihenfolge auszuführen, d. h. eine Aufgabe nach der anderen, keine parallele Ausführung.

Ich habe eine Runnable, die in etwa wie folgt funktioniert

MyRunnable implements Runnable {

@Override
public void run() {
    try {
        Thread.sleep(30000);
    } catch (InterruptedException e1) {
        e1.printStackTrace();
    }

}

Wenn ich z. B. drei Instanzen von MyRunnable an den oben erwähnten Single-Thread-Executor übergebe, würde ich erwarten, dass die erste Aufgabe ausgeführt wird und aufgrund von Thread.sleep ihren ausführenden Thread in TIMED_WAITING hat (ich kann mich über den spezifischen Zustand irren). Den anderen beiden Aufgaben sollten keine Threads zugewiesen werden, die sie ausführen, zumindest nicht, bis die erste Aufgabe beendet ist.

So meine Frage ist, wie man diesen Zustand über die FutureTask-API oder irgendwie an den Thread zu erhalten, die die Aufgabe ausführt (wenn es keinen solchen Thread dann die Aufgabe wartet ausgeführt werden oder anhängig ist) und erhalten seinen Zustand oder vielleicht durch einige andere Mittel?

FutureTask definiert nur die Methoden isCancled() und isDone(), die aber nicht ausreichen, um alle möglichen Ausführungszustände des Tasks zu beschreiben.

3voto

Mark Peters Punkte 78448

Sie können alles, was Sie an diesen Dienst übermitteln, in eine Runnable die aufzeichnet, wenn ihre Ausführungsmethode eingegeben wird.

public class RecordingRunnable implements Runnable {
    private final Runnable actualTask;
    private volatile boolean isRunning = false;
    //constructor, etc

    public void run() {
        isRunning = true;
        actualTask.run();
        isRunning = false;
    }

    public boolean isRunning() {
       return isRunning;
    }
}

2voto

Greg Mattes Punkte 31690

Sie könnten eine getThread() Methode zu MyRunnable die die Thread Ausführen der run() Methode.

Ich würde vorschlagen, eine Instanzvariable wie diese hinzuzufügen (muss sein flüchtig um die Korrektheit zu gewährleisten):

 private volatile Thread myThread;

Tun Sie dies, bevor die try Block:

myThread = Thread.currentThread();

Und fügen Sie eine finally damit blockieren:

myThread = null;

Dann könnten Sie anrufen:

final Thread theThread = myRunnable.getThread();
if (theThread != null) {
    System.out.println(theThread.getState());
}

für einige MyRunnable .

null ist an dieser Stelle ein zweideutiges Ergebnis, das entweder "nicht ausgeführt" oder "abgeschlossen" bedeutet. Fügen Sie einfach eine Methode hinzu, die angibt, ob der Vorgang abgeschlossen ist:

public boolean isDone() {
    return done;
}

Natürlich brauchen Sie eine Instanzvariable, um diesen Zustand aufzuzeichnen:

private volatile boolean done;

Und setzen Sie es auf true in der finally Block (wahrscheinlich bevor der Thread auf null gibt es ein bisschen von einem Rennen Bedingung dort, weil es zwei Werte, die den Zustand von einer Sache zu erfassen sind. Insbesondere könnten Sie mit diesem Ansatz Folgendes beobachten isDone() == true y getThread() != null . Sie könnten dies abmildern, indem Sie eine lock Objekt für Zustandsübergänge und synchronisieren darauf, wenn eine oder beide Zustandsvariablen geändert werden):

done = true;

Beachten Sie, dass es immer noch keinen Schutz gibt, der verbietet, eine einzelne MyRunnable dass sie nicht gleichzeitig in zwei oder mehr Threads eingereicht werden. Ich weiß, dass Sie sagen, dass Sie das nicht tun... heute :) Mehrere gleichzeitige Ausführungen führen mit hoher Wahrscheinlichkeit zu einem korrupten Zustand. Sie könnten eine gegenseitige Exklusivitätssicherung einbauen (z.B. einfach schreiben synchronized über die run() Methode) zu Beginn der Ausführungsmethode, um sicherzustellen, dass zu einem bestimmten Zeitpunkt nur eine einzige Ausführung stattfindet.

1voto

Brad Mace Punkte 26337

Wenn Sie wirklich gründlich sein wollen, FutureTask behält den Überblick über die Zustände READY , RUNNING , RAN y CANCELLED innerlich. Sie könnten eine Kopie dieser Klasse erstellen und einen Accessor für den Status hinzufügen. Dann überschreiben Sie AbstractExecutorService.newTaskFor(Runnable) zu verpacken, indem Sie Ihre CustomFutureTask (die innere Klasse ist private also wird eine einfache Unterklassifizierung nicht funktionieren).

Die Standardimplementierung von newTaskFor(Runnable) ist wirklich einfach:

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}

Es wäre also kein großes Problem, sie außer Kraft zu setzen.

0voto

Zar E Ahmer Punkte 32557

Da FutureTask ein Callable-Objekt erfordert, werden wir eine einfache Callable-Implementierung erstellen.

import java.util.concurrent.Callable;

    public class MyCallable implements Callable<String> {

        private long waitTime;

        public MyCallable(int timeInMillis){
            this.waitTime=timeInMillis;
        }
        @Override
        public String call() throws Exception {
            Thread.sleep(waitTime);
            //return the thread name executing this callable task
            return Thread.currentThread().getName();
        }

    }

Hier ist ein Beispiel für eine FutureTask-Methode und es zeigt häufig verwendete Methoden von FutureTask.

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class FutureTaskExample {

    public static void main(String[] args) {
        MyCallable callable1 = new MyCallable(1000);
        MyCallable callable2 = new MyCallable(2000);

        FutureTask<String> futureTask1 = new FutureTask<String>(callable1);
        FutureTask<String> futureTask2 = new FutureTask<String>(callable2);

        ExecutorService executor = Executors.newFixedThreadPool(2);
        executor.execute(futureTask1);
        executor.execute(futureTask2);

        while (true) {
            try {
                if(futureTask1.isDone() && futureTask2.isDone()){
                    System.out.println("Done");
                    //shut down executor service
                    executor.shutdown();
                    return;
                }

                if(!futureTask1.isDone()){
                //wait indefinitely for future task to complete
                System.out.println("FutureTask1 output="+futureTask1.get());
                }

                System.out.println("Waiting for FutureTask2 to complete");
                String s = futureTask2.get(200L, TimeUnit.MILLISECONDS);
                if(s !=null){
                    System.out.println("FutureTask2 output="+s);
                }
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }catch(TimeoutException e){
                //do nothing
            }
        }

    }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X