동시성 이슈
스레드는 cpu 작업의 한단위이다. 멀티스레드 방식은 멀티태스킹을 하는 방식 중, 한 코어에서 여러 스레드를 이용해서 번갈아 작업을 처리하는 방식이다.
멀티 스레드를 이용하면 공유하는 영역이 많아 프로세스방식보다 context switcing(작업전환) 오버헤드가 작아, 메모리 리소스가 상대적으로 적다는 장점이 있다.
(프로세스는 운영체제로부터 자원을 할당받은 작업의 단위이며, 스레드는 프로세스가 할당받은 자원을 이용하는 실행 흐름의 단위이다.)
하지만 자원을 공유해서 단점도 존재한다.
그게 바로, 동시성(concurrency) 이슈이다.
여러 스레드가 동시에 하나의 자원을 공유하고 있기 때문에 같은 자원을 두고 경쟁상태(raceCondition) 같은 문제가 발생하는 것이다.
HashMap vs ConcurrentHashMap
HashMap은 내부에서 동기화를 제공하지 않기 때문에 단일 스레드(single-threaded) 애플리케이션에 적합하다.
ConcurrentHashMap은 내부에서 동기화(synchronization)를 제공하여 여러 개의 스레드가 동시에 맵에 접근하고 수정할 수 있도록 하기 때문에 동시 다중 스레드(concurrent multi-threaded) 애플리케이션에 적합하다.
Java의 동시성 문제
Java는 멀티 스레드 프로그래밍이 가능한 언어입니다. JVM은 보통 어떤 서버(기기) 상에서 실행되고 있는 프로세스를 말합니다. 이러한 JVM은 최소 한 개(main 스레드) 이상 여러 스레드를 가질 수 있습니다.
그렇다면 많은 스레드가 공유한 자원에 동시에 접근하게 되면 어떤 문제가 발생할 수 있을까요?
public class Main {
public static void main(String[] args) {
Counter counter = new Counter();
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
counter.increment();
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
counter.increment();
}
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final Counter Value: " + counter.getCount());
}
public static class Counter {
private int count = 0;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
}
위 코드만 간단하게 본다면, 정상적으로 동작했을 경우 count의 수는 20000이 되어야 합니다. 실제 코드를 실행하고 결과를 확인 하면 아래와 같습니다.
Final Counter Value: 16950
매 실행마다 다른 결과값을 받아 볼 수 있습니다. 그 이유는 Java의 특성인 멀티 스레드 프로그래밍에 있습니다. 두 스레드가 하나의 자원에 동시에 접근하며, 동기화 되지 않은 데이터의 결과입니다.
[동시성 이슈] HashMap vs ConcurrentHashMap
[Java] 멀티 스레드환경의 동시성 이슈 그리고 해결방법
[Java] ConcurrentHashMap 이란 무엇일까?
완전히 정복하는 프로세스 vs 스레드 개념
동시성에 대한 해결방법을 알아보자