IT/JAVA

[Java] 자바의 동시성 (Concurrency)

음료요정 2022. 3. 15. 00:58

자바의 동시성

자바는 멀티쓰레드를 지원하는 언어이다.
멀티 쓰레드 프로그래밍에서 고려해야 할 것이 바로 동시성 문제이다. -> 동기화를 해주어야 한다.


Thread safe?

- 쓰레드 세이프라는 것은 멀티쓰레드 프로그래밍 환경에서 특정 자원에 대해 여러 쓰레드로 동시에 접근이 이루어져도 프로그램의 실행에 문제가 없음을 의미한다.
- 자바 JVM내 Method 영역내의 데이터나 인스턴스 변수와 같이 Heap영역에 저장되는 데이터는 여러스레드 간에 공유되는 자원이기때문에 Thread safe한 자원이 아니다.
-> 그렇기때문에 Thread safe하지 않은 자원에 대해서 데이터의 안정성과 신뢰성을 보장하고, 동시성 문제를 발생시키지 않기 위한 동기화가 필요하다.


자바의 동기화 방법

1. Syncronized
2. Volatile
3. Atomic



1. Synchronized

- 여러개의 쓰레드가 특정 자원을 사용하고자 할때, 현재 데이터를 사용하고잇는 해당 쓰레드를 제외한 나머지 쓰레드들은 데이터에 접근할 수 없도록 하는 자바의 예약어이다.

- 사용방법
- synchronized methods : 메소드를 syncronized로 선언하는 방법

public synchronized void add(int val){
 amount += val;
}

- synchronized statements : 특정 문장만 synchronized로 감싸는 방법

public void add(int val){
	synchronized(this){
		amount += val;
	}
}

- 메소드가 길어질 경우, 메소드에 synchronzed를 추가하면 성능상에 문제가 발생할 가능성이 크다. 그렇게 때문에 동시성을 보장해야할 코드에만 감싸주면 효율적인 프로그래밍이 가능하다.


Synchronized 의 한계 :
- synchronized는 대상 자원에 대한 Lock을 잡는 것이기 때문에 오버헤드가 있고, deadlock 문제를 일으킬 수 있는 가능성이 있다.
- 실무에서 거의 사용되지 않는 방법이다.



2. Volatile

- Java에서 변수값을 메인메모리에 저장하겠다고 명시하는 키워드이다.
- 매번 변수 값을 읽고 쓸 때마다 CPU의 cache에 저장된 값이 아닌 메인 메모리에서 읽는 것이다.
- 메인메모리 캐시 처리 사진 첨부 필요 - volatile 변수를 사용하지 않는 멀티쓰레드 어플리케이션은 task를 수행하는 동안 성능향상을 위해 메인메모리에서 읽은 변수 값을 CPU 캐시에 저장한다.
- 이러한 상황에서 여러쓰레드가 다른 값을 읽어 변경되기 전 값을 처리한다면 데이터 불일치 문제가 발생한다. -> 가시성 문제

Volatile의 한계:
메인 메모리의 같은 대상을 보고 값을 더할 경우 , 같은 데이터에 값을 더해도 두 데이터 일관성이 깨지는 문제가 발생한다. Volatile을 사용하는 경우 :
- 여러쓰레드가 동시에 데이터를 쓰기하는것은 적합하지 않고, 한 쓰레드만 쓰고, 나머지는 읽기만 하는 경우 동시성 보장이 가능하다.


3. Atomic과 CAS

- Atomic은 CAS (Compare And Swap)방식을 기반으로 하며, 멀티쓰레드 환경에서 동시성 문제를 해결한다.
- CAS 란 무엇일까?
- 변수의 값을 변경하기 전에 기존에 가지고 있던 값이 예상하던 값과 같은 경우에만 새로운 값을 할당하는 방법이다. 즉 값을 변경하기 전 한번 더 확인하는 절차가 있는 것이라고 볼 수 있다.


CAS의 장점 :
- CAS는 병렬성을 해치지 않으면서 동시성을 보장하기 때문에 더 좋은 성능을 가져온다.
- volatile에서 발생할 수 있는 가시성 문제도 해결할 수 있다. CAS의 사용 예:
- 자바의 concurrent 패키지의 타입들은 현재 스레드에서 사용되는 값이 메인메모리의 값과 같은지 비교하고, 불일치한다면 메인메모리의 값을 가져와 계산하는 CAS 알고리즘을 이용해 데이터의 원자성(atomoic)을 보장하고, 좋은 성능을 보장한다.
- ConcurrentHashMap, AtomicInteger, AtomicBoolean등의 타입이 있다.


- 참고사이트 :

https://didrlgus.github.io/java/05-post/
https://okky.kr/article/279692 : 자바 동기화의 어려움을 토로한 okky글