💡 동시성과 병렬성
- 둘다 멀티 태스킹을 처리하는 방식이지만, 다르다.
(동시성)
- 동시성은 여러 작업이 시간을 나누어 마치 동시에 실행되는 것 처럼 보이는 기술
- 멀티태스킹을 예시로 들수 있음 (하나의 코어로 여러개의 작업을 쪼개 실행하는 기술)
- SW 관점
(병렬성)
- 병렬성은 실제 물리적으로 여러 작업을 동시에 실행하는 것
- 여러 코어가 실제로 작업을 동시에 실행
- HW 관점
💡 가시성 문제와 원자성 문제
- 둘다 병렬 프로그래밍에서 발생하는 문제로, 동시성 이슈의 주범이다.
(가시성 문제 - Visibility)
- 멀티스레드 환경에서 한 스레드에서 변경된 데이터가 다른 스레드에서 즉시 보이지 않는 문제이다.
- 발생 이유는 각 스레드는 독립적인 CPU 캐시에 변경된 데이터를 저장하고, 나중에 변경된 데이터를 메모리에 반영하기 때문에 발생한다.
- 해결 : volatile 키워드를 사용해서 가시성 문제를 방지 할수 있다.
(원자성 문제 - Atomicity)
- 원자적 연산이란 더 이상 쪼개지지 않는 연산을 의미하며, 멀티스레드 상황에서 다른 스레드의 간섭 없이 안전하게 처리되는 연산을 의미한다
- 원자성 문제는 원자적 연산이 아닌 연산에서 발생되며, 일례로 i++ 연산이 있다. 이 연산은 얼핏 보면 더 이상 쪼개지지 않는 연산처럼 보이지만
- 위 연산은 다음과 같은 과정으로 쪼개진다.
1. i를 메모리에서 읽어 옴
2. i를 1만큼 증가
3. 1만큼 증가된 i를 대입
- 여기서 두개의 스레드가 동시에 같은값의 i를 메모리에 읽어와서, 1만큼 증가하고 1만큼 증가된 i를 대입하게 되면 1을 증가하는 연산 하나가 생략된다.
- 해결 : synchronized 키워드나 atomic 변수로 해결 가능
💡 volatile
- 가시성 문제를 해결하기 위한 키워드
- 이 키워드를 변수 앞에 추가하면 CPU 캐시를 이용하지 않고, 메모리를 사용하여 연산
- 스레드가 공유하는 메모리를 사용하기 때문에, 변경 즉시 다른 스레드도 변경 사실을 알 수 있음
- CPU 캐시를 사용할때보다 성능이 좋지 않기 때문에 꼭 필요한 경우에만 사용
💡 synchronized
- synchronized 키워드가 붙은 곳은 하나의 스레드만 접근 가능함
- 내부 구현 : 모든 객체 인스턴스는 모니터 락이라는 자신만의 락을 가지고 있고, synchronized 내부로 들어가려면 이 모니터 락을 가져야 들어갈수 있다.
- 문제점 :
1. 모니터 락을 기다리는 스레드는 BLOCKED 상태로 락을 기다리게 되는데 BLOCKED 상태는 인터럽트로도 해제 할수 없다. (자바에서 제공하는 기본 락이라 별로 기능이 없다)
2. 특정 시간 까지만 기다린다는 개념이 없기 때문에 무한정 락을 기다릴수도 있다. (사용시 finally 를 통해 락 해지를 꼭 해주도록 하자)
💡 Atomic 타입
- 멀티스레드에서 사용할수 있는 타입으로 AtomicInteger, AtomicLong, AtomicBoolean등이 있다.
- 위 타입들은 CAS 연산을 이용하여 원자성을 확보하고, 락을 사용하지 않는다는 특징이 있다.
- CAS 연산이란 Copy And Set의 약자로 CPU 하드웨어 차원에서 특정 값을 읽고, 업데이트 하는것을 하나의 연산으로 묶어 원자성을 보장 하는 것이다.
'Java' 카테고리의 다른 글
[JAVA] 가비지 컬렉션 (2) | 2025.01.30 |
---|---|
[JAVA] 컬렉션 총정리 (0) | 2025.01.13 |
[JAVA] 문자열, 예외, 제네릭, 람다, 스트림, 어노테이션, 리플렉션 (0) | 2025.01.06 |
[JAVA] 자바 기본, 자바 객체 지향 (1) | 2025.01.03 |