synchronized 키워드는 Java에서 멀티스레딩 지원과 함께 등장하여 서로 다른 스레드가 코드 블록이나 메서드에 독점적으로 접근할 수 있도록 보장합니다. 이는 역사적으로 race condition 및 데이터 불일치와 같은 전통적인 문제에 대한 Java의 응답입니다. 이 문제는 서로 다른 스레드에서 공유 데이터를 동시에 접근할 때 발생합니다.
문제는 멀티스레딩 작업 시 "원자성"을 보장하고 객체 상태의 상충 변경을 방지하는 것입니다. 잘못된 synchronized 사용은 교착 상태(deadlock), 성능 저하 또는 잘못된 모니터 객체 선택으로 인한 동기화 부족으로 이어질 수 있습니다.
해결책은 메서드나 코드 블록에서 synchronized 키워드를 사용하여 단일 스레드만 동시에 이 지역을 실행할 수 있도록 보장하는 것입니다. 동기화 객체를 신중하게 선택하고 긴 크리티컬 섹션을 피하며, 더 복잡한 작업을 위해 java.util.concurrent 패키지의 특수 클래스를 사용하는 것이 필요합니다.
코드 예시:
public class Counter { private int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } } // 별도의 객체에서 코드의 일부만 동기화: private final Object lock = new Object(); public void complexIncrement() { synchronized (lock) { // 크리티컬 섹션 count++; } }
핵심 특징:
synchronized 메서드와 synchronized 블록의 차이점은 무엇인가요?
synchronized 메서드는 객체(또는 정적 메서드일 경우 클래스)의 "모니터"를 차단하며, synchronized 블록은 명시적으로 모니터 객체를 지정할 수 있어 더 큰 유연성을 제공합니다.
하나의 객체에서 서로 다른 메서드를 동기화하면 어떻게 되나요?
두 메서드가 모두 synchronized로 표시되면 (정적이 아닌 경우) 두 메서드는 자신 객체(this)를 모니터로 사용합니다. 하나의 스레드가 두 메서드 중 하나에 들어가면 다른 스레드는 들어갈 수 없습니다.
정적 메서드와 일반 메서드를 동기화할 수 있나요? 그들끼리 어떻게 해제되나요?
정적 메서드는 클래스 자체의 모니터(클래스 객체)를 사용하고, 일반 메서드는 인스턴스 객체를 사용합니다. 따라서 정적 synchronized 메서드와 일반 synchronized 메서드는 서로를 차단하지 않습니다.
개발자가 다른 객체의 메서드를 동기화하면서 모든 경우에 동일한 String을 모니터로 사용합니다. 결과적으로 속도가 느려지고 풀에서 문자열을 재사용하여 "임의의" 교착 상태가 발생합니다.
장점:
단점:
클래스 내부에서만 생성되는 개인 최종 객체(private final Object lock)에 따라 동기화하고, 크리티컬 섹션의 시간으로 최소화합니다.
장점:
단점: