Goal
- Thread safe이란 무엇인지 알아본다
- Thread safe vs Thread unsafe
- Thread safe한 코드 설계하는 방법을 알아본다
Thread safe
여러 개의 스레드에서 동시에 해당 코드를 실행하더라도 문제가 발생하지 않고, 안전하게 사용될 수 있는 코드를 말한다.
"스레드"는 하나의 프로세스 내에서 병렬로 실행될 수 있는 실행 단위를 말한다.
다중 스레드 환경에서는, 각 스레드가 동시에 코드를 실행할 수 있어, 이로 인해 발생할 수 있는 문제들(예: 경쟁 조건, 교착 상태, 데드락 등)을 방지하기 위해 스레드 안전성이 중요하다.
Thread safe vs Thread unsafe 한 코드의 특징
Tread safe | Tread unsafe |
두 개 이상의 스레드에서 동시에 해당 코드 실행시 문제 발생 x | 여러 스레드에서 동시에 해당 코드 실행 시 예기치 않은 동작 발생 |
공유 자원에 대한 접근을 동기화하거나 동시성 제어 기법 사용 | 공유 자원에 대한 접근을 동기화하지 않거나, 동기화 방법이 부적절하거나, 공유 자원의 불변성을 유지하지 않는다. |
전역 변수와 같은 공유 자원에 대한 접근을 제한하거나 불변성을 유지하는 등의 방법으로 스레드 간의 경쟁 상태를 방지 |
경쟁 조건이 발생하거나 교착 상태 또는 데드락 등의 문제가 발생 |
Thread safety 여부 판단 방법
- 다음과 같이 세 가지를 통해 thread-safe한 상태인지 판단할 수 있다.
1. 전역 변수나 힙, 파일과 같이 여러 스레드가 동시에 접근할 수 있는 자원을 사용하는가?
2. 데이터의 간접 접근이 가능한가?
3. 부수 효과를 가져오는 코드가 있는가?
Thread safe 를 지키는 방법
- Re-entrancy
- 어떤 함수가 한 스레드에 의해 호출되어 실행 중일 때, 다른 스레드가 그 함수를 호출하더라도 그 결과가 각각에게 올바로 주어져야 한다.
- Thread-local storage
- 공유 자원의 사용을 최대한 줄여 각각의 스레드에서만 접근 가능한 저장소들을 사용함으로써 동시 접근을 막는다.
- 이 방식은 동기화 방법과 관련되어 있고, 또한 공유상태를 피할 수 없을 때 사용하는 방식이다.
- Mutual exclusion
- Thread에 lock이나 semaphore를 걸어서 공유자원에는 하나의 thread만 접근 가능하게 한다.
- Atomic operations
- 데이터 변경시 atomic하게 데이터에 접근하도록 만든다.
- Immutable Object
- 객체 생성 이후에 값을 변경할 수 없도록 만든다.
atomic : 프로그래밍에서 데이터의 변경이 동시에 일어난 것처럼 보이게 하는 것을 의미한다. 데이터의 값을 변경하는 것은 항상 그 시간이 필요하다. atomic 한 데이터의 변경이 이루어지는 시간에는 lock 을 건다. 그래서 데이터를 변경하는 시간동안에는 접근이 이루어지지 않게한다. 그래서 프로퍼티가 *atomic 하다는 것은 멀티 스레드 환경에서 데이터가 반드시 변경전과 후의 상황에서만 접근하는 것을 보장한다. 즉, 데이터의 변경이 이루어지고 있는 순간에는 접근이 불가능하다.
Thread safe 한 코드 설계 하기
- 락(lock)이나 뮤텍스(mutual exclusion)와 같은 동기화 기법을 사용 - synchronized 키워드를 사용
@ThreadSafe
public class Sequence {
@GuardedBy("this") private int nextValue;
public synchronized int getNext() {
return nextValue++;
}
}
이렇게 하여 공유 자원에 대한 접근을 동기화한다.
2. 전역 변수 대신 지역 변수를 사용
이는전역 변수와 같은 공유 자원에 대한 접근을 제한하면 스레드 간의 경쟁 조건을 방지한다.
3. 스레드 간의 작업을 적절히 분리하여 스레드 간의 경쟁 조건을 방지
4. 불변 객체를 사용하거나, 객체 상태 변경을 최소화
이는 불변성을 유지하여 스레드 간의 경쟁 조건을 방지한다
5. java.util.concurrent 패키지 하위 클래스를 사용
java.util.concurrent는 Java 5에서 추가된 패키지로, 동기화가 필요한 상황에서 사용할 수 있는 다양한 유틸리티 클래스들을 제공
- Locks : 상호 배제를 사용할 수 있는 클래스를 제공한다.
- Atomic : 동기화가 되어있는 변수를 제공한다.
- Executors : 쓰레드 풀 생성, 쓰레드 생명주기 관리, Task 등록과 실행 등을 간편하게 처리할 수 있다.
- Queue : thread-safe한 FIFO 큐를 제공한다.
- Synchronizers : 특수한 목적의 동기화를 처리하는 5개의 클래스를 제공한다. (Semaphroe, CountDownLatch, CyclicBarrier, Phaser, Exchanger)
참고
https://sup2is.github.io/2021/05/03/thread-safe-in-java.html
https://zion830.tistory.com/57
https://velog.io/@hoo00nn/Thread-safe%EC%99%80-%EB%8F%99%EA%B8%B0%ED%99%94-%EA%B0%9D%EC%B2%B4
'JAVA > about java' 카테고리의 다른 글
[Generic] 제네릭 (0) | 2023.04.30 |
---|---|
[GC] Garbage Collector (0) | 2023.04.29 |
[JVM] jvm / java.lang (1) | 2023.04.25 |
[Annotation] 어노테이션 (1) | 2023.04.25 |
[ArrayList] ArrayList / Array vs ArrayList / 자바 버전 별 차이점 (0) | 2023.04.25 |