[해결] 자바 쓰레드 프로그래밍 질문
글쓴이: GunSmoke / 작성시간: 목, 2009/01/29 - 2:49오후
예전에 윤경구씨가 마이크로소프트웨어지에 기고하셨던 원고를 보고 있습니다.
자바 쓰레드 관련 부분을 보고 있는데요.
일단 예제는 다음과 같습니다.
import java.io.*; class LockMonitor { RandomAccessFile raf=null; LockMonitor() { try { raf=new RandomAccessFile("monitor.txt", "rw"); } catch (IOException ie) { System.err.println("IOException:"+ie.getMessage()); return; } Thread thread1=new RaceThread(this, raf); thread1.setName("FirstThread"); thread1.start(); Thread thread2=new RaceThread(this, raf); thread2.setName("SecondThread"); thread2.start(); Thread thread3=new RaceThread(raf, raf); thread3.setName("ThirdThread"); thread3.start(); } public static void main(String args[]) { new LockMonitor(); } } class RaceThread extends Thread { Object monitor; RandomAccessFile raf=null; RaceThread(Object monitor, RandomAccessFile raf) { this.monitor=monitor; this.raf=raf; } // thread class's lifetime public void run() { try { synchronized (monitor) { for (int i=0; i<10; i++) { raf.writeBytes( Thread.currentThread().getName() +":["+i+"]" +raf.getFilePointer() +"\n"); } } } catch (IOException ie) { ie.printStackTrace(); } } }
첫째 쓰레드와 둘째 쓰레드는 동일한 this 객체 인스턴스를 모니터 객체로 사용하지만 셋째 쓰레드는 다른 객체를 모니터 객체로 사용하기 때문에 다른 결과를 낸다는 예제입니다. 첫째 쓰레드와 둘째 쓰레드는 상호간에 동기화되지만 셋째 쓰레드는 다른 두 쓰레드의 동기화 여부를 전혀 고려하지 않고 실행된다는 설명입니다. 프로그램 실행 결과 monitor.txt는 이런 식이어야 합니다.
FirstThread:[0]0 FirstThread:[1]17 ... FirstThread:[9]164 SecondThread:[0]183 ThirdThread:[0]383 ThirdThread:[1]402 ... ThirdThread:[5]478 SecondThread:[1]203 ... SecondThread:[4]263 ThirdThread:[6]497 ...
하지만 제가 실행한 결과는 (정확히 세어보지는 않았습니다만 꽤 많이 해봤습니다.) 그야말로 똑 같습니다. 첫째, 둘째 셋째 쓰레드가 사이좋게 순서대로 차례대로 실행됩니다.
FirstThread:[0]0 FirstThread:[1]17 FirstThread:[2]35 FirstThread:[3]53 FirstThread:[4]71 FirstThread:[5]89 FirstThread:[6]107 FirstThread:[7]126 FirstThread:[8]145 FirstThread:[9]164 SecondThread:[0]183 SecondThread:[1]203 SecondThread:[2]223 SecondThread:[3]243 SecondThread:[4]263 SecondThread:[5]283 SecondThread:[6]303 SecondThread:[7]323 SecondThread:[8]343 SecondThread:[9]363 ThirdThread:[0]383 ThirdThread:[1]402 ThirdThread:[2]421 ThirdThread:[3]440 ThirdThread:[4]459 ThirdThread:[5]478 ThirdThread:[6]497 ThirdThread:[7]516 ThirdThread:[8]535 ThirdThread:[9]554
이쯤에서 질문 나갑니다.
1. 쓰레드 스케줄러의 불확실성에 대해 모르는 바는 아닙니다만 셋째 쓰레드가 첫째, 혹은 둘째 쓰레드 사이에 실행되지 못하는 이유는 제가 동일한 컴퓨터에서만 실행하기 때문인가요?
2. 이렇게 나오는 것이 정상이라고 할 수 있는 것인가요?
3. 쓰레드는 각각 첫째, 둘째, 셋째 차례대로 생성되지만 실행되는 순서만 스케줄러에 의해 바뀌는 것인가요?
Forums:
1. 쓰레드 스케줄러의
1. 쓰레드 스케줄러의 불확실성에 대해 모르는 바는 아닙니다만 셋째 쓰레드가 첫째, 혹은 둘째 쓰레드 사이에 실행되지 못하는 이유는 제가 동일한 컴퓨터에서만 실행하기 때문인가요?
-> 아닙니다. cpu 2개이상이 달린 놈으로 동작시키시면 섞인 결과가 나올 수 있습니다. (반드시 섞이지는 않습니다 - 그야말로 스케줄러 마음대로입니다)
cpu가 2개 달린 제 머신 결과를 올려드립니다.
2. 이렇게 나오는 것이 정상이라고 할 수 있는 것인가요?
-> 네
스케쥴러는 프로그래머가 지정한 차례를 흐트리지 않는 한 (synch 를 깨지 않는 한) 마음대로 스케쥴링 합니다.
3. 쓰레드는 각각 첫째, 둘째, 셋째 차례대로 생성되지만 실행되는 순서만 스케줄러에 의해 바뀌는 것인가요?
-> 네 생성은 차례로 해 주니 ( thread1 = new ... thread2 = new ... thread3 = new ...) 이 차례로 쓰레드는 생성됩니다.
위와 같은 결과는 너무 빨리 일이 끝나서 마치 순서대로 수행되는 것 처럼 보인 것입니다.
처리 시간이 길면 명확히 보이게 할 수 있습니다.
제 3의 Lock 을 사용해서 억지로 처리를 길게 만든 코드입니다.
이 코드를 수행시켜 보시면 쓰레드 1과 3이 핑퐁을 하는 도중이지만 2가 끼여들지 못하고 대기하고 있다가 1과 3이 끝나면 (1과 3이 잡은 latencyLock 과 1이 잡은 file lock 이 풀리면)
그제서야 2가 수행되는 것을 보실 수 있습니다.
결과입니다.
--
말할 수 있는 것은 분명하게 말해질 수 있다;
말해질 수 없는 것에 대해서는 침묵해야한다.
논리철학논고 - 루드비히 비트겐슈타인
--
말할 수 있는 것은 분명하게 말해질 수 있다;
말해질 수 없는 것에 대해서는 침묵해야한다.
논리철학논고 - 루드비히 비트겐슈타인
명쾌한 답변, 친절한
명쾌한 답변, 친절한 해설, 덧붙여 응용 예제까지
너무나 감사드립니다.
大逆戰
大逆戰
댓글 달기