public class Counter {
private int count;
public int increase() {
return ++count;
}
}
Q) ++count 문이 atomic 연산인가?
A) read (count 값을 읽음) > modify (count 값 수정) > write (count 값 저장)의 과정에서, 여러 Thread가 공유 자원(count)으로 접근할 수 있으므로, 동시성 문제가 발생함.
✅ 동시성 문제는 결국 여러 스레드가 공유 자원 (count 변수)에 접근하기 때문에 발생하는데 동시성 문제를 해결하기 위해 count 변수로 접근하는 스레드를 제어해야 함
public class Counter {
private Object lock = new Object();
private int count;
public int increase() {
synchronized(lock) {
return ++count;
}
}
}
public class Counter {
private int count;
public int increase() {
synchronized(this) {
return ++count;
}
}
}
public class Counter {
private int count;
public synchronized int increase() {
return ++count;
}
}
public class Reentrancy {
// b가 Synchronized로 선언되어 있더라도, a 진입시 lock을 획득하였음.
// b를 호출할 수 있게 됨.
public synchronized void a() {
System.out.println("a");
b();
}
public synchronized void b() {
System.out.println("b");
}
public static void main (String[] args) {
new Reentrancy().a();
}
}
Q. 고유락(Intrinsic Lock)이란 무엇인가요?
✅ 고유락은 모든 자바 객체가 가지며, synchronized 블록과 고유락을 이용하여 스레드의 접근을 제어할 수 있습니다.
Q. Synchronized 블록을 어떻게 사용하여 Thread-safe를 구현할 수 있나요?
✅ lock이라는 Object의 인스턴스를 이용하여 스레드가 동시에 count 변수에 접근하지 못하도록 제어하거나 Counter 의 인스턴스를 이용해 this 로 제어하거나 메서드에 synchronized 키워드를 붙여주는 것으로 구현할 수 있습니다.
Q. 구조적인 락(Structured Lock)은 무엇인가요?
✅ synchronized 블록 단위로 락의 획득과 해제가 이루어지는 방식을 의미하며 블록에 진입할 때 락을 획득하고, 블록을 벗어날 때 락을 해제합니다. 이로 인해 특정 순서로 락을 획득하고 해제하는 제약이 발생하는데, 가령 A락 획득 > B락 획득 > B락 해제 > A락 해제 순서와 같은 제약이 생깁니다.
Q. Reentrancy(재진입 가능성)란 무엇인가요?
✅ Java의 고유락은 재진입이 가능하며, 이미 락을 획득한 스레드는 동일한 락을 다시 획득할 때 대기할 필요 없이 바로 진행됩니다.
Q. Visibility 문제는 무엇인가요?
✅ Visibility는 여러 스레드가 동시에 메모리의 값을 제대로 볼 수 있는지의 문제이며, 최적화나 멀티 코어 환경에서 발생하는 코드 재배열, 코어 캐시의 문제 등으로 발생할 수 있습니다. synchronized 또는, Reentrant Lock을 사용하면 visibility 문제를 해결할 수 있습니다.
참고자료
Java의 고유 락(intrinsic lock)에 대해
<CS 지식> Java 고유락 (Intrinsic Lock)
원자적(atomic) 연산과 순서(ordering) 제약