[프로그래밍] 스레드 안전

자바 언어 기준

데이터 타입이나 메서드가 스레드 안전(thread safe)하다는 것은 멀티 스레드 프로그램에서 서로 다른 스레드가 동일한 데이터 타입이나 메서드에 접근하여 사용하더라도 의도대로 올바르게 동작하는 것을 말한다.

동시성(concurrent) 연산이 수행되는 경우 코드 실행의 상대적 발생 순서 및 시점에 따라 연산 결과가 달라지고 연산의 정확성이 떨어지게 되는데 이러한 조건을 경쟁 조건(race condition)(또는 경합 조건)이라고 한다. 멀티 스레드 환경에서는 여러 스레드가 동일한 가변 변수(가변 객체의 프로퍼티)를 공유하는 경우 스레드가 수행하는 작업을 서로 조율하는 과정이 없다면 프로그램의 정확성은 저수준의 연산 수행 시점에 따라 달라질 수 있으며 이는 스레드 안전하지 않다. 스레드의 작업을 서로 조율하기 위해서는 동기화(synchronization)라는 과정이 필요하며 객체 락(object lock)은 여러 동기화 기법 중 하나이다.

멀티 스레드 환경에서 스레드 안전한 코드를 구현하기 위해 다음과 같은 방법을 사용할 수 있다.

  1. 가변 데이터가 스레드 간 공유되지 않도록 한다.
  2. 스레드 간 공유하여 사용할 데이터는 불변성을 갖도록 만든다.
  3. 공유 가변 데이터는 스레드 안전한 데이터 타입에 저장한다. API 또는 라이브러리가 제공하는 스레드 안전한 데이터 타입을 사용한다.
  4. 동기화를 통해 한번에 하나의 스레드만 접근할 수 있는 데이터 타입을 정의한다.


스레드 안전한 데이터 타입은 그것을 사용하는 호출자가 별다른 전제조건 없이 사용할 수 있다. 반면 스레드 안전하지 않은 데이터 타입의 경우 여러 스레드가 공유하여 사용하게 되면 올바른 동작이 보장되지 않으므로 사용 시점에 경쟁 조건에 의해 연산 또는 메서드 호출이 방해 받지 않도록 제한이 필요하다.

로컬 변수는 항상 특정 스레드에 한정되어 있으므로 스레드 간 공유될 경우가 존재하지 않는다. 따라서 로컬 변수는 가변이거나 불변에 관계 없이 스레드 안전하다. 반면 정적 변수(클래스의 정적 필드)는 특정 스레드에 한정되지 않으며 공유될 수 있다. 따라서 가변 정적 변수는 스레드 안전하지 않으며 불변 정적 변수는 스레드 안전하다.

스레드 안전한 데이터 타입을 사용하는 것은 스레드 안전하지 않은 데이터 타입을 사용하는 것보다 더 많은 시스템 리소스를 필요로 한다. 스레드 안전성으로 인해 성능 저하가 유발되므로 연산의 정확성과 성능을 기준으로 적절한 사용 여부를 판단해야 한다.

싱글톤 패턴(singleton pattern)을 구현한 객체는 그 자체로 스레드 안전하지는 않다. 싱글톤 패턴에서 싱글톤 인스턴스는 하나만 생성되는 것이 목적이지만 스레드 경쟁 조건이 발생하는 상황에서 여러 개의 인스턴스가 생성될 수도 있다. 이러한 문제를 해결하기 위해 스레드 안전하게 싱글턴 인스턴스를 생성하는 코드 구현이 필요하다.


참고

Comments