SSISO Community

시소당

Callable을 사용하여 Runnable로부터 결과 반환

저자 John Zukowski

Runnable
인터페이스는 자바 플랫폼 초기부터 사용되어 왔습니다. 이 인터페이스를 사용하면 완료할 작업을 스레드별로 정의할 수 있습니다. 대부분의 사용자들이 이미 알고 있듯이 이 인터페이스는 run()이 라는 단일 메서드를 사용하는데, 이 메서드는 인수를 허용하지 않고 값을 반환하지 않으며 확인된 어떤 예외도 반환할 수 없습니다. 방금 완료된 작업으로부터 값을 반환 받으려면 인터페이스 외부의 메서드를 사용하여 작업이 완료되었다는 일종의 알림 메시지를 기다려야 합니다. 예를 들어, 이러한 시나리오의 경우 다음과 같이 코딩해야 합니다.

  Runnable runnable = ...;
Thread t = new Thread(runnable);
t.start();
t.join();
String value = someMethodtoGetSavedValue()

원칙적으로 이 코드에 잘못된 점은 없지만 J2SE 5.0에서 소개된 Callable 인터페이스 덕분에 이제는 다른 방법을 사용할 수 있습니다. run() 메서드를 사용하는 대신 Callable 인터페이스는 call() 메서드를 제공하며 이 메서드는 Object를 반환하거나, 보다 구체적으로 generic화된 형식에 사용된 유형을 반환합니다.

  public interface Callable<V> {
V call() throws Exception;
}

실행할 ThreadCallable을 전달할 수 없기 때문에 대신 ExecutorService를 사용하여 Callable 개체를 실행합니다. 이 서비스는 Callable 개체를 수락하여 submit() 메서드를 통해 실행합니다.

  <T> Future<T> submit(Callable<T> task)

메서드 정의에서 보여 주듯이 Callable 개체를 ExecutorService에 제공하면 Future 개체가 반환됩니다. 그런 다음 Futureget() 메서드는 작업이 완료될 때까지 차단을 수행합니다. 이것은 첫 번째 예에서 join() 호출과 동일합니다. 실제로 이 메서드는 join() 호출과 동일하며, get()Callable 인스턴스에서 계산한 값을 반환할 때 get value 호출과도 동일합니다.

이를 설명하기 위해 다음 예에서는 명령줄에서 전달된 각 단어에 대해 Callable 인스턴스를 개별적으로 만들어 길이를 모두 합산합니다. 각각의 Callable은 개별 단어의 합만을 계산합니다. Future 개체 집합은 각각으로부터 계산된 값을 얻기 위해 저장됩니다. 반환된 값의 순서를 유지해야 할 경우 List를 대신 사용할 수 있습니다.

import java.util.*;
import java.util.concurrent.*;

public class CallableExample {

public static class WordLengthCallable
implements Callable {
private String word;
public WordLengthCallable(String word) {
this.word = word;
}
public Integer call() {
return Integer.valueOf(word.length());
}
}

public static void main(String args[]) throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(3);
Set<Future<Integer>> set = new HashSet<Future&lg;Integer>>();
for (String word: args) {
Callable<Integer> callable = new WordLengthCallable(word);
Future<Integer> future = pool.submit(callable);
set.add(future);
}
int sum = 0;
for (Future<Integer> future : set) {
sum += future.get();
}
System.out.printf("The sum of lengths is %s%n", sum);
System.exit(sum);
}
}

WordLengthCallable은 각 단어를 저장하고 이 단어의 길이를 call() 메서드의 반환 값으로 사용합니다. 이 값은 생성하는 데 시간이 다소 걸릴 수 있지만 이 예에서는 즉시 생성됩니다. call()은 호출 종료 시 반환된 값만을 필요로 합니다. Futureget() 메서드가 나중에 호출될 경우 이 예에서처럼 작업이 금방 실행되면 Future에서 값을 바로 받고, 작업이 오래 걸릴 경우에는 완료될 때까지 기다립니다. get()을 여러 번 호출한다고 해서 스레드에서 작업이 다시 실행되지는 않습니다.

이 프로그램의 목표는 단어 길이의 합을 계산하는 것이므로 Callable 작업의 완료 순서는 문제가 되지 않습니다. 처음 세 개의 작업이 완료되기 전에 마지막 작업이 완료되어도 상관 없습니다. Future에 대한 첫 번째 get() 호출은 Set의 첫 번째 작업이 완료되기만을 기다립니다. 이는 다른 작업이 개별적으로 실행되는 것을 막지 않으며, 단지 하나의 스레드 또는 작업이 완료되기를 기다립니다.

제공되는 모든 서비스는 고정 크기의 스레드 풀을 사용할 것이므로 이 특정 예에서는 ExecutorService에 대해 고정 크기의 스레드 풀을 사용합니다.

실행자 및 스레드 풀 사용에 대한 자세한 내용은 Java Tutorial의 Executors 단원을 참조하십시오. SwingWorker 클래스는 약간 다르긴 하지만 Future와 함께 작동하는 Runnable 개체의 또 다른 예입니다. 이에 대한 자세한 내용은 Worker Threads and SwingWorker 단원을 참조하십시오.

************

NetBeans6
NetBeans 6.0 통합 개발 환경(IDE)은 보다 다양한 기능과 속도를 자랑하는 편집기, Rails에서의 Ruby/JRuby/Ruby 지원, 향상된 스윙 개발을 위한 확장 기능, 새로운 비주얼 게임 디자이너, 개선된 데이터 바인딩 지원, 통합 프로파일링 등과 같은 기능을 통해 개발자의 생산성을 한층 높여 줍니다. NetBeans 6.0 다운로드하기


이 글의 영문 원본은
http://blogs.sun.com/CoreJavaTechTips/entry/get_netbeans_6
에서 보실 수 있습니다.

출처 : http://www.sdnkorea.com/blog/509

867 view

4.0 stars