- 멀티 스레드 프로세스에서는 다른 스레드의 작업에 영향을 미칠 수 있다.
- 진행 중인 작업이 다른 스레드에게 간섭받지 않게 하려면 동기화가 필요
스레드의 동기화
한 스레드가 진행 중인 작업을 다른 스레드가 간섭하지 못하게 막는 것
- 동기화하려면 간섭받지 않아야 하는 문장들을 '임계 영역'으로 설정
- 임계영역은 락(lock)을 얻은 단 하나의 스레드만 출입가능(객체 1개에 락 1개)
synchronized를 이용한 동기화
synchronized로 임계영역(lock이 걸리는 영역)을 설정하는 방법 2가지
1. 메서드 전체를 임계 영역으로 지정
public synchronized void calcSum() {
//...
}
2. 특정한 영역을 임계 영역으로 지정
synchronized(객체의 참조변수) { // 참조변수는 락을 걸고자하는 객체를 참조하는 것이어야 함
//...
}
임계영역은 최소화해야 한다. 가능하면 메서드 전체로 하지 않는 것이 좋다.
class ThreadEx21 {
public static void main(String args[]) {
Runnable r = new RunnableEx21();
new Thread(r).start(); // ThreadGroup에 의해 참조되므로 gc대상이 아니다.
new Thread(r).start(); // ThreadGroup에 의해 참조되므로 gc대상이 아니다.
}
}
class Account {
private int balance = 1000; // private로 해야 동기화가 의미가 있다.
public synchronized int getBalance() {
return balance;
}
public synchronized void withdraw(int money){ // synchronized로 메서드를 동기화
if(balance >= money) {
try { Thread.sleep(1000);} catch(InterruptedException e) {}
balance -= money;
}
} // withdraw
}
class RunnableEx21 implements Runnable {
Account acc = new Account();
public void run() {
while(acc.getBalance() > 0) {
// 100, 200, 300중의 한 값을 임으로 선택해서 출금(withdraw)
int money = (int)(Math.random() * 3 + 1) * 100;
acc.withdraw(money);
System.out.println("balance:"+acc.getBalance());
}
} // run()
}

임계영역을 지정하지 않으면 A, B, C 세 개의 스레드가 100원씩 출금한다고 가정했을 때, 잔고가 200인 상태에서 세 스레드가 모두 if문을 통과할 수 있고 그 경우 잔고가 -가 될 수 있다.
하지만 임계영역을 지정하면 제일 먼저 들어온 스레드 이외에는 다른 스레드가 들어오지 못하기 때문에 잔고가 위의 문제가 발생하지 않는다.
참고로 위 코드를 메서드 전체가 아닌 특정한 영역을 임계 영역으로 지정하는 것은 아래와 같다.
class Account {
private int balance = 1000;
public synchronized int getBalance() {
return balance;
}
public void withdraw(int money){
synchronized(this) {
if(balance >= money) {
try { Thread.sleep(1000);} catch(InterruptedException e) {}
balance -= money;
}
}
} // withdraw
}
계좌인 Account에 대해 락을 거는 것이기 때문에 synchronized()의 참조변수로 Account에 해당하는 this를 사용했다.
'JAVA' 카테고리의 다른 글
| [Thread] 스레드의 동기화 - Lock과 Condition (0) | 2023.02.28 |
|---|---|
| [Thread] wait(), notify() (0) | 2023.02.27 |
| [Thread] join(), yield() (0) | 2023.02.27 |
| [Thread] suspend(), resume(), stop() (0) | 2023.02.27 |
| [Thread] sleep(), interrupt()와 interrupted() (0) | 2023.02.26 |