멀티스레드 프로그램에서 여러 스레드가 공유 자원을 동시에 접근하면 경쟁상태 또는 데이터 불일치가 발생할 수 있다. 이를 방지하기 위해 스레드들이 순차적으로
자원에 접근할 수 있도록 동기화가 필요하다.
synchronized는 특정 객체의 모니터 락을 사용하여, 한 스레드가 자원을 사용하는 동안 다른 스레드가
해당 자원에 접근하지 못하도록 제어. 자원을 다 사용한 후에는 락을 해제하고, 다른 스레드가 접근할 수 있도록 한다.
임계 영역(critical section)
synchronized 키워드가 있는 메서드에 진입하려면 반드시 해당 인스턴스의 락이 있어야한다.synchronized 안에서 접근하는 변수의 메모리 가시성 문제는 자동으로 해결.@Override
public synchronized boolean withdraw(int amount) {
log("거래 시작: " + getClass().getSimpleName());
log("[검증 시작] 출금액 : " + amount + ", 잔액: " + balance);
if(balance < amount){
log("[검증 실패]" + "출금액 : " + amount + ", 잔액: " + balance);
return false;
}
log("[검증 완료] 출금액 : " + amount + ", 잔액: " + balance);
sleep(1000);
balance -= amount;
log("[출금 완료] 출금액 : " + amount + ", 잔액: " + balance);
log("거래 종료");
return true;
}
synchronized 메서드는 공유 자원을 사용하지 않는 부분도 한 번에 하나의 스레드만 실행을 할 수 있다.synchronized 메서드가 아니라 synchronized 코드 블럭은 특정 코드 블럭에 최적화 해서 적용을 할 수 있는 기능이다.synchronized (this)는 객체가 생성된 그 객체 자체에 대한 락을 걸고, 여러 스레드가 동시에 접근하지 못하게 보호하는 역할을 한다.
synchronized 코드 블럭 예시 코드@Override
public boolean withdraw(int amount) {
log("거래 시작: " + getClass().getSimpleName());
synchronized (this) {
// ==임계 영영 시작==
log("[검증 시작] 출금액 : " + amount + ", 잔액: " + balance);
if(balance < amount){
log("[검증 실패]" + "출금액 : " + amount + ", 잔액: " + balance);
return false;
}
log("[검증 완료] 출금액 : " + amount + ", 잔액: " + balance);
sleep(1000);
balance -= amount;
log("[출금 완료] 출금액 : " + amount + ", 잔액: " + balance);
// ==임계 영영 종료==
}
log("거래 종료");
return true;
}
스레드가 동시에 접근할 수 있는 자원, 객체나 메서드에 대해서 일관성 있꼬 안전한 접긍늘 보장하기 위한 메커니즘이다.
동기화는 주로 멀티스레드 환경에서 발생할 수 있는 문제, ex) 데이터 손상이나 얘기치 않은 결과를 방지하기 위해 사용.
주로 공유 자원에 접근을 하는 거에서 문제가 발생.
이러한 문제들을 해결한게 synchronized이다. synchronized 메서드, 코드 블럭을 사용하여 여러 스레드가 동시에 실행하는 걸 막을 수 있었다.
synchronized 메서드을 사용하면 공유 자원을 시용하지 않는 부분도 오직 하나의 스레드만 실행 할 수 있기 때문에 되도록이면 synchronized 메서드
보다는 임계영역 시작과 종료되는 부분을 잘 구분해서 synchronized 코드 블럭을 사용하는 것이 좋을 거 같다.
이런 동기화를 사용하면 경합 조건(두 개 이상의 스레드가 경쟁적으로 동일한 자원을 수정할 때 발생하는 문제)와
데이터 일관성(여러 스레드가 동시에 읽고 쓰는 데이터의 일관성을 유지)를 해결 할 수 있었다.
과도한 동기화는 성능 저하가 발생할 수 있으므로 동기화는 필요한 곳에 꼭 적절하게 사용을 해야 한다.
그리고 synchronized을 사용하면 메모리 동시성 문제까지 해결 할 수 있으니 너무나 좋은 기능인 거 같다.