Java ‐ 공유 중인 가변 데이터는 동기화해 사용하라[Effective Java Item 78] - thought-corner/Backend-PlayGround GitHub Wiki
동기화
- 프로세스나 쓰레드들이 서로 알고 있는 공유중인 데이터가 같은 것을 의미한다.
- 멀티 코어 프로세서의 힘을 제대로 활용하려면 멀티쓰레드 프로그래밍을 해야하며 여러 쓰레드가 동시에 접근하는 만큼 동기화에 주의를 기울여야 한다.
- 동기화는 다음과 같이 2가지 기능을 제공한다.
- 배타적 실행 : 현재 사용중인 쓰레드만 접근이 가능하고, 다른 쓰레드가 접근하지 못하게 한다.
- 쓰레드 사이 안정적인 통신 : 어떤 쓰레드가 변경한 데이터를 다른 쓰레드에서 읽을 수 있게 한다.
Java synchronized 키워드
- Java에서는
synchronized 키워드를 통해 메서드나 블록을 한 번에 한 쓰레드씩 수행하도록 보장함으로써 동기화를 지원하고 있다.
- 언어 명세상
long, double 외의 변수를 읽고 쓰는 동작은 원자적이다. 여러 쓰레드가 같은 변수를 동기화 없이 수정하는 중이라도 항상 어떤 쓰레드가 정상적으로 저장한 값을 온전히 읽어옴을 보장할 수 있다.
- 그러나 자바는 한 쓰레드가 저장한 값이 다른 쓰레드에게 '보이는가'는 보장하지 않는다.
volatile
- 멀티 쓰레드 환경에서는 task를 수행하는 동안 성능 향상을 위해 변수 데이터들을 메인 메모리에서 활용하는 것이 아닌 CPU 캐시에 저장하고 활용한다.
- 즉, 쓰레드 간에 같은 변수에 접근한다고하더라도 같은 값을 가지지 않고 다른 값을 가지게 되는 것이다.
- 즉,
volatile이 사용된 필드는 멀티 쓰레드 상황에서 CPU 캐시를 사용하지 않고 메인 메모리로부터 데이터를 저장하고 읽기에 문제 상황을 해결할 수 있다.
- 그러나 이 방식은 성능 저하를 유발하며 사용을 자제해야 한다.
동기화 문제를 피하는 가장 좋은 방법
- 애초에 가변 데이터 자체를 공유하지 않는 것이다.
- 불변 데이터만 공유하거나 아무것도 공유하지 말도록 한다.
- 가변 데이터는 단일 쓰레드에서만 사용하도록 한다.
- 문서화를 잘해서 동기화 문제가 발생하지 않도록 한다. →
synchronized 키워드를 사용했다면, 다른 부분에서도 사용할 수 있도록 하고 가변 데이터는 단일 쓰레드에서만 사용한다면 멀티 쓰레드에서는 사용하지 않도록
- 사용하려는 프레임워크, 라이브러리가 쓰레드를 수행하는지 인지하고 사용한다.