STUDY/JAVA

[JAVA] ReentrantLock 설명

ReCode.B 2023. 5. 8. 21:24
728x90

ReentrantLock란?

동기화된 메소드와 문장을 사용하여 액세스 할 수 있는 암시적인 모니터 잠금 기능과 같은

기본적인 동작과 의미를 가진 Reentrant 상호 간의 상호 배제된 상호 배제 잠금 기능을 의미한다.

이는 마치 뮤텍스와 많이 흡사한 모습을 띄고 있다.

즉, 상호 배타적 락이며 기본적으로 synchronized 키워드를 이용한 암시적인 모니터와 같이 동작한다.

동기화에는 아래와 같은 내용들이 있는데 이중 ReentrantLock는 Mutex라고 생각하면 쉽다.

 

방법 설명
 임계영역(critical section)  공유 자원에 대해 단 하나의 스레드만 접근하도록 한다.
 (하나의 프로세스에 속한 스레드만 가능하다) 
 뮤텍스 (mutex)  공유 자원에 대해 단 하나의 스레드만 접근하도록 한다.
 (서로 다른 프로세스에 속한 스레드도 가능) 
 이벤트 (event)   특정한 사건의 발생을 다른 스레드에게 알린다. 
 세마포어 (Semaphore)  한정된 개수의 자원을 여러 스레드가 사용하려고 할 때 접근을 제한한다.  
 대기 가능 타이머 (waitable timer)  특정 시간이 되면 대기중이던 스레드를 깨운다.

 

synchronized 블럭은 자동으로 lock이 잠기고 풀리기 때문에 편리하지만,

ReentrantLock 클래스를 이용하면 다양한 고급기능을 사용할 수 있습니다.

  • Lock polling을 지원한다.
  • 코드가 단일 블록 형태를 넘어서는 경우 사용 가능 하다.
  • 타임 아웃을 지정할 수 있다.
  • Condition을 적용해서 대기 중인 쓰레드를 선별적으로 깨울 수 있다.
  • lock 획득을 위해 waiting pool에 있는 쓰레드에게 인터럽트를 걸 수 있다.

즉, 위의 기능이 필요할 때 synchronized 블럭 대신 ReentrantLock을 적용하면 됩니다.

 

사용법

//Constructor
ReentrantLock()
ReentrantLock(boolean fair)

ReentrantLock은 두 개의 생성자를 가지고 있으며, fair를 true로 주면 가장 오래 기다린 쓰레드가 lock을 얻을 수 있도록 공정하게 처리합니다.

단, 공정하게 처리하려면 어떤 쓰레드가 가장 오래 기다렸는지 확인하는 과정이 필요하므로 성능은 떨어집니다.

 

//Method
void lock() // lock 잠금
void unlock() // lock 해제
boolean isLocked() // lock이 잠겼는지 확인
boolean tryLock() // lock polling
boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException

자동으로 lock의 잠금과 해제가 관리되는 synchronized 블럭과는 다르게,

수동으로(명시적으로) lock을 잠그고 해제 합니다.

 

일반적인 lock()은 lock을 얻을 때 까지 쓰레드를 블락시키므로 context swtich에 따른 overhead가 발생할 수 있는데, Critical Section의 수행시간이 매우 짧을 경우에는 tryLock()을 통한 Lock polling(SpinLock)을 통해

효율적인 locking이 가능합니다. tryLock()에 시간을 설정하면,

지정된 시간 동안 Lock을 얻지 못한 경우 다시 작업을 시도할 것인지 포기할 것인지 결정할 수 있습니다.

 

//기본적인 사용법
class TestClass{
	private ReentrantLock lock = new ReentrantLock(); // Lock 생성
    
    public testMethod(){
    	lock.lock();
        try{
        	//Critical Section
        } finally {
        	lock.unlock();
        }
    }
}

 

 

 

ReentrantLock을 사용한 예시

import java.util.concurrent.locks.ReentrantLock;

public class Counter {
    private int count = 0;
    private ReentrantLock lock = new ReentrantLock();

    public void increment() {
        lock.lock(); // 락 획득
        try {
            count++;
        } finally {
            lock.unlock(); // 락 해제
        }
    }

    public int getCount() {
        lock.lock(); // 락 획득
        try {
            return count;
        } finally {
            lock.unlock(); // 락 해제
        }
    }
}

위 코드에서는 ReentrantLock 객체를 생성하고, increment() 메소드와 getCount() 메소드에서 락을 획득하고 해제하는 코드가 포함되어 있습니다. increment() 메소드에서는 count 변수를 증가시키고, getCount() 메소드에서는 count 변수의 값을 반환합니다.

 

ReentrantLock은 try-finally 블록을 사용하여 락을 해제하는 것이 좋습니다. 이를 통해 락이 예외가 발생하더라도 안전하게 해제됩니다. 또한, 락을 재진입할 수 있기 때문에 같은 스레드에서 여러 번 락을 획득할 수 있습니다. 이는 synchronized 블록과는 다르게 락의 소유권을 가지고 있는 스레드가 다른 스레드에서도 락을 획득할 수 있도록 허용하므로 유용합니다.

 

 

정리출처: 

https://www.crocus.co.kr/1558

 

ReentrantLock이란?

ReentrantLock란? 동기화된 메소드와 문장을 사용하여 액세스 할 수 있는 암시적인 모니터 잠금 기능과 같은 기본적인 동작과 의미를 가진 Reentrant 상호 간의 상호 배제된 상호 배제 잠금 기능을 의

www.crocus.co.kr

https://jhkimmm.tistory.com/36

 

[JAVA] 자바 쓰레드 동기화(2) - ReentrantLock과 Condition

[JAVA] 자바 쓰레드 동기화(1) - synchronized, wait()/notify() 멀티 쓰레드 환경에서 Critical section 문제를 해결하기 위해서는 Critical section에 대해 쓰레드를 동기화 해야합니다. 자바에서는 아래 두 가지 방

jhkimmm.tistory.com

 

728x90