강의 메모 - ThreadLocal - 1,2 #
개요 #
- 여러 스레드에서 클래스나 객체에 동시에 접근해서 계속 실행하더라도 지속적인 정확성이 보장되는 코드를 스레드 세이프(thread-safe) 즉 스레드에 안전하다고 한다.
- 동시에 실행해도 동일한 결과값
- 기본적으로 클래스 명세에 스레드 안정성을 헤치는 코드나 상태를 가지고 있지 않으면 스레드에 안전하다라고 정의할 수 있다
- 스레드에 안전한 코드에는 경쟁상태가 없으며 경쟁 상태는 다수의 스레드가 공유 자원에 쓰기 작업을 시도할 때 발생하기 때문에 스레드가 실행될 때 어떤 자원을 공유하게 되는지 아는 것이 중요하다
스레드에 안전한 구조 #
-
임계영역을 동기화 한다
- 동시에 여러개의 스레드가 임계영역을 접근하지 못하도록 락(Lock) 메카니즘을 사용한다
-
동기화 도구를 사용한다
- 세마포어, CAS, Atomic 변수, 동시성 자료구조 등의 동기화 도구들을 사용해서 스레드 안전성을 구현한다
-
스레드의 스택에 한정해서 상태를 관리한다
- 스레드마다 할당된 스택 메모리 내에서 상태를 관리함으로서 다른 스레드와 상태를 공유할 수 없도록 한다’
-
ThreadLocal 을 사용한다
- 스레드마다 가지고 있는 전용 저장소인 ThreadLocal 을 사용해서 상태를 관리함으로서 다른 스레드와 상태를 공유할 수 없도록 한다
-
불변 객체를 사용한다
- 객체의 상태를 변경할 수 없는 클래스를 사용하거나 클래스를 설계할 때 상태를 변경할 수 없도록 만들어서 스레드에 안전하도록 한다
동기화 도구 사용 #
-
각 스레드가 동시에 동일한 Item 을 중복해서 읽어 올 수 있다
-
각 스레드가 대기하고 있다가 순차적으로 Item 을 읽어 온다
스레드의 스택 한정 #
-
지역 변수
- 기본형 지역 변수는 스레드 마다 독립적으로 가지고 있는 스택에 저장되기 때문에 스레드간에 공유될 수 없다. 스레드에 안전한다
- 메서드로 전달되는 기본형 파라미터 변수도 스택에서만 관리되므로 스레드에 안전하다
-
지역 객체 참조
- 지역 변수라 할지라도 객체 참조 변수는 기본형과 다른점이 있는데 객체는 스택에 저장되지 않고 메모리의 힙(heap) 영역에 저장된다는 점이다
- 지역적으로 생성된 객체가 해당 메서드에서 벗어나지 않고 사용 된다면 스레드는 자신만의 객체를 참조할 수 있게 되어 스레드에 안전하다
- 지역 참조 변수를 다른 클래스의 메소드에 파라미터로 넘겼을 때 해당 클래스가 파라미터 변수를 다른 스레드가 접근할 수 있는 멤버 변수로 저장했을 경우에는 스레드에 안전하지 않다
- 만약에 Member member1을 파라미터로 받는다면?
- 위 member1객체의 변경 행위를 하면 스레드 안정하지 않다. 모든 스레드가 이 객체를 바라보기 때문 (new 연산자로 생성한게 아니니깐)
- 동시 접근이 가능하기 때문에 발생 (멤버변수)
- 문자열 같이 불변 객체는 상태가 변경되지 않기 때문에 스레드에 안전하다
-
멤버 변수 참조
- 멤버 변수 참조 역시 스레드 마다 객체를 생성하는 원리는 동일하다. 즉 스레드의 스택별로 객체가 생성되어 참조되도록 구현하면 된다
불변 객체 사용 #
- Setter 메서드가 없음, 생성자에서 멤버 변수 초기화, 멤버 변수는 final 로 선언 등으로 불변객체를 생성한다
- 불변객체는 어떠한 상황에도 상태가 변하지 않으므로 스레드에 안전하다고 할 수 있다
※ 최초로 객체가 생성되는 시점 이후로 값이 절대 변하지 않는다