상황 가정 + 실패 예시
아래 예시는 좋지 않은 예시이다.
만약 두개의 스레드 각 10000번 돌려 두 스레드 값을 더하여 20000이 나오게 하는 프로그램을 작성한다고 가정하자.
public class SyncTest1BadMain {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Runnable task = new Runnable(){
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
counter.increment();
}
}
};
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("결과 : " + counter.getCount());
}
static class Counter {
private int count = 0;
public void increment() {
count += 1;
}
public int getCount() {
return count;
}
}
}
위 예시 결과는 아래와 같다. (운이 좋아 20000이 나올 수도 있긴 함)
문제점 + 해결 로직
최초에 스레드 두개가 동시에 실행 되면, 두 스레드가 공유 자원의 값을 0으로 읽어버린다.
코드의 흐름이 count 값을 읽어서 계산하는 부분 + 결과를 count 변수에 넣는 두가지 로직으로 구분이 되는데, 서로 공유자원의 값을 계속 덮어 쓰게 된다.
이때 각 스레드가 서로 다른 값을 읽으며 결과 값을 누적해간다면 결과 값을 적절히 얻어올 수 없다. -> 이럴 때 synchronized 키워드가 필요하다
public class SyncTest1Main {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter(); // 공유 자원
Runnable task = new Runnable(){
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
counter.increment();
}
}
};
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("결과 : " + counter.getCount());
}
static class Counter {
private int count = 0;
public synchronized void increment() {
count += 1;
}
public synchronized int getCount() {
return count;
}
}
}
적절히 싱크로나이즈를 사용한 덕분에 몇번을 돌려도 20000이 나오는 것을 확인 할 수 있었다.
'Java > Java' 카테고리의 다른 글
[Java] 까먹지 말아야 할 Java 스레드 생명 주기 및 상태 전이 (0) | 2025.03.08 |
---|---|
[Java] 까먹지 말아야 할 Java 메모리 구조 (1) | 2025.03.04 |
[Java] 채팅 프로그램 소켓 연결 구현 1 - 1 대 1 통신을 해보자 (0) | 2025.02.09 |
[Java] 두줄로 이해하는 객체 직렬화, 역직렬화 (1) | 2025.01.28 |
[Java] 예외처리 - 부모 자식 관계 (1) | 2025.01.02 |