동기화 관련 문제에 걸려 여러 모로 고민을 하다 아래와 같은 글을 찾았습니다.
정녕 실제 프로그래미에는 적용을 하지 않았지만, 경쟁적 쓰레드 구조에서 언젠간 써먹을 날이 있을 것 같습니다.
쓰레들의 경쟁 부추기기… ㅡㅡ;
동기화 메소드(synchronized
method)
동기화
블록은 블록 안의 코드만을 동기화하는 반면에 동기화 메소드는 메소드 전체를 동기화한다. 동기화 메소드의 형태는 다음과 같다.
|
synchronized void [코드] } |
동기화
메소드도 동기화 블록처럼 모니터를 가진 스레드에게 실행권한을 주는 방식으로 동기화 블록과 크게 다르지 않다. 그렇다면 여기서 말하는 모니터는
어떤 객체의 모니터일까? 바로 자기 자신의 모니터, 즉, this의 모니터를 말하는 것이다.
어떤
스레드가 this의 f()를 실행하고 있다면 다른 스레드는 f()를 만났을 때 대기하게 된다. 다른 말로 this의 모니터를 얻은 객체가
f()를 실행할 수 있다.
따라서
동기화 메소드를 동기화 블록으로 변환한다면 다음과 같을 것이다.
|
void f(){ synchronized(this){ [코드]; } } |
다음은
예제는 쓰레드가 공유하고 있는 객체에 대하여 동기화 메소드를 사용한 것이다.
|
Synchronization5.java |
class Printer{
synchronized void
printChar(char ch){ // x1, 동기화 메소드, 문자를 10회 출력
for(int
i=1;i<=10;i++)
System.out.print(ch);
}
}
class PrinterThread
extends Thread{
Printer ptr;
// 공유할 객체
char ch;
// 출력할 문자
PrinterThread(Printer ptr, char
ch){ // 생성자
this.ptr=ptr;
this.ch=ch;
}
public void run(){
for(int
i=1;i<=10;i++){
ptr.printChar(ch);
// x2
System.out.println();
}
}
}
public class
Synchronization5{
public static void
main(String[] args){
Printer ptr=new
Printer(); // 공유 객체
PrinterThread pt1=new
PrinterThread(ptr,’A’); // x3
PrinterThread pt2=new
PrinterThread(ptr,’B’); // x4
pt1.start();
pt2.start();
}
}
|
출력 결과 |
AAAAAAAAAA
…
BBBBBBBBBB
AAAAAAAAAA
BBBBBBBBBB
…
BBBBBBBBBB
x1행의
printChar()는 동기화 메소드이다. 따라서 이 메소드를 실행할 수 있는 스레드는 printChar()을 멤버로 가지는 객체의 모니터를
가지는 스레드이다. 그런데 주의할 점은 스레드가 Printer 클래스로부터 생성되는 객체를 공유하고 있어야 동기화가 적용된다는 것이다. x3행과
x4행에서 ptr이 공유되고 있음을 확인하자. x2행을 실행할 수 있는 스레드는 ptr의 모니터를 가진 스레드이다. ptr의 모니터를 가진
스레드가 메소드를 실행하고 빠져 나오면 x2행에서 대기하고 있던 나머지 스레드 중의 한 놈이 ptr의 모니터를 얻고 printChar 메소드를
실행한다.
x1행의
synchronized 키워드를 삭제하고 실행해보면 동기화와 비동기화의 차이를 알 수 있다.
|
혼자 해보기 |
Alone14_4.java |
출력 결과와 같이 실행되도록 아래 소스를 수정해
보자.
public class Alone14_4
extends Thread{
IntArrayBuffer iab;
int num;
public Alone14_4(IntArrayBuffer
iab , int num){
this.iab = iab;
this.num = num;
}
public void run(){
iab.add(new int[]{num, num,
num, num, num});
}
public static void
main(String[] args){
IntArrayBuffer iab=new
IntArrayBuffer();
Alone14_4 ob1 = new
Alone14_4(iab, 1);
Alone14_4 ob2 = new
Alone14_4(iab, 2);
ob1.start();
ob2.start();
try{ ob1.join(); ob2.join();
}catch(InterruptedException ie){}
System.out.println(iab.sb);
}
static class
IntArrayBuffer{
StringBuffer sb=new
StringBuffer();
public void add(int[]
array){
for(int i=0;
i<array.length; i++){
sb.append(array[i]);
try{Thread.sleep(100);}catch(Exception e){}
}
}
}
}
|
출력 결과 예시 |
경우1: “1111122222”
경우2: “2222211111”