
- 한 cpu에서 동시에 여러 작업을 하는 것처럼 보이게 만드는 것
- 동시에 실행되는 것 같이 보이는 것
- 싱글 코어에서 멀티 쓰레드를 동작 시키는 방식
- 한 번에 많은 것을 처리
- 논리적인 개념
- concurrently ⭕ simultaneously ❌
- concurrently : N 개의 task 의 실행 시간이 타임라인 상에서 겹칠 수 있다
- simultaneously : 우리가 일반적으로 사용하는 ’동시에’ 라는 단어의 맥락
context switching이 일어나면서 번갈아서 실행된다
- 다중 cpu에서 작업이 병렬적으로 실행된다. 하나의 cpu당 코드가 실행된다
- 실제로 동시에 여러 작업이 처리되는 것
- 멀티 코어에서 멀티 쓰레드를 동작시키는 방식
- 한 번에 많은 일을 처리
- 물리적인 개념
- concurrently ⭕ simultaneously ⭕
데이터 병렬성(Data parallelism)과작업 병렬성(Task parallelism)으로 구분된다
병렬 스트림이 데이터 병렬성을 구현한 것이다웹 서버는 각각의 브라우저에서 요청한 내용을 개별 쓰레드에서 병렬 처리한다
동시성 > 병렬성
CPU가 작업처리시에,
RAM에 있는 데이터 일부를 고속 저장 장치CPU Cache Memory로 읽어들인다.CPU가 작업을 마치고 데이터를RAM에 저장할 때,
CPU Cache Memory에서RAM으로 쓰기 작업을 수행한다
- 👉 이 말은
CPU에서CPU Cache Memory로 쓰기 작업을 수행하여도,
RAM으로 쓰기작업을 바로 수행할 필요가 없다는 의미
CPU와RAM중간에 위치한CPU Cache Memory의 병렬성으로 두 가지 문제가 발생한다
👉가시성(visibility) 문제&동시 접근 문제
하나의 스레드에서 공유 자원(변수, 객체)을 수정한 결과가 다른 스레드에게 보이지 않을 수 있다
public class StopThread {
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(() -> {
int i = 0;
while (!stopRequested)
i++;
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
- 메인 스레드가 1초 sleep 후
stopRequested = true;을 실행하여backgroundThread스레드가 반복문을 빠져나올것 처럼 보이지만 아니다.

- CPU1에서 수행된 스레드 =
backgroundThread
CPU2에서 수행된 스레드 =mainThread일때,
- ✍
mainThread에서
CPU Cache Memory 2와RAM에 공유 변수인stopRequested를true로 쓰기 작업을 완료했지만- ✍
backgroundThread에서
CPU Cache Memory 1에서 읽은 여전히 업데이트 되지 않은stopRequested값을 사용한다.
👉mainThread가 수정한 값을backgroundThread가 언제쯤에나 보게 될지 보증할 수 없다 (가시성 문제)
volatile로 선언된 변수에 대해서는CPU Cache Memory를 거치지 않고RAM으로 직접 읽고 쓰는 작업을 수행하게 된다.
👉 stopRequested 변수를 volatile로 선언하면private volatile boolean stopRequested;
변수 값 불일치 문제를 해결 할 수 있다.

- Multi Thread 환경에서
- 하나의 Thread만 read & write하고 나머지 Thread가 read하는 상황에서 적합하다
- 여러 Thread가 write하는 상황에서는 적합하지 않는다
👉 여러 Thread가 write하는 상황에서는synchronized를 통해 변수 read & write의 원자성(atomic)을 보장해야한다CPU Cache보다Main Memory가 비용이 더 크기 때문에 변수 값 일치을 보장해야 하는 경우에만volatile사용하는 것이 좋다
여러 스레드에서 공유 자원에 동시에 접근하여 변경했을 때 문제가 발생할 수 있다
public class IncremantThread {
private static int count;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(() -> {
for (int i = 0; i < 10000000; ++i) {
++count;
}
});
backgroundThread.start();
for (int i = 0; i < 10000000; ++i) {
++count;
}
TimeUnit.SECONDS.sleep(5);
System.out.println(count);
}
}
- 5초후에 결과 값
count가20000000으로 출력되지 않는다

- CPU1에서 수행된 스레드 =
backgroundThread
CPU2에서 수행된 스레드 =mainThread일때,
count변수의 값이2라고 가정해보자.
- ✍
mainThread와backgroundThread에서 동시에
CPU Cache Memory로count값을 읽어오게 된다.- 두 스레드에서
count값을 1 증가시켜3이란 값을 각각의CPU Cache Memory에 저장하게 된다.- 👉그 후, 두
CPU Cache Memory에 있는count값이RAM에 저장이 된다면
3이란 값이 연속으로 중복 저장된다 (동시 접근 문제)
lock을 이용하여 스레드가 공유 자원에 접근시 하나의 스레드만 공유 자원에 접근할 수 있도록 한다
public class IncremantThread {
private static int count;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(() -> {
for (int i = 0; i < 10000000; ++i) {
increment();
}
});
backgroundThread.start();
for (int i = 0; i < 10000000; ++i) {
increment();
}
TimeUnit.SECONDS.sleep(5);
System.out.println(count);
}
// synchronized 키워드
private static synchronized void increment() {
++count;
}
}
synchrozied는 가시성의 문제도 해결한다.volatile은 동시 접근의 문제를 해결하지 못 한다.