Heim  >  Artikel  >  Java  >  Beispiele für das Executor-Framework in Java

Beispiele für das Executor-Framework in Java

黄舟
黄舟Original
2017-09-08 09:49:571806Durchsuche

In diesem Artikel werden hauptsächlich relevante Informationen zur detaillierten Erläuterung von Beispielen des Java Executor-Frameworks vorgestellt, um jedem das Erlernen und Verstehen dieses Teils des Inhalts zu erleichtern

Java Executor Framework Detaillierte Erläuterung von Beispielen

Der größte Teil der Parallelität wird durch die Aufgabenausführung erreicht.

Es gibt im Allgemeinen zwei Möglichkeiten, Aufgaben auszuführen: seriell und parallel.


Natürlich haben beide oben genannten Methoden Probleme. Das Problem beim Single-Threading besteht darin, dass das Ausmaß der Parallelität einen Engpass darstellt. In der Multi-Thread-Version führt die unbegrenzte Thread-Erstellung zu unzureichenden Ressourcen.
class SingleThreadWebServer {
 public static void main(String[] args) throws Exception {
  ServerSocket socket = new ServerSocket(80);
  while(true) {
   Socket conn = socket.accept();
   handleRequest(conn);
  }
 }
}
class ThreadPerTaskWebServer {
 public static void main(String[] args) throws Exception {
  ServerSocket socket = new ServerSocket(80);
  while(true) {
   final Socket conn = socket.accept();
   Runnable task = new Runnable() {
    public void run() {
     handleRequest(conn);
    }
   };
   new Thread(task).start();
  }
 }
}

Executor Framework

Eine Aufgabe ist eine Reihe logischer Arbeitseinheiten, und Threads sind ein Mechanismus, der die asynchrone Ausführung von Aufgaben ermöglicht.

JDK stellt die Executor-Schnittstelle bereit:


Obwohl die Executor-Schnittstelle relativ einfach ist, ist sie die Grundlage des asynchronen Task-Ausführungs-Frameworks, das kann viele verschiedene Arten von Aufgabenausführungsstrategien unterstützen. Es bietet eine Standardmethode zur Entkopplung des Aufgabenübermittlungsprozesses vom Ausführungsprozess. Verwenden Sie Runnable, um Aufgaben darzustellen. Die Implementierung von Executor bietet Mechanismen wie Lebenszyklusunterstützung und statistisches Anwendungsmanagement.
public interface Executor {
  void execute(Runnable command);
}

Executor basiert auf dem Producer-Consumer-Modell. Der Vorgang des Sendens einer Aufgabe entspricht dem des Producers, und der Thread, der die Aufgabe ausführt, entspricht dem Consumer.

Executor-basierte Webserver-Beispiele sind wie folgt:


Darüber hinaus können Sie Ihren eigenen Executor implementieren, um zu steuern, ob er gleichzeitig oder parallel ist , wie im folgenden Code gezeigt:
public class TaskExecutorWebServer {
 private static final int NTHREADS = 100;
 private static final Executor exec = Executors.newFixedThreadPool(NTHREADS);
 public static void main(String[] args) throws Exception {
  ServerSocket serverSocket = new ServerSocket(80);
  while (true) {
   final Socket conn = serverSocket.accept();
   Runnable task = new Runnable() {
    @Override
    public void run() {
     handleRequest(conn);
    }
   };
   exec.execute(task);
  }
 }
}


/**
 * 执行已提交的 Runnable 任务的对象。
 * 此接口提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法。
 * 通常使用 Executor 而不是显式地创建线程。
 *
 *
 * @author renchunxiao
 *
 */
public class ExecutorDemo {
 public static void main(String[] args) {
  Executor executor = new ThreadExecutor();
  executor.execute(new Runnable() {
   @Override
   public void run() {
    // do something
   }
  });
  Executor executor2 = new SerialExecutor();
  executor2.execute(new Runnable() {
   @Override
   public void run() {
    // do something
   }
  });
 }
}
/**
 * 创建一个线程来执行 command
 *
 * @author renchunxiao
 *
 */
class ThreadExecutor implements Executor {
 @Override
 public void execute(Runnable command) {
  new Thread(command).start();
 }
}
/**
 * 串行执行 command
 *
 * @author renchunxiao
 *
 */
class SerialExecutor implements Executor {
 @Override
 public void execute(Runnable command) {
  command.run();
 }
}
Thread-Pool

Thread-Pool ist ein Ressourcenpool von Threads, der kann über die statische Factory-Methode in Executors erstellt werden.

    newFixedThreadPool. Erstellen Sie einen Thread-Pool mit fester Länge und erstellen Sie bei jeder Übermittlung einer Aufgabe einen Thread, bis die maximale Anzahl von Thread-Pools erreicht ist.
  • newSingleThreadExecutor. Einzelner Thread-Pool.
  • newCachedThreadPool. Ein Thread-Pool, der mit der Aufgabengröße skaliert.
  • newScheduledThreadPool. Erstellen Sie einen Thread-Pool mit fester Länge, um Aufgaben verzögert oder zeitgesteuert auszuführen.

  • Die JVM wird erst beendet, nachdem alle Nicht-Daemon-Threads beendet wurden. Wenn der Executor daher nicht ordnungsgemäß geschlossen werden kann, kann die JVM nicht beendet werden.

Um das Lebenszyklusproblem von Ausführungsdiensten zu lösen, gibt es eine neue Schnittstelle ExecutorService, die die Executor-Schnittstelle erweitert.


Der ExecutorService-Lebenszyklus hat drei Zustände: läuft, geschlossen und beendet. ExecutorService wird bei der ersten Erstellung ausgeführt. Die Shutdown-Methode wird ordnungsgemäß heruntergefahren: Sie akzeptiert keine neuen Aufgaben mehr und wartet auf den Abschluss bereits ausgeführter Aufgaben (einschließlich derjenigen, die noch nicht gestartet wurden). Die Methode „shutdownNow“ führt ein grobes Herunterfahren durch: Sie versucht, alle laufenden Aufgaben abzubrechen und startet keine Aufgaben mehr in der Warteschlange, die noch nicht gestartet wurden. Nachdem alle Aufgaben abgeschlossen sind, wechselt es in den beendeten Zustand.
public interface ExecutorService extends Executor {
 void shutdown();
 List<Runnable> shutdownNow();
 boolean isShutdown();
 boolean isTerminated();
 boolean awaitTermination(long timeout, TimeUnit unit)
  throws InterruptedException;
 <T> Future<T> submit(Callable<T> task);
 <T> Future<T> submit(Runnable task, T result);
 Future<?> submit(Runnable task);
 <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
  throws InterruptedException;
 <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
         long timeout, TimeUnit unit)
  throws InterruptedException;
 <T> T invokeAny(Collection<? extends Callable<T>> tasks)
  throws InterruptedException, ExecutionException;
 <T> T invokeAny(Collection<? extends Callable<T>> tasks,
     long timeout, TimeUnit unit)
  throws InterruptedException, ExecutionException, TimeoutException;
}

Callable und Future

Das Executor-Framework verwendet Runnable als grundlegende Aufgabendarstellung. Runnable ist insofern eine eingeschränkte Abstraktion, als seine Ausführungsmethode keinen Wert zurückgeben kann und eine geprüfte Ausnahme auslöst.

Viele Aufgaben sind tatsächlich Berechnungen mit Verzögerungen, wie etwa Datenbankabfragen und das Abrufen von Ressourcen aus dem Netzwerk. Für diese Aufgaben ist Callable eine bessere Abstraktion, die davon ausgeht, dass der Aufruf einen Wert zurückgibt und möglicherweise eine Ausnahme auslöst.

Die vom Executor ausgeführten Aufgaben haben vier Lebenszyklusphasen: Erstellung, Übermittlung, Start und Abschluss. Da einige Aufgaben lange dauern und möglicherweise abgebrochen werden müssen, können im Executor-Framework Aufgaben abgebrochen werden, die übermittelt, aber noch nicht gestartet wurden.

Future stellt den Lebenszyklus einer Aufgabe dar und bietet entsprechende Methoden, um festzustellen, ob sie abgeschlossen oder abgebrochen wurde, sowie um die Ergebnisse der Aufgabe zu erhalten und die Aufgabe abzubrechen usw.

Das obige ist der detaillierte Inhalt vonBeispiele für das Executor-Framework in Java. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn