2011년 5월 22일 일요일

스레드의 동기화(Synchronization)

자바에서는 쓰레드 자체가 어떻게 움직일지 우리가 예상할수 없으므로 다중쓰레드를 사용하다보면 예기치못한 문제를 야기할수 있다. 보여줄 예제를 설명삼아 미리 얘기해 보겠다. 여러개의 쓰레드에게 각기 다른 출력 메세지를 주고 모든 쓰레드를 작동시킨다. 문제는 한 쓰레드가 일정시간 출력을 하다가 대기모드로 전환하면 이어서 다른 쓰레드가 출력을 할것이고 쓰레드 각자가 맡은 메세지를 다 출력할수도 있고 안하고 다른 쓰레드에게 바턴이 넘어갈수도 있을 것이다. 그렇다면 화면에 출력되는 메세지는 아래처럼 말그대로 뒤죽박죽 두서가 없어질 것은 자명하다.


[강이의 자바강좌[쓰레드의 동기화[Synchronization]
]
]

동시 프로그래밍 영역에서 다중쓰레드는 말그대로 어디로 튈지 모르는 공과 같다. 어느 쓰레드가 먼저 작동할런지는 모르지만 이왕 작동했으면 처음부터 끝까지 맡은바 임무(출력 메세지)는 완수하도록 권한을 부여하는 것이 동기화(Synchronization)라 할수 있겠는데 동기화라는 말자체가 어려워서 많이 애먹는것 같다. 필자는 동기화라는 표현보다는 보호막이라는 표현이 synchronization을 이해하는데 더 도움이 될꺼라 생각한다.


자바에서 다중쓰레드가 공유하고 있는 자원을 어떤 쓰레드가 실행하고 있을때 다른 쓰레드는 접근하지 못하도록 막아주는 "보호막" 같은 장치가 바로 synchronized 라는 키워드다. 쓰는 방법은 쓰레드에서 보호막 치기를 원하는 부분을 { } 블록으로 감싸고 그 위에 synchronized(레퍼런스) 라는 타이틀을 만들어주면 된다. 다시 코드로 표현하면 아래와 같이 될것이다.

synchronized(레퍼런스)
{
   ...
   ......
}


[강이의 자바강좌]
[Synchronization]
[쓰레드의 동기화]

예제에서는 쓰레드에게 권한을 주는 용도로 쓰일 레퍼런스를 key라고 명하고 Object를 이용해 만들어 쓰고 있는데 이 권한을 같이 공유하면서 서로 쓸수 있도록 만들어야되므로 static을 붙였다. 결과에서 보듯이 한 쓰레드가 key(권한)를 얻어 출력을 시작하면 다른 쓰레드가 출력이 끝날때까지 대기했다가 key(권한)를 넘겨받아 자신이 가진 메세지를 출력하고 남아있는 쓰레드도 역시 출력이 끝날때까지 기다렸다가 본인이 가진 메세지를 key(권한)를 넘겨받은 후에야 출력을 한다. 예제에서는 쓰레드가 3개인 다중쓰레드를 작동하였는데 작업환경에 따라 어느 구문이 먼저 출력될지는 장담할수 없겠지만 어느 쓰레드건 출력을 시작했으면 처음부터 끝까지 그 구문은 완전하게 찍히는 것을 확인할수 있을 것이다.

이렇게 일정 구문을 동기화 시켜서(보호막 만들어서) 사용한다고 하여 동기화 구문(Synchronized Statements)이라고 부른다. 말나온김에 동기화 메소드(Synchronized Methods)도 공부해 보자. 말그대로 메소드앞에 그러니까 메소드 리턴타입앞에 synchronized 키워드를 붙여주면 메소드 전체를 동기화 즉 보호막 만들어서 사용할수 있다.

synchronized void print(String message )
{
   ...
   ......
}

이 경우에는 쓰레드가 해당클래스의 객체를 공유하도록 만들어야 정상적으로 작동된다. 이렇게 설명하고 끝내면 비난(?)이 빗발칠걸로 예상되므로 동기화 메소드에 관련된 예제도 아래에 준비하였으니 코드를 보면서 연구해보기 바란다. 결과는 위와 같을 것이나 이번에는 구문이 아닌 메소드를 동기화시켰다는게 차이점이다.


예제를 간략하게 설명하자면 클래스의 레퍼런스로 key를 만들어 쓰레드끼리 공유해서 쓰도록 하고 있고 쓰레드의 실행블록인 run( ) 메소드에서 동기화시킨 print( ) 메소드를 key 레퍼런스를 이용해 불러서 쓰면 특정 쓰레드가 해당블록 실행시 다른 쓰레드가 관련 메소드에 들어오지 못하도록 보호막을 쳐준다. key의 데이터형이 지금 클래스명이라는 것을 여러분이 알아챘기 바란다. 예제를 곰곰히 이리저리 씹어보면 어느순간(?) 이해가 되기 시작할 것이다. 생성자(constructor)를 이용하면 코드가 훨씬 더 간결해질 것이나 이해를 돕고자 기존 예제를 최대한 건드리지 않는 쪽으로 가닥을 잡아서 만든 까닭에 소스가 좀 길다. 마음에 안들면 생성자를 이용해서 여러분이 원하는데로 응용해 보기 바란다.+ 제발 해봐라.ㅎㅎ 또한 synchronized 키워드를 메소드에서 제하고 다시 실행을 하여 무슨 차이가 있는지 비교하기 바란다.^^

쓰레드의 동기화는 동시 프로그래밍 영역에서 매우 유용하게 쓰이는 부분이다. 이보다 더 간단할수는 없다라는 심정으로 쓰레드의 Synchronization에 관한 가장 기본적인 내용만이라도 확실하게 기억하기를 바라면서 본 강좌를 아주 심플하게 구성하였으니 더도 덜도말고 최소한 오늘 배운 내용은 확실하게 습득하기 바란다.^^

댓글 10개:

  1. 잘 보았습니다.. 열심히 복습해야겠습니다 ㅠ

    답글삭제
  2. 쓰레드 동기화 파트에서 갑자기 벽에 부딪힌 느낌이네요
    몇 번이고 다시 봤지만 이해가 안가는 부분이 수두륵 ㅜㅜ
    갑자기 Object를 이용해서 key를 생성한다는 부분도 그렇고
    메서드의 동기화에서는 객체선언과 생성을 클라스 내부와 메인에서
    동시에 더군다나 그 객체를 꼭! 주고 받아야만 에러가 없다는 것..
    왜 또.. 첫 예제의 구문 동기화처럼 메서드의 동기화에서는 Object
    혹은, 실행파일을 이용하지 않았는지에 대한점 등등..
    추가 설명이 없는한 평생 이해를 못할 듯 하네요 ㅜㅜ

    답글삭제
  3. 여기부터 좀 어려워졌네요 ㅠㅠ

    답글삭제
  4. 저도 정확히 이해는 못했지만 Object 안쓰고 다른 클래스로 객체로 레퍼런스역할을 할수 있도록 해도 실행 되네요.
    예를 들어 static Test54 key =new Test54();이렇게요. 포인트는 앞에 static을 붙여서 서로 값을 공유할 수 있도록 설정한거 같네요 ㅎ

    답글삭제
  5. When some one searches for his required thing, so he/she
    wants to be available that in detail, thus that thing is maintained
    over here.

    Stop by my web blog - cellulite treatment

    답글삭제
  6. 두번째 예제에서는 key라는 변수는 없어도 샐행되네요.. key가 필요한 부분을 모두 삭제 ...

    답글삭제
  7. osmosis skin care reviews

    Visit my blog; organic skin care

    답글삭제
  8. 그럼 join() 메소드와의 차이점이 뭔가요

    join()메소드도 해당 start() 메소드밑에 선언하면 해당 스레드 끝나고 다음 스레드가 실행되자나요??ㅠㅠ

    답글삭제
  9. Hi, I do hink this is a great blog. I stumbledupon it ;)
    I may return once again since I bookmarked it.
    Money and freedom is the best way to change, may you be
    rich and continue to guide others.

    Feel free to visit my web page phentermine

    답글삭제
  10. 두 가지가 무엇이 다를까요..? 힌트를 얻으세용.

    http://www.tutorialspoint.com/java/java_thread_synchronization.htm

    답글삭제