jdk1.7.0_79
이전 글 "ThreadPoolExecutor 스레드 풀 원리와 그 실행 방법"에서 스레드 풀 ThreadPoolExecutor의 원리와 그 실행 방법에 대해 언급한 적이 있습니다. 이 기사에서는 ThreadPoolExecutor#submit을 분석합니다.
작업을 실행하려면 결과를 반환할 필요가 없지만 실행 결과를 반환해야 하는 경우가 있습니다. 스레드의 경우 결과를 반환할 필요가 없으면 Runnable을 구현할 수 있고, 결과를 실행해야 하는 경우 Callable을 구현할 수 있습니다. 스레드 풀에서 실행은 결과를 반환할 필요가 없는 작업 실행도 제공하며, 결과를 반환해야 하는 작업의 경우 submit 메서드를 호출할 수 있습니다.
ThreadPoolExecutor의 상속 관계를 검토하세요.
Executor 인터페이스에는 실행 메소드만 정의되어 있고, ExecutorService 인터페이스에는 submit 메소드가 정의되어 있습니다.
//ExecutorServicepublic interface ExecutorService extends Executor { ... <T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); <T> Future<T> submit(Runnable task); ... }
그리고 submit 메소드는 서브클래스 AbstractExecutorService에서 구현됩니다.
//AbstractExecutorServicepublic abstract class AbstractExecutorService implements ExecutorService { ... public <T> Future<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task); execute(ftask); return ftask; } public <T> Future<T> submit(Runnable task, T result) { if (task == null) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task); execute(ftask); return ftask; } public Future<?> submit(Runnable task) { if (task == null) throw new NullPointerExeption(); RunnableFuture<Void> ftask = newTaskFor(task, null); execute(ftask); return ftask; } ... }
AbstractExecutorService에 구현된 submit 메소드는 실제로 submit 메소드의 알고리즘 뼈대를 정의하는 템플릿 메소드이며, 그 실행은 서브클래스에 넘겨진다. (많은 소스코드에서 템플릿 메소드 패턴이 널리 사용되고 있음을 알 수 있다. 템플릿 메소드 패턴은 "템플릿 메소드 패턴"을 참고한다.)
submit 메소드는 스레드 실행의 반환값을 제공할 수 있지만, Callable이 구현된 경우에만 반환되며 Runnable을 구현하는 스레드에는 반환 값이 없습니다. 즉, 위의 세 가지 메서드 중 submit(Callable
제출 방법에 대한 느낌을 주기 위해 아래에 세 가지 예가 나와 있습니다.
submit(Callable
package com.threadpoolexecutor;import java.util.concurrent.*;/** * ThreadPoolExecutor#sumit(Callable<T> task) * Created by yulinfeng on 6/17/17. */public class Sumit1 {public static void main(String[] args) throws ExecutionException, InterruptedException { Callable<String> callable = new Callable<String>() {public String call() throws Exception { System.out.println("This is ThreadPoolExetor#submit(Callable<T> task) method.");return "result"; } }; ExecutorService executor = Executors.newSingleThreadExecutor(); Future<String> future = executor.submit(callable); System.out.println(future.get()); } }
submit(실행 가능한 작업, T 결과)
package com.threadpoolexecutor;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/** * ThreadPoolExecutor#submit(Runnable task, T result) * Created by yulinfeng on 6/17/17. */public class Submit2 {public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executor = Executors.newSingleThreadExecutor(); Data data = new Data(); Future<Data> future = executor.submit(new Task(data), data); System.out.println(future.get().getName()); } }class Data { String name;public String getName() {return name; }public void setName(String name) {this.name = name; } }class Task implements Runnable { Data data;public Task(Data data) {this.data = data; }public void run() { System.out.println("This is ThreadPoolExetor#submit(Runnable task, T result) method."); data.setName("kevin"); } }
제출(실행 가능한 작업)
package com.threadpoolexecutor;import java.util.concurrent.ExecutionException;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/** * ThreadPoolExecutor#sumit(Runnable runnables) * Created by yulinfeng on 6/17/17. */public class Submit {public static void main(String[] args) throws ExecutionException, InterruptedException { Runnable runnable = new Runnable() {public void run() { System.out.println("This is ThreadPoolExetor#submit(Runnable runnable) method."); } }; ExecutorService executor = Executors.newSingleThreadExecutor(); Future future = executor.submit(runnable); System.out.println(future.get()); } }
위의 예를 보면 submit(Runnable runnable)을 호출할 때 정의된 타입이 필요하지 않다는 것을 알 수 있다. 즉, ExecutorService에 정의된 Generic 메소드이기는 하지만 AbstractExecutorService에서는 Generic 메소드가 아니기 때문이다. 반환 값이 없습니다. (Object, T, ?의 차이점은 "Java에서 Object, T(Generics), ?의 차이점"을 참조하세요.)
위의 소스 코드에서 세 가지 메서드가 거의 동일하다는 것을 알 수 있습니다. 핵심은 다음과 같습니다.
RunnableFuture<T> ftask = newTaskFor(task); execute(ftask);
작업을 newTaskFor에 매개 변수로 전달한 다음 실행 메서드를 호출하고 마지막으로 ftask를 반환하는 방법 은 어떻게 되느냐?
//AbstractExecutorService#newTaskForprotected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { return new FutureTask<T>(callable); } protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { return new FutureTask<T>(runnable, value); }
FutureTask 인스턴스가 반환된 것으로 보이며 FutureTask는 Future 및 Runnable 인터페이스를 구현합니다. Future 인터페이스는 비동기 계산에 사용할 수 있는 Java 스레드 Future 모드의 구현입니다. Runnable 인터페이스를 구현한다는 것은 스레드로 실행될 수 있음을 의미합니다. FutureTask는 이 두 인터페이스를 구현합니다. 이는 비동기 계산의 결과를 나타내고 실행을 위한 스레드로 Executor에 전달될 수 있음을 의미합니다. FutureTask는 다음 장에서 별도로 분석됩니다. 따라서 이 기사의 스레드 풀 ThreadPoolExecutor 스레드 풀의 제출 메소드에 대한 분석은 완료되지 않았습니다. Java 스레드의 미래 모드 - "14. Java의 미래 모드"를 이해해야 합니다.
위 내용은 ThreadPoolExecutor 스레드 풀의 제출 메소드의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!