Thread에서 데이터 반환(폴링, 콜백) - Receive data by using thread polling, callback
1. thread의 데이터 반환
- run(), start() 는 어떤 값도 반환하지 않는다.
- 특정한 방법이 필요하다
2. 일반 적인 데이터 반환
1) ThreadTest.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class ThreadTest implements Runnable{
private String fileName;
private String result;
public ThreadTest(String fileName) {
this .fileName = fileName;
}
@Override
public void run() {
FileOutputStream out = null ;
String filePath = "/Users/jeonghui/eclipse-workspace/JavaTest/src/" ;
String content = "Hello" ;
try {
out = new FileOutputStream(filePath + fileName);
out.write(content.getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
out.close();
result = fileName;
} catch (IOException e) {
e.printStackTrace();
}
}
}
public String getResult() {
return result;
}
}
|
- getResult() 를 이용하여 파일 쓰기가 끝나면 파일 이름을 반환한다.
2) ThreadInterface.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import java.io.IOException;
public class ThreadInterface {
public static void main(String[] args) throws IOException {
String[] files = { "abc0.txt" , "abc1.txt" , "abc2.txt" };
for (String filename : files) {
ThreadTest tt = new ThreadTest(filename);
Thread t = new Thread(tt);
t.start();
System.out.println(tt.getResult());
}
}
}
|
- getResult() 를 호출하여 확인한다.
3) 문제
- 그러나 콘솔에는 null 값이 출력되거나 운 좋다면 파일 명이 나올 수 있다.
- 스레드의 처리 속도와 main() 의 속도가 불일치(경쟁조건) 하다.
3. 폴링(polling)을 이용한 경쟁조건 해결
1) 폴링(polling) 이란?
- 동기화를 목적으로 상태를 주기적으로 검사하여 일정 조건이 만족하면 처리하는 방법
2) 위의 문제 해결
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import java.io.IOException;
public class ThreadInterface {
public static void main(String[] args) throws IOException {
String[] files = { "abc0.txt" , "abc1.txt" , "abc2.txt" };
ThreadTest[] tt = new ThreadTest[files.length];
for ( int i = 0 ; i<files.length; i++) {
tt[i] = new ThreadTest(files[i]);
Thread t = new Thread(tt[i]);
t.start();
}
for ( int i = 0 ; i<files.length; i++) {
while ( true ) {
if (tt[i].getResult() != null ) {
System.out.println(tt[i].getResult());
break ;
}
}
}
}
}
|
- 반복적으로 null 을 체크하여 아니라면 출력한다.
3) 문제
- 체크하기 위하여 너무 많은 일을 한다.
- 메인 스레드가 작업종료 상태를 계속 확인해야 하기 때문에 다른 스레드가 일할 시간 없다(성능저하)
4. 콜백(callback) 으로 문제 해결
1) 콜백(callback) 이란?
- 단일 스레드의 작업이 끝났을 때 자신을 생성한 클래스를 호출하여 메인 스레드에게 결과를 알려준다.
- 폴링의 무한 루프로 결과값을 체크하는 문제 해결
1) ThreadTest.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class ThreadTest implements Runnable{
private String fileName;
private String result;
public ThreadTest(String fileName) {
this .fileName = fileName;
}
@Override
public void run() {
FileOutputStream out = null ;
String filePath = "/Users/jeonghui/eclipse-workspace/JavaTest/src/" ;
String content = "Hello" ;
try {
out = new FileOutputStream(filePath + fileName);
out.write(content.getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
out.close();
ThreadInterface.ThreadResult(fileName);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public String getResult() {
return result;
}
}
|
- 정적 메소드를 호출하여 결과값을 전달한다.
2) ThreadInterface.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import java.io.IOException;
public class ThreadInterface {
public static void ThreadResult(String name) {
System.out.println(name);
}
public static void main(String[] args) throws IOException {
String[] files = { "abc0.txt" , "abc1.txt" , "abc2.txt" };
ThreadTest[] tt = new ThreadTest[files.length];
for ( int i = 0 ; i<files.length; i++) {
tt[i] = new ThreadTest(files[i]);
Thread t = new Thread(tt[i]);
t.start();
}
}
}
|
- 반환 값을 받기위한 정적메소드
3) 개선
- 정적메소드를 호출하는 것보다 인스턴스를 생성하여 반환값을 받는 것이 더 좋다.
4) 문제
- 스레드의 순서가 없다. 먼저 종료되는 스레드의 결과를 먼저 받는다.
- 순서가 필요한 결과 값이라면 다른 방법이 필요하다.(Future, callable, Executor)