728x90
반응형

synchronized 키워드 (Java 동기화)

  • Java에서 synchronized 키워드는 멀티스레드 환경에서 공유 자원에 대한 동기화(Synchronization) 를 제공하여 데이터 일관성 유지경쟁 상태(Race Condition) 방지 에 사용됩니다.


1. synchronized 사용 방법

(1) 메서드 동기화

메서드 전체를 동기화할 때 사용합니다.

  • 인스턴스 메서드 → 해당 객체(this)에 대한 잠금(Lock) 을 가짐
  • 정적 메서드 → 클래스(Class)에 대한 잠금(Lock) 을 가짐

① 인스턴스 메서드 동기화

java

class SharedResource {
    public synchronized void syncMethod() {
        System.out.println(Thread.currentThread().getName() + " 실행 중");
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
        System.out.println(Thread.currentThread().getName() + " 종료");
    }
}
  • 같은 객체에서 syncMethod() 를 여러 스레드가 호출하면, 한 번에 하나의 스레드만 실행됨.

② 정적 메서드 동기화

java

class SharedResource {
    public static synchronized void staticSyncMethod() {
        System.out.println(Thread.currentThread().getName() + " 실행 중");
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
        System.out.println(Thread.currentThread().getName() + " 종료");
    }
}
  • 정적 메서드는 클래스 레벨(Class-wide)에서 동기화되므로, 같은 클래스 내의 모든 객체에 영향을 줌.


(2) 블록 동기화 (synchronized 블록)

메서드 전체가 아니라 특정 코드 블록만 동기화하여 불필요한 성능 저하 방지.

java

class SharedResource {
    public void syncBlock() {
        System.out.println(Thread.currentThread().getName() + " 실행 중 (동기화 X)");

        synchronized (this) { // 특정 객체(this)만 동기화
            System.out.println(Thread.currentThread().getName() + " 동기화 블록 진입");
            try { Thread.sleep(1000); } catch (InterruptedException e) {}
            System.out.println(Thread.currentThread().getName() + " 동기화 블록 종료");
        }

        System.out.println(Thread.currentThread().getName() + " 실행 종료 (동기화 X)");
    }
}
  • synchronized (this)는 현재 객체에 대한 락(Lock) 을 사용.

다른 객체를 Lock으로 설정

java

class SharedResource {
    private final Object lock = new Object();

    public void syncBlock() {
        synchronized (lock) { // 특정 객체 lock을 동기화 대상으로 설정
            System.out.println(Thread.currentThread().getName() + " 실행 중");
            try { Thread.sleep(1000); } catch (InterruptedException e) {}
            System.out.println(Thread.currentThread().getName() + " 종료");
        }
    }
}
  • 커스텀 락 객체(lock)을 사용하면 더 세밀한 동기화가 가능.


2. synchronized의 문제점과 개선 방법

(1) 단점

  • 성능 저하: synchronized는 락을 얻기 위해 대기하는 시간이 필요함.
  • 데드락(Deadlock) 위험: 여러 개의 synchronized 블록이 서로 다른 객체를 잠금하면 교착 상태가 발생 가능.

(2) 개선 방법

ReentrantLock 사용 (명시적 락)

  • synchronized보다 유연한 제어 가능.
  • tryLock()을 활용하여 데드락 방지.

java

import java.util.concurrent.locks.ReentrantLock;

class SharedResource {
    private final ReentrantLock lock = new ReentrantLock();

    public void safeMethod() {
        if (lock.tryLock()) {  // 락 획득 시도 (데드락 방지)
            try {
                System.out.println(Thread.currentThread().getName() + " 실행 중");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock(); // 락 해제
            }
        } else {
            System.out.println(Thread.currentThread().getName() + "은 락을 얻지 못함");
        }
    }
}
  • tryLock()은 즉시 락을 얻을 수 없으면 대기하지 않고 바로 반환하여 데드락을 방지.



3. synchronized 정리

사용 방식 설명
synchronized method 전체 메서드를 동기화 (객체 또는 클래스 락)
synchronized block 특정 코드 블록만 동기화 (더 효율적)
ReentrantLock 더 유연한 동기화 (tryLock 가능)

  • 🚀 synchronized는 간단하지만, 성능을 고려하면 ReentrantLock 같은 대안도 필요!
728x90
반응형

+ Recent posts