본문 바로가기
Development/JAVA

[자바]쓰레드, 동기화(Synchronization)와 교착상태(DeadLock)

by True Life 2015. 12. 31.


자바 프로그래밍 - 쓰레드, 동기화와 교착상태


오늘은 쓰레드의 연장선, 동기화 및 교착상태에 대해서 포스팅 해보도록 하겠습니다.

쓰레드는 프로그래밍에 매우 빈번히 활용되는 개념, 클래스입니다. 하지만 이 쓰레드는 동시다발성이라는 특성이 있기 때문에 서로 자료를 중복해서 다루게 된다면 치명적인 오류가 발생 가능합니다. 이것을 막기 위해 '동기화(Synchronization)'을 해야 합니다. 하지만 이 동기화라는 조건은 교착상태를 유발할 수 있어 그것도 염두하며 프로그래밍 해야 합니다.


쓰레드를 사용할 경우 충돌을 막기 위해 동기화를 해야되는데 교착상태에 유념해야 한다.


어중이 떠중이 잘 알지도 못하는게 떠들었네요, 시작합니다!


1. 동기화의 필요성(Necessity of Synchronization)


그전에.. 쓰레드가 뭔가요? 하시는분은 아래 글을 읽고 오세요~


[자바]쓰레드-Thread


자, 동기화가 필요한 이유는.. 자원의 공유를 보다 안전하게 하기 위해서입니다.

예제 하나로 이해를 돕겠습니다.



자, 위의 예제는 두마리의 쓰레드가 세번씩 돈을 넣는 과정을 다룹니다.

2*3*10 = 60으로 결과는 아래와 같이 예상됩니다.



하지만 실제 프로그램 스케쥴러는 다릅니다. 결과는 위처럼 인간적일수도 있고 아래처럼 논리적일수도 있습니다.

왜냐, 여기서 tmp변수에 그 이유의 의미가 있습니다.

int tmp = money;

이부분이 진행되고 println 도중 갑자기 또다른 쓰레드가

int tmp = money;를 진행하는 겁니다.

그러면 아직 10원을 더하지 않았기 때문에 그대로 기존 금액을 tmp에 넣어주는 결과를 초래합니다.

이러한 과정의 이유로 10원은 더해지지 않은채 남아있게 됩니다.

이런 결과가 나오는 이유는 tmp 변수를 사용했기 때문입니다.

아래는 잘못된 결과입니다.

자, 그렇다면 항상 원하는 답이 구해지도록 프로그램을 수정하겠습니다.


이렇게 된다면 항상 올바른 답이 나올 것입니다. 왜냐하면 tmp대신 money로 항상 변수를 사용하기 때문에 중간에 쓰레드가 침범할 '과정'이 없기 때문입니다.

자, 그렇다면 이러한 경우 굳이 동기화를 사용해야 할까요?

아닙니다!!

동기화는 반드시 필요한 경우에만 사용해야 합니다. 


자 그렇다면 동기화를 실제로 사용해보도록 하겠습니다.

위 소스에서 쓰레드는 "병렬"로 처리 된다는 것을 다시 한번 되새겨 보시기 바랍니다.


2. 동기화(Synchronization)


자, 위 예제 소스를 동기화 시키겠습니다.


자, 한키워드가 삽입되었을 뿐입니다 synchronized라는 키워드입니다.

synchronized를 이용하여 동기화를 시키는 방법은 크게 두~세가지가 있는데..

1. Synchronized method

2. code block synchronize

3. Object synchronize

(사실 2~3번은 방법이 거의 같습니다.) 상단 예제를 동기화한 방법은 1번으로 메소드를 통채로 동기화 한것입니다. 이로써 저 메소드에는 하나의 쓰레드의 프로세싱이 진행중일 경우 다른 나머지는 대기에 걸립니다. 결국 예제에서는 동시에 tmp가 이용될 가능성이 배제되므로 안전하게 값을 도출해낼 수 있게 됩니다.


두번째 code block은 메소드 안의 '부분'을 {} 블록으로 동기화시키는 것입니다.

이때 항상 어떠한 Object가 매개체로 이용이 되는데 그 매게체의 접근을 동기화 시키는 것으로써 일반적인 경우 객체를 this를 사용해 클래스 자체를 매개하거나 변수등을 매개하여 동기화합니다. (그때 그때 알맞은 설계를 해야하며 상단의 예제의 경우 다들 비슷한(같은) 결과를 볼 수 있을 것입니다.


 - 자, 조금 개략적인 설명을 앞서 해드렸고 차이를 조금 더 명확하게 설명하겠습니다. -

위의 예제와 곧 나올 소스 예제는 거의 동일합니다. method를 동기화하는 것은 매개체를 this(현 클래스)로 잡는 것입니다. 그리고 아래 synchronize(){ }는 매개체를 명시해주는 것인데 이때 this로 명시했으므로 결국 같다고 해도 무방합니다. 하지만 만약 동기화를 하되 어떤 객체의 접근이냐에 따라 다른 동기화를 적용하고 싶으시다면 후자를 이용하되 Object를 지정해주면 됩니다.

블록 synchronize는 멀티쓰레드시 가능한 좁은 범위를 동기화하고 싶으실 때 이용하시면 됩니다.



3. 교착상태(Deadlock)


이제 마지막으로 교착상태에 대해 알아보도록 하겠습니다.

 - 감사합니다 -