Java에서 Runnable 인터페이스와 Callable 인터페이스의 차이점
Java에서 동시 스레드를 디자인 할 때 인터페이스 Runnable
와 Callable
인터페이스 를 사용하는 것의 차이점은 무엇입니까 ?
Callable 인터페이스는 Runnable과 비슷합니다. 둘 다 인스턴스가 다른 스레드에 의해 잠재적으로 실행될 수있는 클래스를 위해 설계되었습니다. 그러나 Runnable은 결과를 반환하지 않으며 확인 된 예외를 throw 할 수 없습니다.
어떤이의 애플리케이션에서 차이가있다
Runnable
및Callable
. 에 반환 매개 변수와의 차이점 만Callable
있습니까?
기본적으로 그렇습니다. 이 질문에 대한 답변을 참조하십시오 . 에 대한 javadocCallable
.
Callable
모든 것을 할 수 있다면 둘 다 가질 필요는 무엇입니까Runnable
?
Runnable
인터페이스 가 모든 것을 할 수 없기 때문에 Callable
!
Runnable
Java 1.0 이후로 사용되었지만 Callable
Java 1.5에서만 소개되었습니다 ... Runnable
지원하지 않는 사용 사례를 처리하기 위해. 이론적으로 Java 팀은 Runnable.run()
메소드 의 서명을 변경했을 수 있지만 이는 1.5 이전 코드와 바이너리 호환성을 손상시켜 이전 Java 코드를 최신 JVM으로 마이그레이션 할 때 코드를 다시 작성해야합니다. 그것은 큰 NO-NO입니다. Java는 이전 버전과의 호환성을 위해 노력하고 있으며 이는 비즈니스 컴퓨팅을위한 Java의 가장 큰 판매 지점 중 하나입니다.
그리고 분명히 작업이 결과를 반환하거나 확인 된 예외를 throw 할 필요 가없는 사용 사례가 있습니다 . 이러한 유스 케이스의 경우 사용 Runnable
은 메소드 에서 Callable<Void>
더미 ( null
) 값을 사용 하고 리턴하는 것보다 더 간결 합니다 call()
.
- A는
Callable
구현해야call()
잠시 방법을Runnable
요구 구현하는run()
방법을. - A
Callable
는 값을 반환 할 수 있지만 a는 반환Runnable
할 수 없습니다. - A
Callable
는 확인 된 예외를 던질 수 있지만Runnable
불가능합니다. A
Callable
는ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)
메소드 와 함께 사용할 수 있지만 aRunnable
는 사용할 수 없습니다.public interface Runnable { void run(); } public interface Callable<V> { V call() throws Exception; }
나는 이것을 다른 블로그 에서이 차이점을 조금 더 설명 할 수있는 것을 발견했다 .
두 인터페이스는 다른 실행 스레드에서 실행하려는 클래스에 의해 구현되지만 두 인터페이스 사이에는 다음과 같은 차이점이 거의 없습니다.
Callable<V>
인스턴스 유형의 결과를 반환V
반면,Runnable
인스턴스하지 않습니다.Callable<V>
인스턴스는 반면, 체크 된 예외를 던질 수Runnable
인스턴스가 없습니다
Java 디자이너는 Runnable
인터페이스 의 기능을 확장해야 할 필요성을 느꼈지만 인터페이스의 사용에 영향을 미치고 싶지 Runnable
않았을 것입니다. 아마도 Callable
Java 1.5에서 별도의 인터페이스를 이미 사용했던 것보다 기존 Runnable
.
Runnable과 Callable을 사용할 위치를 살펴 보겠습니다.
Runnable과 Callable은 모두 호출 스레드와 다른 스레드에서 실행됩니다. 그러나 Callable은 값을 반환하고 Runnable은 반환 할 수 없습니다. 그래서 이것이 실제로 어디에 적용됩니까?
Runnable : 화재가 있고 작업을 잊어 버린 경우 Runnable을 사용하십시오. Runnable에 코드를 넣고 run () 메서드가 호출되면 작업을 수행 할 수 있습니다. 호출 스레드는 실제로 작업을 수행 할 때 중요하지 않습니다.
호출 가능 : 작업에서 값을 검색하려는 경우 호출 가능을 사용하십시오. 이제 스스로 호출 할 수는 없다. Callable을 감싸고 future.get ()에서 가치를 얻는 미래가 필요합니다. 여기서 호출 스레드는 Future가 결과로 돌아올 때까지 차단되며 결과적으로 Callable의 call () 메소드가 실행되기를 기다리고 있습니다.
So think about an interface to a target class where you have both Runnable and Callable wrapped methods defined. The calling class will randomly call your interface methods not knowing which is Runnable and which is Callable. The Runnable methods will execute asynchronously, till a Callable method is called. Here the calling class's thread will block since you are retrieving values from your target class.
참고 : 대상 클래스 내에서 단일 스레드 실행기에서 Callable 및 Runnable을 호출 하여이 메커니즘을 직렬 디스패치 큐와 유사하게 만들 수 있습니다. 호출자가 Runnable 랩핑 된 메소드를 호출하는 한 호출 스레드는 차단하지 않고 실제로 빠르게 실행됩니다. Future 메소드에서 Callable wrap을 호출하자마자 대기중인 다른 모든 항목이 실행될 때까지 차단해야합니다. 그래야만 메소드가 값과 함께 리턴됩니다. 이것은 동기화 메커니즘입니다.
Callable
인터페이스는 call()
메소드를 선언 하고 Object call () 유형이 반환해야하므로 제네릭을 제공해야합니다.
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
Runnable
반면 run()
에 runnable을 사용하여 Thread를 작성하고 start ()를 호출 할 때 호출되는 메소드 를 선언 하는 인터페이스입니다 . 직접 run ()을 호출 할 수도 있지만 run () 메서드를 실행하는 것은 동일한 스레드입니다.
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
몇 가지 주목할만한 차이점을 요약하면
Runnable
반면 객체는 결과를 반환하지 않는Callable
개체가 결과를 반환합니다.Runnable
개체가 예외를 throw 할 수 있는 동안 개체는 확인 된 예외를 throw 할 수 없습니다Callable
.Runnable
반면 인터페이스는 자바 1.0 이후 주변왔다Callable
에만 자바 1.5에서 소개되었습니다.
몇 가지 유사점 포함
- Runnable 또는 Callable 인터페이스를 구현하는 클래스의 인스턴스는 다른 스레드에 의해 잠재적으로 실행될 수 있습니다.
- Callable 및 Runnable 인터페이스의 인스턴스는 submit () 메소드를 통해 ExecutorService에 의해 실행될 수 있습니다.
- 둘 다 기능적 인터페이스이며 Java8 이후 Lambda 표현식에서 사용할 수 있습니다.
ExecutorService 인터페이스의 메소드는 다음과 같습니다.
<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);
오라클 문서에서 이러한 인터페이스의 목적 :
실행 가능한 인터페이스는 인스턴스를 a로 실행하려는 모든 클래스에서 구현해야합니다 Thread
. 클래스는라는 인수가없는 메소드를 정의해야합니다 run
.
호출 가능 : 결과를 반환하고 예외가 발생할 수있는 작업입니다. 구현자는 call이라는 인수가없는 단일 메소드를 정의합니다. 이 Callable
인터페이스는 Runnable
인스턴스가 다른 스레드에 의해 잠재적으로 실행될 수있는 클래스를 위해 설계되었다는 점에서 와 비슷합니다 . Runnable
그러나 A 는 결과를 반환하지 않으며 확인 된 예외를 throw 할 수 없습니다.
다른 차이점들 :
Thread
Runnable
를 생성하도록 전달할 수 있습니다 . 그러나 매개 변수 로 전달하여 새 스레드를 만들 수는 없습니다 . Callable을 인스턴스 에만 전달할 수 있습니다 .Callable
ExecutorService
public class HelloRunnable implements Runnable { public void run() { System.out.println("Hello from a thread!"); } public static void main(String args[]) { (new Thread(new HelloRunnable())).start(); } }
Runnable
화재에 사용 하고 전화를 잊어 버립니다. 사용Callable
결과를 확인 할 수 있습니다.Callable
와 달리 invokeAll 메소드에 전달할 수 있습니다Runnable
. 가장 일반적으로 유용한 대량 실행 방법, 작업 모음을 실행 한 후 하나 이상이 완료되기를 기다리는 방법invokeAny
및invokeAll
수행사소한 차이 : 구현할 메소드 이름 =>
run()
forRunnable
andcall()
forCallable
.
이미 언급했듯이 Callable은 비교적 새로운 인터페이스이며 동시성 패키지의 일부로 도입되었습니다. Callable 및 Runnable은 모두 실행 프로그램과 함께 사용할 수 있습니다. Runnable 자체를 구현하는 클래스 스레드는 Runnable 만 지원합니다.
실행기와 함께 Runnable을 계속 사용할 수 있습니다. Callable의 장점은 executor로 전송하여 즉시 완료 할 수 있다는 장점입니다. 실행이 완료되면 업데이트됩니다. Runnable에서도 동일하게 구현 될 수 있지만이 경우 결과를 직접 관리해야합니다. 예를 들어 모든 결과를 보유 할 결과 대기열을 생성 할 수 있습니다. 다른 스레드는이 큐에서 대기하고 도착한 결과를 처리 할 수 있습니다.
+-------------------------------------+--------------------------------------------------------------------------------------------------+
| Runnable | Callable<T> |
+-------------------------------------+--------------------------------------------------------------------------------------------------+
| Introduced in Java 1.0 of java.lang | Introduced in Java 1.5 of java.util.concurrent library |
| Runnable cannot be parametrized | Callable is a parametrized type whose type parameter indicates the return type of its run method |
| Runnable has run() method | Callable has call() method |
| Runnable.run() returns void | Callable.call() returns a value of Type T |
| Can not throw Checked Exceptions | Can throw Checked Exceptions |
+-------------------------------------+--------------------------------------------------------------------------------------------------+
Java 설계자는 Runnable
인터페이스 의 기능을 확장해야 할 필요성을 느꼈지만 인터페이스 사용에 영향을 미치고 싶지 Runnable
않았을 수도 있습니다. 아마도 Callable
Java 1.5에서 별도의 인터페이스를 이미 사용했던 것보다 Runnable
Java 1.0 이후 Java의 일부인 기존 인터페이스 출처
Callable과 Runnable의 차이점은 다음과 같습니다.
- Callable은 JDK 5.0에 도입되었지만 Runnable은 JDK 1.0에 도입되었습니다
- Callable에는 call () 메서드가 있지만 Runnable에는 run () 메서드가 있습니다.
- Callable에는 값을 반환하는 call 메서드가 있지만 Runnable에는 값을 반환하지 않는 run 메서드가 있습니다.
- 호출 메소드는 확인 된 예외를 던질 수 있지만 실행 메소드는 확인 된 예외를 던질 수 없습니다.
- 작업 대기열에 넣으려면 호출 가능한 submit () 메소드를 사용하고 태스크 대기열에 넣으려면 Runnable 사용 execute () 메소드를 사용하십시오.
Callable과 Runnable 은 서로 비슷하며 스레드 구현에 사용할 수 있습니다. 구현하는 경우 의 Runnable을 당신이 구현해야 실행 () 메소드 만 호출의 경우 구현해야한다 ()를 호출 방법을 비슷한 방식으로 만 호출 두 방법의 작품 ()를 호출 방법이 더 flexibility.There는 그들 사이에 약간의 차이가 있습니다.
아래와 같이 Runnable 과 Callable의 차이점
1) runnable 의 run () 메소드 는 void를 반환 합니다. 스레드가 더 사용할 수있는 것을 반환하려면 Runnable run () 메소드를 선택할 수 없습니다 . 'Callable' 솔루션이 있습니다. 객체 형태로 물건을 반환 하려면 Runnable 대신 Callable 을 사용해야합니다 . 호출 가능한 인터페이스에는 Object를 반환하는 'call ()' 메서드가 있습니다 .
메소드 서명-실행 가능->
public void run(){}
호출 가능->
public Object call(){}
2) 확인 된 예외가 발생하면 Runnable run () 메서드의 경우 try catch block으로 처리 해야 하지만 Callable call () 메서드의 경우 다음 과 같이 확인 된 예외 를 throw 할 수 있습니다
public Object call() throws Exception {}
3) Runnable 은 레거시 Java 1.0 버전에서 제공되지만 Callable 은 Executer 프레임 워크 가있는 Java 1.5 버전에서 제공 됩니다.
Executers 에 익숙하다면 Runnable 대신 Callable 을 사용해야 합니다 .
이해하시기 바랍니다.
실행 가능 (vs) Executer 프레임 워크를 사용할 때 Callable 이 시작됩니다.
ExecutorService는 Executor
Runnable 및 Callable 작업을 모두 허용 하는의 하위 인터페이스입니다 .
초기 멀티 스레딩은 Interface 1.0 이후 인터페이스를 사용하여 달성 할 수 있지만 여기서는 스레드 작업을 완료 한 후 스레드 정보를 수집 할 수 없습니다. 데이터를 수집하기 위해 정적 필드를 사용할 수 있습니다.Runnable
예 각 학생 데이터를 수집하기 위해 별도의 스레드.
static HashMap<String, List> multiTasksData = new HashMap();
public static void main(String[] args) {
Thread t1 = new Thread( new RunnableImpl(1), "T1" );
Thread t2 = new Thread( new RunnableImpl(2), "T2" );
Thread t3 = new Thread( new RunnableImpl(3), "T3" );
multiTasksData.put("T1", new ArrayList() ); // later get the value and update it.
multiTasksData.put("T2", new ArrayList() );
multiTasksData.put("T3", new ArrayList() );
}
이 문제를 해결하기 위해 1.5 를 도입 하여 결과를 반환하고 예외를 throw 할 수 있습니다.Callable<V>
단일 추상 메소드 : Callable 인터페이스와 Runnable 인터페이스에는 단일 추상 메소드가 있으며 이는 Java 8의 람다 표현식에 사용될 수 있음을 의미합니다.
public interface Runnable { public void run(); } public interface Callable<Object> { public Object call() throws Exception; }
실행 태스크를 ExecutorService 에 위임하는 방법에는 몇 가지가 있습니다.
execute(Runnable task):void
이 메소드는 void를 리턴하므로 새 스레드를 크레이트하지만 기본 스레드 또는 호출자 스레드를 차단하지 않습니다.submit(Callable<?>):Future<?>
,submit(Runnable):Future<?>
당신이 사용하는 경우 새 스레드와 블록 메인 스레드를 상자 하는 Future.get () .
실행기 프레임 워크에서 호출 가능, 실행 가능 인터페이스를 사용하는 예
class CallableTask implements Callable<Integer> {
private int num = 0;
public CallableTask(int num) {
this.num = num;
}
@Override
public Integer call() throws Exception {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " : Started Task...");
for (int i = 0; i < 5; i++) {
System.out.println(i + " : " + threadName + " : " + num);
num = num + i;
MainThread_Wait_TillWorkerThreadsComplete.sleep(1);
}
System.out.println(threadName + " : Completed Task. Final Value : "+ num);
return num;
}
}
class RunnableTask implements Runnable {
private int num = 0;
public RunnableTask(int num) {
this.num = num;
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " : Started Task...");
for (int i = 0; i < 5; i++) {
System.out.println(i + " : " + threadName + " : " + num);
num = num + i;
MainThread_Wait_TillWorkerThreadsComplete.sleep(1);
}
System.out.println(threadName + " : Completed Task. Final Value : "+ num);
}
}
public class MainThread_Wait_TillWorkerThreadsComplete {
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("Main Thread start...");
Instant start = java.time.Instant.now();
runnableThreads();
callableThreads();
Instant end = java.time.Instant.now();
Duration between = java.time.Duration.between(start, end);
System.out.format("Time taken : %02d:%02d.%04d \n", between.toMinutes(), between.getSeconds(), between.toMillis());
System.out.println("Main Thread completed...");
}
public static void runnableThreads() throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(4);
Future<?> f1 = executor.submit( new RunnableTask(5) );
Future<?> f2 = executor.submit( new RunnableTask(2) );
Future<?> f3 = executor.submit( new RunnableTask(1) );
// Waits until pool-thread complete, return null upon successful completion.
System.out.println("F1 : "+ f1.get());
System.out.println("F2 : "+ f2.get());
System.out.println("F3 : "+ f3.get());
executor.shutdown();
}
public static void callableThreads() throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(4);
Future<Integer> f1 = executor.submit( new CallableTask(5) );
Future<Integer> f2 = executor.submit( new CallableTask(2) );
Future<Integer> f3 = executor.submit( new CallableTask(1) );
// Waits until pool-thread complete, returns the result.
System.out.println("F1 : "+ f1.get());
System.out.println("F2 : "+ f2.get());
System.out.println("F3 : "+ f3.get());
executor.shutdown();
}
}
'Programing' 카테고리의 다른 글
스크롤 막대를 사용하지 않고 iframe을 내용에 따라 높이를 자동으로 조정합니까? (0) | 2020.02.15 |
---|---|
언제 레디 스에? (0) | 2020.02.15 |
React에서 상태와 소품의 차이점은 무엇입니까? (0) | 2020.02.15 |
하이픈으로 구분 된 케이스의 이름은 무엇입니까? (0) | 2020.02.15 |
주어진 Linux가 32 비트인지 64 비트인지 확인하는 방법은 무엇입니까? (0) | 2020.02.15 |