Thread가 여러 개가 각각 완벽하게 독립적인 일을 수행할 수도 있지만, 때로는
그렇지 않고 하나의 객체를 경쟁하면서 사용할 수도 있고 혹은 Thread끼리 정보를 주고
받는 등의 협력을 할 수도 있습니다.
만약 Thread가 서로 완벽하게 독립적이지 않고 하나의 객체를 서로 경쟁하면서 사용하려고
할 때가 많은데 이때는 반드시 주의해야 합니다. 문제가 아주 복잡해질 수 있으니까요.
예를 하나 들어보겠습니다.
짝수를 항상 돌려주는 객체를 생각해보겠습니다.
Even객체를 만들고 next()메소드를 호출하면 항상 짝수를 돌려주겠지요. 의심의 여지가
없는 완벽한 클래스입니다. (숫자가 증가해서 Overflow나는것은 생각하지 말구요.)
/**
* 항상 짝수만 만드는 클래스입니다.
*/
public class Even {
private long number = 0;
public long next() {
number++;
number++;
return number;
}
}
예제 8 - 2 Even.java
그러나 문제가 없다는 주장하는 것은 하나의 Thread가 Even객체를 이용하는 경우일 때의
얘기입니다. 만약 여러 개의 Thread가 Even객체의 레퍼런스를 가지고 동시에 메소드를
호출 했을때는 미묘한 문제가 발생할 수 있습니다.
무슨 말인가 하면, Thread가 Even객체의 레퍼런스를 가지고 동시에 public int next()를
호출하면 number++가 두번 호출되고 그 값이 리턴됩니다.
여기서 꼼꼼히 살펴보겠습니다. number++는 number = number + 1의 의미입니다.
이는 number변수의 값을 읽어서 그 값에 1을 더하란 말인데 경쟁하는 Thread가 있어서
Even객체의 레퍼런스를 가지고 public int next()를 호출했다면 number값에 변화가 생길 수
있습니다.
Thread A |
Thread B |
read 0 |
|
write 1 (1증가 시킴) |
|
|
read 1 |
|
write 2 (1 증가시킴) |
read 2 |
read 2 |
|
write 3 (1 증가시킴) |
write 3 (1증가 시킴) |
return 3 |
return 3 |
|
표 8 - 1 경쟁하는 Thread가 Even객체의 next()메소드를 호출했을 때
표 8 - 1은 Even객체 하나를 두고 경재하는 Thread A와 Thread B가 시간순서에 따라
공유하는 Even객체의 next()메소드를 호출한 후의 메모리 상태를 언급한 것입니다.
Thread A의 경우 number값을 읽으면 0 이어서 1로 증가했구요. 다음에 읽었을때는
1이어야 하겠지만, Thread B때문에 2가 되었고 거기서 1을 증가한 후에 돌려주기
때문에 3을 돌려주는 결과가 되버렸습니다.
즉, Even객체는 항상 짝수를 돌려주지 못할 수 있습니다. 즉 경쟁하는 Thread환경에서
공유당하는 Even객체는 안전하지 않다는 것입니다.
/**
* Even객체를 이용하려고 하는 경쟁하는 Thread입니다.
*/
public class CompetingThread {
public static void main(String[] args) {
final Even even = new Even();
new Thread(new Runnable() {
public void run() {
for(long i = 0; i < 10000000; i++) {
if (even.next() % 2 != 0)
System.out.println("Opps ! Not Even");
}
}
}).start();
new Thread(new Runnable() {
public void run() {
for(long i = 0; i < 10000000; i++) {
if (even.next() % 2 != 0)
System.out.println("Opps ! Not Even");
}
}
}).start();
}
}
예제 8 - 3 CompetingThread.java
예제 8 - 3의 CompetingThread는 2개의 Thread가 경쟁해서 한 개의 Even객체의 next()
메소드를 호출하고 있습니다. 물론 대개의 경우는 짝수를 얻을 수 있을 것입니다.
하지만 수만번, 수백만번, 수천만번 실행하다보면 한 두번씩 홀수를 얻을 수 있습니다.
물론 이것은 결코 일어나서는 안되는 사건이지요.
경쟁하는 Thread들이 동시에 사용하는 객체는 기본적으로 다중 Thread 환경에서 객체
스스로의 상태가 Thread들의 동시다발적인 메소드 호출로 인해서 객체의 상태가 어긋날 수
있습니다. 이런 이유로 객체는 경쟁하는 Thread로부터 객체의 상태가 어긋나지 않도록
스스로를 보호하는 방법을 확보하고 있어야 합니다.
'자바 Threads Programming > Basic' 카테고리의 다른 글
Thread-6.Thread 우선순위 (0) | 2008.01.07 |
---|---|
Thread-5.Thread 라이프사이클(Life Cycle) (0) | 2008.01.07 |
Thread-4.간단한 Thread 검색 프로그램 (0) | 2007.12.28 |
Thread-3.Thread와 Thread의 상속 (0) | 2007.12.28 |
Thread-2.Thread의 사용방법 (0) | 2007.12.18 |