쓰레드의 동기화(1): Critical Section & Lock, snychronized
1. Critical Section과 Lock
- 싱글 쓰레드 프로세스의 경우 하나의 쓰레드가 자원을 가지고 작업하기 때문에 별 문제가 없지만,
멀티 쓰레드 프로세스의 경우 같은 프로세스 내의 자원을 공유해서 작업하기 때문에 서로 영향을 주게 된다.
- 쓰레드 A,B가 있다고 가정해보자. 쓰레드 A가 공유 데이터를 작업하는 도중 쓰레드 B가 제어권을 얻어
공유데이터를 변경하게 된다면, 사용자는 다른 결과를 얻게 될 것이다.
- 이러한 일이 발생하는 것을 방지하기 위해서 한 쓰레드가 작업을 끝마치기 전까지 다른 쓰레드에
의해 방해받지 않도록 하는 것이 필요하다.
- 그래서 도입된 개념이 바로 Critical Section과 Lock이다.
( 앞으로 간단하게 부르기 위해 전자는 CS를 후자는 L이라고 지칭한다. )
- CS는 공유 데이터를 사용하는 코드 영역을 말하며, L은 공유 데이터(객체)가 가지고 있으며 CS 영역을
수행하기 위한 권한이다.
( 그러므로, L은 단 하나의 쓰레드만 가질 수 있다. )
- L을 획득한 쓰레드는 작업을 마치면, L을 반납해야만 다른 쓰레드가 CS영역을 수행할 수 있다.
- 이처럼 한 쓰레드가 진행 중인 작업을 다른 쓰레드가 간섭하지 못하도록 막는 것을 '쓰레드 동기화'
(synchronization)이라고 부른다.
- 자바에서는 JDK 1.5부터 'java.util.concurrent.locks'와 'java.util.concurrent.atomic' 패키지를 통해서
지원한다.
2. synchronized를 이용한 동기화
- CS를 지정하기 위해서는 아래의 두 가지 방식이 있다.
(1) 메서드 전체를 CS로 지정
: 쓰레드는 synchronized가 붙여진 메서드가 호출 =되자말자 L을 얻게 된다.
public synchronized void method{
//..
}
(2) 특정한 영역을 CS로 지정
: 참조변수는 L을 걸고자하는 객체를 참조하는 것이어야 한다.
synchronized(객체의 참조변수){
//..
}
( 위 두 방법 모두 L의 획득과 반납은 자동이므로, 사용자는 그저 CS만 지정해주면 된다. )
( 모든 객체는 L을 가지고 있다. )
( CS는 멀티쓰레드 프로그램의 성능을 좌우하기 때문에, 되도록이면 메서드 전체보다는 (2)을
사용하여 최소화하는 것이 중요하다. )
2-1. synchronized를 이용한 동기화를 이해하기 위한 예제(1)
: 은행계좌에서 잔고를 확인하고 출금을 하는 예제이다.
import java.util.*;
public class Exercise017 {
public static void main(String[] args) {
Runnable r = new RunnableEx17();
new Thread(r).start();
new Thread(r).start();
}
}
class RunnableEx17 implements Runnable{
Acount acc = new Acount();
public void run() {
while(acc.getBalance()>0) {
int money = (int)(Math.random()*3+1)*100;
acc.withdraw(money);
System.out.println("balance::" + acc.getBalance());
}
}
}
class Acount{
private int balance = 1000;
public int getBalance() {
return balance;
}
public void withdraw(int money) {
if(balance >= money) {
try { Thread.sleep(1000); }catch (InterruptedException e) {}
balance-=money;
}
}
}
( 음수가 나오지 않게 조건문을 했지만, 두 쓰레드가 공유데이터에 접근을 제한하지 않았기 때문에 원하지 않는
값이 나오게 되었다. )
( 그러므로, 두 쓰레드가 공유데이터를 접근하는 메서드(withdraw) 앞에 synchronized를 붙여 접근을 제한한다. )
( 또한 synchronized 블럭을 사용하면 아래와 같다. )
( 여기서 주의할 점은 공유데이터 변수의 접근제어자는 private로 지정하는 것이 좋다. )
( 하지 않는다면, 아무리 동기화를 설정해도 다른 외부접근으로부터 값이 변경되기 때문이다. )
다음장
쓰레드의 동기화(1): Critical Section & Lock, snychronized (tistory.com)
쓰레드의 동기화(1): Critical Section & Lock, snychronized
1. Critical Section과 Lock - 싱글 쓰레드 프로세스의 경우 하나의 쓰레드가 자원을 가지고 작업하기 때문에 별 문제가 없지만, 멀티 쓰레드 프로세스의 경우 같은 프로세스 내의 자원을 공유해서 작
kind-coding.tistory.com