반환 값이 관심사가 아닌 경우 ExecutorService의 submit 또는 execute 중에서 어떻게 선택해야 합니까?
둘 다 테스트하면 반환 값을 제외하고 둘 사이에 차이가 없었습니다.
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.execute(new Task());
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
threadExecutor.submit(new Task());
답변
예외 / 오류 처리와 관련하여 차이가 있습니다.
함께 대기중인 태스크 execute()
그 일부는 생성 Throwable
의 원인이됩니다 UncaughtExceptionHandler
(가)에 대한 Thread
호출 할 작업을 실행할 수 있습니다. 사용자 정의 핸들러가 설치되지 않은 경우 UncaughtExceptionHandler
일반적으로 Throwable
스택 추적을에 인쇄하는 기본값 System.err
이 호출됩니다.
한편, Throwable
작업에 의해 생성과 함께 대기 submit()
의지 바인드 Throwable
받는 사람 Future
에 대한 호출에서 생산하였습니다 submit()
. 호출 하면 원본 을 원인으로 (을 호출 하여 액세스 할 수 get()
있음) Future
을 던집니다 .ExecutionException
Throwable
getCause()
ExecutionException
답변
실행 : 화재에 사용하고 전화를 잊어
제출 : 메소드 호출 결과를 검사하고 호출에Future
의해 리턴 된오브젝트에대해적절한 조치를 수행하는 데 사용하십시오.
에서 의 javadoc
submit(Callable<T> task)
실행을 위해 가치 반환 작업을 제출하고 보류중인 작업 결과를 나타내는 Future를 반환합니다.
Future<?> submit(Runnable task)
실행 가능한 실행 가능 태스크를 제출하고 해당 태스크를 나타내는 Future를 리턴합니다.
void execute(Runnable command)
나중에 언젠가 주어진 명령을 실행합니다. 명령은 실행기 구현의 재량에 따라 새 스레드, 풀링 된 스레드 또는 호출 스레드에서 실행될 수 있습니다.
를 사용하는 동안 예방 조치를 취해야 submit()
합니다. 작업 코드를 try{} catch{}
블록에 포함시키지 않으면 프레임 워크 자체에서 예외가 숨겨 집니다.
예제 코드 : 이 코드는 제비 Arithmetic exception : / by zero
입니다.
import java.util.concurrent.*;
import java.util.*;
public class ExecuteSubmitDemo{
public ExecuteSubmitDemo()
{
System.out.println("creating service");
ExecutorService service = Executors.newFixedThreadPool(10);
//ExtendedExecutor service = new ExtendedExecutor();
service.submit(new Runnable(){
public void run(){
int a=4, b = 0;
System.out.println("a and b="+a+":"+b);
System.out.println("a/b:"+(a/b));
System.out.println("Thread Name in Runnable after divide by zero:"+Thread.currentThread().getName());
}
});
service.shutdown();
}
public static void main(String args[]){
ExecuteSubmitDemo demo = new ExecuteSubmitDemo();
}
}
산출:
java ExecuteSubmitDemo
creating service
a and b=4:0
() 로 대체 submit()
하여 동일한 코드가 발생합니다 execute
.
바꾸다
service.submit(new Runnable(){
와
service.execute(new Runnable(){
산출:
java ExecuteSubmitDemo
creating service
a and b=4:0
Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zero
at ExecuteSubmitDemo$1.run(ExecuteSubmitDemo.java:14)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
submit ()을 사용하는 동안 이러한 유형의 시나리오를 처리하는 방법은 무엇입니까?
- try {} catch {} 블록 코드를 사용 하여 작업 코드 ( Runnable 또는 Callable 구현 중 하나)를 포함 시킵니다.
- 도구
CustomThreadPoolExecutor
새로운 솔루션 :
import java.util.concurrent.*;
import java.util.*;
public class ExecuteSubmitDemo{
public ExecuteSubmitDemo()
{
System.out.println("creating service");
//ExecutorService service = Executors.newFixedThreadPool(10);
ExtendedExecutor service = new ExtendedExecutor();
service.submit(new Runnable(){
public void run(){
int a=4, b = 0;
System.out.println("a and b="+a+":"+b);
System.out.println("a/b:"+(a/b));
System.out.println("Thread Name in Runnable after divide by zero:"+Thread.currentThread().getName());
}
});
service.shutdown();
}
public static void main(String args[]){
ExecuteSubmitDemo demo = new ExecuteSubmitDemo();
}
}
class ExtendedExecutor extends ThreadPoolExecutor {
public ExtendedExecutor() {
super(1,1,60,TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(100));
}
// ...
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t == null && r instanceof Future<?>) {
try {
Object result = ((Future<?>) r).get();
} catch (CancellationException ce) {
t = ce;
} catch (ExecutionException ee) {
t = ee.getCause();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt(); // ignore/reset
}
}
if (t != null)
System.out.println(t);
}
}
산출:
java ExecuteSubmitDemo
creating service
a and b=4:0
java.lang.ArithmeticException: / by zero
답변
반환 유형에 신경 쓰지 않으면 execute를 사용하십시오. 미래의 귀환없이 제출과 동일합니다.
답변
Javadoc에서 가져온 것 :
메소드 는 실행을 취소하거나 완료를 기다리는 데 사용할 수있는 {@link Future}를 작성하고 리턴하여
submit
기본 메소드 {@link Executor #execute
}를 확장합니다 .
개인적으로 나는 실행이 더 선언적이라고 생각하기 때문에 실행의 사용을 선호합니다. 비록 이것이 실제로 개인적인 선호의 문제입니다.
더 많은 정보를 제공하려면 다음의 경우 ExecutorService
구현의 핵심 구현에 호출에 의해 반환되는 Executors.newSingleThreadedExecutor()
입니다 ThreadPoolExecutor
.
submit
전화는 부모가 제공하는 AbstractExecutorService
모든 호출은 내부적으로 실행합니다. 실행이 ThreadPoolExecutor
직접 재정의 / 제공됩니다 .
답변
로부터 자바 독 :
명령은 실행기 구현의 재량에 따라 새 스레드, 풀링 된 스레드 또는 호출 스레드에서 실행될 수 있습니다.
따라서 구현에 따라 Executor
작업이 실행되는 동안 제출 스레드가 차단 될 수 있습니다.
답변
전체 답변은 여기에 게시 된 두 가지 답변으로 구성되어 있습니다 (약간 “추가”).
- 작업을 제출하면 (vs. 실행) 결과를 얻거나 작업을 취소하는 데 사용할 수있는 미래를 다시 얻을 수 있습니다. 당신은 이러한 종류의 제어가없는 때
execute
(그 반환 유형 ID 때문에void
) execute
예상합니다Runnable
동안이submit
중 하나 걸릴 수 있습니다Runnable
또는Callable
(- 아래 참조 둘 사이의 차이에 대한 자세한 정보를 원하시면) 인수로가.execute
검사되지 않은 예외는 즉시 확인하고 (확인 된 예외를 던질 수 없습니다 !!!) 결과로 반환되는 미래submit
에 어떤 종류의 예외도 바인딩future.get()
하고 (랩 된) 예외 를 호출 할 때만 throw됩니다. 얻을 수있는 Throwable은 인스턴스 이며이ExecutionException
객체를 호출getCause()
하면 원래 Throwable을 반환합니다.
몇 가지 더 (관련된) 포인트 :
- 원하는 작업
submit
에서 결과를 반환하지 않아도을 사용할 수 있습니다Callable<Void>
(대신 사용Runnable
). - 인터럽트 메커니즘을 사용하여 작업 취소를 수행 할 수 있습니다 . 취소 정책을 구현하는 방법 의 예 는 다음과 같습니다.
요약 submit
하면, Callable
(와 vs)를 execute
함께 사용하는 것이 좋습니다 Runnable
. Brian Goetz의 “실제로 Java 동시성”을 인용하겠습니다.
6.3.2 결과를내는 작업 : 소명과 미래
Executor 프레임 워크는 Runnable을 기본 작업 표현으로 사용합니다. Runnable은 상당히 제한적인 추상화입니다. run은 로그 파일에 쓰거나 결과를 공유 데이터 구조에 배치하는 등의 부작용이있을 수 있지만 값을 반환하거나 확인 된 예외를 throw 할 수 없습니다. 데이터베이스 쿼리 실행, 네트워크를 통한 리소스 페치 또는 복잡한 기능 계산 등 많은 작업이 계산을 효과적으로 지연시킵니다. 이러한 유형의 작업의 경우 Callable은 더 나은 추상화입니다. 주요 항목 인 call은 값을 반환하고 예외를 throw 할 것으로 예상합니다. Callable이있는 java.security.PrivilegedAction.
답변
허용 된 답변에 추가하기 만하면됩니다.
그러나 태스크에서 발생한 예외는 execute ()로 제출 된 태스크에 대해서만 예외를 처리되지 않은 예외 핸들러로 만듭니다. submit ()을 사용하여 실행기 서비스에 제출 된 태스크의 경우, 예외는 태스크 리턴 상태의 일부로 간주됩니다.