[Java] 자바 synchronized (멀티스레드/동기화)
자바에서 synchronized 키워드는 멀티스레드 환경에서 동기화를 위해 사용되는 중요한 기능입니다. 이 포스팅에서는 synchronized의 개념, 사용 방법, 장단점, 그리고 예시를 통해 상세하게 설명하겠습니다.
1. synchronized의 개념
동기화란?
동기화는 여러 스레드가 동시에 접근할 수 있는 공유 자원에 대해 한 번에 하나의 스레드만 접근할 수 있도록 제어하는 것을 의미합니다. 이를 통해 데이터의 일관성을 유지하고, 경쟁 상태(race condition)를 방지할 수 있습니다.
synchronized 키워드
자바에서 synchronized 키워드는 메서드나 코드 블록 앞에 사용되어 해당 영역을 임계 영역(critical section)으로 지정합니다. 임계 영역은 한 번에 하나의 스레드만 접근할 수 있는 코드 영역을 의미합니다.
2. synchronized의 사용 방법
메서드 동기화
메서드 선언부에 synchronized 키워드를 붙여서 해당 메서드가 한 번에 하나의 스레드만 접근할 수 있도록 합니다.
public synchronized void method() {
// 임계 영역
}
블록 동기화
특정 코드 블록을 동기화할 수 있습니다. 이 경우, synchronized 블록 내의 코드만 동기화됩니다.
public void method() {
synchronized(this) {
// 임계 영역
}
}
정적 메서드 동기화
정적 메서드에 synchronized 키워드를 붙이면 클래스 레벨에서 동기화가 이루어집니다.
public static synchronized void staticMethod() {
// 임계 영역
}
정적 블록 동기화
정적 블록을 동기화할 때는 클래스 객체를 사용합니다.
public static void staticMethod() {
synchronized(MyClass.class) {
// 임계 영역
}
}
3. synchronized의 동작 원리
모니터 락(Monitor Lock)
synchronized 키워드는 객체의 모니터 락을 사용합니다. 스레드가 synchronized 메서드나 블록에 진입하면 해당 객체의 모니터 락을 획득하고, 메서드나 블록을 빠져나올 때 락을 해제합니다
예시
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
위 예시에서 increment와 getCount 메서드는 동기화되어 있어, 여러 스레드가 동시에 접근하더라도 count 변수의 일관성이 유지됩니다.
4. synchronized의 장단점
장점
- 데이터 일관성 유지: 여러 스레드가 동시에 접근할 때 데이터의 일관성을 유지할 수 있습니다.
- 간단한 사용법: synchronized 키워드를 사용하여 쉽게 동기화를 구현할 수 있습니다.
단점
- 성능 저하: 동기화로 인해 스레드가 대기 상태에 들어가면 성능이 저하될 수 있습니다.
- 교착 상태(Deadlock): 잘못된 동기화로 인해 교착 상태가 발생할 수 있습니다.
- 무한 대기(Blocked 상태): 스레드가 락을 획득하지 못할 경우 무한 대기 상태에 빠질 수 있습니다
5. 고급 예시
생산자-소비자 문제
생산자-소비자 문제는 멀티스레드 환경에서 자주 등장하는 문제로, synchronized를 사용하여 해결할 수 있습니다.
import java.util.LinkedList;
import java.util.Queue;
public class ProducerConsumer {
private final Queue<Integer> queue = new LinkedList<>();
private final int MAX_SIZE = 5;
public void produce() throws InterruptedException {
int value = 0;
while (true) {
synchronized (this) {
while (queue.size() == MAX_SIZE) {
wait();
}
queue.add(value);
System.out.println("Produced: " + value);
value++;
notify();
Thread.sleep(1000);
}
}
}
public void consume() throws InterruptedException {
while (true) {
synchronized (this) {
while (queue.isEmpty()) {
wait();
}
int value = queue.poll();
System.out.println("Consumed: " + value);
notify();
}
public static void main(String[] args) {
ProducerConsumer pc = new ProducerConsumer();
Thread producerThread = new Thread(() -> {
try {
pc.produce();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
Thread consumerThread = new Thread(() -> {
try {
pc.consume();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
producerThread.start();
consumerThread.start();
}
}
위 예시에서 produce와 consume 메서드는 synchronized 블록을 사용하여 동기화됩니다. wait와 notify 메서드를 사용하여 생산자와 소비자 스레드 간의 협력을 구현합니다.
synchronized 키워드는 자바에서 멀티스레드 환경에서 동기화를 구현하는 데 매우 유용한 도구입니다. 이를 통해 데이터의 일관성을 유지하고, 경쟁 상태를 방지할 수 있습니다. 그러나 성능 저하와 교착 상태와 같은 단점도 있으므로, 상황에 맞게 적절히 사용해야 합니다.
'낙서장[1] > 91. Java' 카테고리의 다른 글
[Java] 우분투22.04에서 자바 한글 출력 (1) | 2025.03.23 |
---|---|
[Java] 자바에서 오버로드와 오버라이드 (0) | 2025.02.02 |
[Java] 자바기초, (멤버, 생성자 등) (0) | 2025.02.02 |
[Java] 자바 접근 지정자 이해하기 (0) | 2025.02.02 |
[Java] 자바로 개인정보 숨김 처리하기 (0) | 2025.01.30 |