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 BeispielenDer 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.
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(); } } }
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:
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:
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 ist ein Ressourcenpool von Threads, der kann über die statische Factory-Methode in Executors erstellt werden.
Um das Lebenszyklusproblem von Ausführungsdiensten zu lösen, gibt es eine neue Schnittstelle ExecutorService, die die Executor-Schnittstelle erweitert.
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; }
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!