본문 바로가기
Language/JAVA

[자바 멀티스레딩] 자바 동시성 고급: ReentrantLock 사용법

by YoonJong 2025. 3. 30.
728x90
반응형

ReentrantLock 은 syncronized 보다 유연한 동기화 도구이다.

세밀한 제어가 간으하며, 인터럽트 처리를 지원한다. 또한 락 상태 확인이 가능하다.

 

ReentrantLock

- 같은 스레드가 락을 여러 번 획득 가능하며, 획득 횟수만큼 해제 필요

- ReentrantLock(true) 로 공정모드 설정. 대기 순서 보장(성능 저하 가능)

- Condition 객체로 특정 조건 기다림

- tryLock(long, TimeUnit) 으로 락 획득 시간 제한 가능 

 

- 세밀한 제어 가능하며 인터럽트 처리를 지원

- 코드 복잡도가 증가하며, unlock() 메서드 누락 시 데드락 위험

 

public class LockCounter {

    private int count = 0;
    private final ReentrantLock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count ++;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        return count;
    }

    public static void main(String[] args) throws InterruptedException {
        LockCounter counter = new LockCounter();
        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                counter.increment();
            }
        };

        Thread t1 = new Thread(task);
        Thread t2 = new Thread(task);

        t1.start();
        t2.start();
        t1.join();
        t2.join();

        System.out.println("Final count: " + counter.getCount());
    }
}

 

tryLock() : 락을 즉시 획득 시도

public void tryIncrement() {
    if (lock.tryLock()) {
        try {
            count++;
            System.out.println("증가 " + Thread.currentThread().getName());
        } finally {
            lock.unlock();
        }
    } else {
        // 락 획득 실패 시 대체 작업 가능
        System.out.println("락 획득 시도 실패 " + Thread.currentThread().getName());
    }
}

 

tryLock(long, TimeUnit) : 타임아웃 설정 가능

public void timedIncrement() throws InterruptedException {
    if (lock.tryLock(1, TimeUnit.SECONDS)) {
        try {
            count++;
            System.out.println("Incremented after waiting");
        } finally {
            lock.unlock();
        }
    } else {
        System.out.println("Timeout: Lock not acquired");
    }
}

 

Condition : 조건 대기

public class ConditionExample {
    private int count = 0;
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();

    public void incrementAndWait() throws InterruptedException {
        lock.lock();
        try {
            count++;
            System.out.println("Count: " + count);
            condition.await(); // 락 해제하고 대기
            System.out.println("락 해제, 계속 진행");
        } finally {
            lock.unlock();
        }
    }

    public void signal() {
        lock.lock();
        try {
            condition.signal(); // 대기 중인 스레드 깨움
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ConditionExample example = new ConditionExample();
        Thread t1 = new Thread(() -> {
            try {
                example.incrementAndWait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        t1.start();
        System.out.println("Thread.sleep 1초 발생");
        Thread.sleep(1000);
        example.signal();
        t1.join();
    }
}

//결과값 
Thread.sleep 1초 발생
Count: 1
락 해제, 계속 진행
728x90
반응형

댓글