동시성
과 병렬성
의 차이는 무엇일까?동시성
: 동시에 실행되는 것처럼 보이는 것 (논리적 개념)병렬성
: 실제로 동시에 여러 작업이 수행되는 것 (물리적 개념) 배타적 실행
: A 스레드에 의해 객체가 수정되는 동안 B 스레드가 일관성 없는 상태로 객체를 보는 것을 방지하는 것이다.락
을 사용하여 공유하는 자원은 현재 실행 중인 스레드만 접근하게 하는 것이다.가시성
을 바탕으로 안정적인 통신 보장Thread.stop()
메서드는 안전하지 않아 사용되지 않는다.잘못된 예시
// 영원히 수행된다
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;
}}
// 원래 코드
while (!stopRequested)
i++;
// 최적화한 코드
if (!stopRequested)
while (true)
i++;
올바른 예시
public class SyncStopThread {
private static boolean stopRequested;
private static synchronized void requestStop(){
stopRequested = true;
}
private static synchronized boolean stopRequested(){
return 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);
requestStop();
}}
stopRequested
을 volatile로 선언하면 synchronized를 생략할 수 있다.가시성
을 보장하는 키워드이다. (동기화는 보장되지 않는다.)private static volatile int nextSerialNumber = 0;
public static int generateSerialNumber() {
return nextSerialNumber++;
}
원자성
을 지원한다.private static volatile int nextSerialNumber = 0;
public static int generateSerialNumber() {
return nextSerialNumber++;
}
public class AtomicLong extends Number implements java.io.Serializable {
private volatile long value;
}
가시성
을 보장한다.getAndIncresement
함수의 내부 구현이다.CAS
: Compare And Swap을 통해 가능하게 한다. @HotSpotIntrinsicCandidate
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!weakCompareAndSetInt(o, offset, v, v + delta));
return v;
}
weakCompareAndSetInt
은 unSafe class의 compareAndSetInt
를 호출한다.weakCompareAndSetInt
을 반복 수행하여 값을 변경한 뒤 getIntVolatile
으로 값을 조회해 반환하는 것이다.| 참고
long
, double
을 제외한 변수를 읽고 쓰는 동작은 atomic
하다. 수정이 완전히 반영된
값을 얻는다고 보장하지만, 보이는지
는 보장하지 않기 때문에 동기화가 필요하다. // AtomicLong
public final void set(long newValue) {
// See JDK-8180620: Clarify VarHandle mixed-access subtleties
U.putLongVolatile(this, VALUE, newValue);
}
// AtomicInteger
public final void set(int newValue) {
value = newValue;
}