일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- infcon 2024
- Spring multimodule
- jwttoken
- DesignPattern
- @FeignClient
- 디자인패턴
- KPT회고
- 코딩테스트 준비
- JavaScript
- spring batch 5.0
- 99클럽
- 빈 충돌
- 단기개발자코스
- 개발자 취업
- 개발자부트캠프추천
- 파이썬
- 디자인 패턴
- Python
- 커스텀 헤더
- jwt
- 취업리부트코스
- 전략패턴 #StrategyPattern #디자인패턴
- 구글 OAuth login
- 항해99
- 빈 조회 2개 이상
- 인프콘 2024
- TiL
- 1주일회고
- 프로그래머스
- 프로그래머스 이중우선순위큐
- Today
- Total
m1ndy5's coding blog
Ditto 프로젝트 동시성 문제 해결하기 4편 - Java에서 동시성을 제어하는 방법 (Synchronized, ConcurrentHashMap) 본문
Ditto 프로젝트 동시성 문제 해결하기 4편 - Java에서 동시성을 제어하는 방법 (Synchronized, ConcurrentHashMap)
정민됴 2024. 3. 25. 01:06파면 팔수록 굉장히 많은 것들이 나오는 동시성..!! 재밌구나 하하
이번에는 Java에서 동시성 이슈를 제어하는 방법에 대해 정리해보자.
1. Synchronized 키워드 : Synchronized 키워드를 사용하여 특정 메서드 또는 코드 블록을 한 번에 하나의 스레드만 실행하도록 한다.
public class SynchronizedExample {
private int counter = 0;
// synchronized 키워드를 사용하여 메서드를 동기화
public synchronized void increment() {
counter++;
}
public int getCounter() {
return counter;
}
public static void main(String[] args) {
SynchronizedExample example = new SynchronizedExample();
// 여러 스레드가 동시에 increment 메서드를 호출하여 counter를 증가시킴
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 예상 결과: 2000 (하지만 동시성 문제가 없으면 그렇지 않을 수도 있음)
System.out.println("Counter: " + example.getCounter());
}
}
위 예제에서는 increment() 메서드에 synchronized 키워드를 사용하여 여러 스레드가 동시에 이 메서드를 호출할 때 동기화를 보장한다.
단점 : synchronized 키워드는 실행 중인 스레드가 잠금을 획득하고 해제할 때까지 다른 스레드가 대기해야 함으로 성능 저하를 초래할 수 있다. 또한 단일 락을 사용하여 동시성을 제어하기 때문에, 많은 스레드가 동시에 실행될 때 성능이 저하될 수 있다.
2. 스레드 안전한 컬렉션 : Java는 동시성 컬렉션인 ConcurrentHashMap, ConcurrentLinkedQueue 등을 제공한다. 이런 컬렉션은 여러 스레드에서 안정하게 사용될 수 있다.
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentHashMapExample {
public static void main(String[] args) {
// ConcurrentHashMap 생성
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 여러 스레드가 동시에 맵에 접근하여 값을 추가
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
// putIfAbsent 메서드는 키가 없을 때만 값을 추가
map.putIfAbsent("Key", 0);
// 키 "Key"에 해당하는 값을 증가시킴
map.compute("Key", (key, value) -> value + 1);
}
};
// 여러 스레드 생성 및 실행
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
thread1.start();
thread2.start();
// 스레드 종료 대기
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 결과 출력
System.out.println("Value for key 'Key': " + map.get("Key"));
}
}
위 예시는 ConcurrentHashMap을 사용하여 여러 스레드가 동시에 맵에 접근하고 값을 증가시키는 상황이다.
putIfAbsent() 메서드를 사용하여 특정 키가 맵에 존재하지 않을 때만 값을 추가하고 compute() 메서드를 사용하여 해당 키의 값을 증가시켰다. 이러한 작업은 여러 스레드가 안전하게 동시에 실행될 수 있도록 동시성 기능을 이용하였다.
단점 : ConcurrentHashMap은 동시성 보장을 위해 내부적으로 많은 추가 메모리를 사용한다. 또한 맵을 반복하고 있는 동안 다른 스레드가 맵에 변경을 가할 경우, 반복 중인 스레드에게 이 변경 사항이 반영되지 않을 수 있다. 또한 서버가 종료될 때 ConcurrentHashMap에 있는 내용도 모두 손실되기 때문에 주기적으로 다른 저장 장치에 저장하는 작업도 필요하다.
결론
synchronized 키워드와 ConcurrentHashMap을 사용하여 동시성을 제어할 수 있다.
synchronized같은 경우 한 스레드가 잠금을 획들하고 해제할 때까지 다른 스레드는 대기해야하기 때문에 성능 저하가 발생한다.
ConcurrentHashMap 같은 경우 여러 스레드가 동시에 읽기 및 쓰기 작업을 수행할 수 있어 동시성을 보장하지만 반복 중에 일관성이 보장되지 않을 수 있고 추가 메모리를 많이 사용해야한다. 또한 서버가 종료될 때 저장된 내용이 날라가니 추가적으로 저장 장치에 저장하는 작업이 필요하다.
'Toy Projects > Ditto - Discuss Today's Topic' 카테고리의 다른 글
Ditto 프로젝트 docker-compose 2편 - docker-compose란? (0) | 2024.04.24 |
---|---|
Ditto 프로젝트 동시성 문제 해결하기 3편 - 낙관적 락 Version, Select for Update (0) | 2024.03.13 |
Ditto 프로젝트 docker-compose 1편 - Docker란, Docker Cache, Docker Network (0) | 2024.03.07 |
Ditto 프로젝트 종목 불러오기 with batchUpdate (1) | 2024.02.29 |
Ditto 프로젝트 N+1 문제 2편 - N+1 문제 해결과 외래키 (2) | 2024.02.27 |