Java 고유 락 (Intrinsic Lock)

기술노트

Java 고유 락 (Intrinsic Lock)

---

Intrinsic Lock / Synchronized Block / Reentrancy

Intrinsic Lock (= monitor lock = monitor) : Java의 모든 객체는 lock을 갖고 있음.

Synchronized 블록은 Intrinsic Lock을 이용해서, Thread의 접근을 제어함.

java
public class Counter {
    private int count;
    
    public int increase() {
        return ++count;		// Thread-safe 하지 않은 연산
    }
}


Q) ++count 문이 atomic 연산인가?

A) read (count 값을 읽음) -> modify (count 값 수정) -> write (count 값 저장)의 과정에서, 여러 Thread가 공유 자원(count)으로 접근할 수 있으므로, 동시성 문제가 발생함.


Synchronized 블록을 사용한 Thread-safe Case
java
public class Counter{
    private Object lock = new Object(); // 모든 객체가 가능 (Lock이 있음)
    private int count;
    
    public int increase() {
        // 단계 (1)
        synchronized(lock){	// lock을 이용하여, count 변수에의 접근을 막음
            return ++count;
        }
        
        /* 
        단계 (2)
        synchronized(this) { // this도 객체이므로 lock으로 사용 가능
        	return ++count;
        }
        */
    }
    /*
    단계 (3)
    public synchronized int increase() {
    	return ++count;
    }
    */
}

단계 3과 같이 lock 생성 없이 synchronized 블록 구현 가능



Reentrancy

재진입 : Lock을 획득한 Thread가 같은 Lock을 얻기 위해 대기할 필요가 없는 것

(Lock의 획득이 '호출 단위'가 아닌 Thread 단위로 일어나는 것)

java
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();
    }
}


Structured Lock vs Reentrant Lock

Structured Lock (구조적 Lock) : 고유 lock을 이용한 동기화

(Synchronized 블록 단위로 lock의 획득 / 해제가 일어나므로)


따라서,

A획득 -> B획득 -> B해제 -> A해제는 가능하지만,

A획득 -> B획득 -> A해제 -> B해제는 불가능함.

이것을 가능하게 하기 위해서는 Reentrant Lock (명시적 Lock) 을 사용해야 함.


Visibility
  • 가시성 : 여러 Thread가 동시에 작동하였을 때, 한 Thread가 쓴 값을 다른 Thread가 볼 수 있는지, 없는지 여부
  • 문제 : 하나의 Thread가 쓴 값을 다른 Thread가 볼 수 있느냐 없느냐. (볼 수 없으면 문제가 됨)
  • Lock : Structure Lock과 Reentrant Lock은 Visibility를 보장.
  • 원인 :

1. 최적화를 위해 Compiler나 CPU에서 발생하는 코드 재배열로 인해서. 2. CPU core의 cache 값이 Memory에 제때 쓰이지 않아 발생하는 문제.