카샤의 만개시기

Java의 동기화 (atomic, volatile, synchronized) 본문

Java/POJO

Java의 동기화 (atomic, volatile, synchronized)

SKaSha 2019. 7. 3. 15:14

싱글 스레드와 달리 멀티 스레드 프로그래밍 방식에서는 고려해야 할 것이 많다.
그 원인은 경쟁 상태(race condition)와 변수의 가시성(visibility)에서 온다.

경쟁 상태

여러 스레드 같은 시점 변수를 읽는 상태

변수의 가시성

변수들이 사용될 수 있는 영역의 범위로써 변수의 값이 CPU의 캐시 메모리에 저장되어 있는지, 메인메모리에 저장되어 있는지 알 수 없다는 데에서 온다. 동일한 변수를 동시에 접근 했을때 어떤 스레드는 캐시 메모리에 접근 할수도 있고 어떤 스레드는 메인 메모리에 접근할수도 있기 때문이다.

Atomic

java.concurrent.atomic 패키지를 보면 원자적 연산을 수행 할 수 있는 클래스들이 있다.
Atomic 클래스들은 CAS(compare-and-swap) 기반으로 되어 있어 스레드에 안전하다.
CAS방식은 자신이 읽었던 변수의 값을 기억하고 있다가 변경을 완료하기 직전에 읽었던 변수의 값이 그대로인지 확인하고 아니라면 실행을 무산시키는 방식이다.

volatile

이 키워드를 사용하면 변수를 CPU의 캐시 메모리에 저장하지 않고 반드시 메인 메모리에 저장하기 때문에 변수의 가시성 문제를 해결 할 수 있습니다. 하지만 항상 동시성 문제를 해결하는 것이 아니고, 하나의 스레드만 write를 하고 나머지의 스레드들은 read하는 상황에서만 최신의 값을 보장해 줍니다.
여러 스레드를 사용해야 하는 상황이라면 synchronized를 이용해야 합니다.

synchronized

가장 기본적으로 사용되는 동기화 방법이며 너무 잘게 쪼개거나 사용을 남발하게 되면 성능상에 문제가 생깁니다.

함수에 사용하는 경우

public synchronized void fuc() {
     // code
}

객체 변수에 사용하는 경우

private Object object = new Object();
public void fuc() {
    synchronized(object) {
        // code
    }
}
Comments