Race Condition, Thread Safety, Immutability

man soup·2020년 7월 5일
0

자바 공부

목록 보기
4/7

Race Conditions and Critical Sections

  • 경쟁 조건이란 임계 구역 안에서 일어날 수 있는 특별한 상태를 말한다.
  • 임계 구역이란 여러 쓰레드에 의해 실행되는 코드 지역으로 쓰레드들의 실행 순서가 동시 실행 결과를 다르게 하는 지역이라는 뜻이다.
  • 임계 구역의 다중 쓰레드 실행 결과가 어떤 쓰레드부터 실행했는지 순서에 따라 달라질 때, 임계 구역은 경쟁 조건을 가진다고 한다.

Critical Sections

  • 하나 이상의 쓰레드를 응용에서 실행하는 것만이 문제를 발생시키지 않는다.
  • 문제는 다중 쓰레드가 같은 자원에 접근할경우 발생한다.
    • 예를들어 같은 메모리(변수, 배열, 객체), 시스템(데이터 베이스, 웹 서비드 등), 파일
  • 사실 문제는 이러한 자원에 하나 이상의 쓰레드가 write할 경우 발생한다.
  • 자원이 변하지 않는다면 여러 쓰레드가 같은 자원을 읽는 것은 안전하다.

Preventing Race Conditions

  • 경쟁 조건을 방지하기 위해서 임계 구역이 원자적 instruction으로 실행됨을 보장해야한다.
  • 하나의 쓰레드가 실행할 때 다른 쓰레드는 실행중인 쓰레드가 임계 구역을 나오기 전까지 실행할 수 없게 만드는 것을 말한다.
  • 경쟁 조건은 임계구역의 적절한 쓰레드 동기화를 통해 피할 수 있다.
  • 자바 코드의 동기화 블록을 통해 쓰레드 동기화를 얻을 수 있다.
  • 쓰레드 동기화는 lock 또는 원자 변수를 사용해서도 얻을 수 있다.

여러 쓰레드가 안전하게 동시에 호출할 수 있는 코드를 thread safe라고 한다.

만약 어떤 코드가 thread safe라는 것은 경쟁 조건(누가 먼저 사용하냐에 따라 결과가 달라지는 것)을 포함하지 않는다는 뜻이다.
경쟁 조건은 공유 자원을 여러 쓰레드가 업데이트할 경우에만 발생한다.
그러므로 자바 쓰레드가 어떤 자원을 공유하는지 아는 것은 매우 중요하다.

Local Variables

  • 지역 변수는 각 쓰레드의 스택에 저장된다. 그러므로 쓰레드간 지역 변수는 절대로 공유되지 않는다. 즉 모든 지역 primitive 변수들은 thread safe이다.

Local Object References

  • 지역 레퍼런스 변수는 조금 다르다. 레퍼런스 자체는 공유되지 않지만 참조된 객체는 쓰레드 각각의 스택에 저장되지 않는다. 모든 객체들은 공유 힙에 저장된다.
  • 만약 생성된 객체가 생성된 메소드 지역 안에서 벗어나지 않으면 thread safe하다.

Object Member Variables

  • 객체 멤버 변수(필드)는 객체와 함께 힙에 저장된다.
  • 그러므로 만약 두 쓰레드가 같은 객체 인스턴스의 메소드를 호출하고 그 메소드가 객체 맴버 변수를 업데이트 할 경우 메소드는 thread safe하지 않다.
NotThreadSafe sharedInstance = new NotThreadSafe();

new Thread(new MyRunnable(sharedInstance)).start();
new Thread(new MyRunnable(sharedInstance)).start();
  • 그러나만약 두 쓰레드가 다른 인스턴스에 대해 동시적으로 호출한다면 경쟁 조건을 유발하지 않는다.
new Thread(new MyRunnable(new NotThreadSafe())).start();
new Thread(new MyRunnable(new NotThreadSafe())).start();
  • 즉 객체가 thread safe하지 않더라도 경쟁 조건을 유발하지않는 방법으로 사용될 수 있다.

The Thread Control Escape Rule

  • 특정 자원에 접근하는 코드가 thread safe인지 아닌지 결정하기 위해서 thread control escape rule 을 사용할 수 있다.
    • 만약 리소스가 생성,사용,제거가 같은 쓰레드 안의 control에서 발생하고 그 쓰레드의 control을 절대로 벗어나지 않다면 그 자원 사용은 thread safe하다
  • 자원은 객체, 배열, 파일, 데이터베이스 연결, 소켓 등의 어떤 공유 자원도 될 수 있다.
  • 자바에서 언제나 명시적으로 객체를 제거할 수 없으니 제거의 뜻은 그 객체에 대한 레퍼런스를 버리거나 null로 만드는 것을 의미한다.
  • 객체 사용이 thread safe 여도 그 객체가 파일 또는 데이터베이스 같은 공유 자원을 가리키고 있다면 그 응용은 thread safe가 아닐 수 있다.
  • 예를 들어 thread 1과2가 각각 자신만의 데이터베이스 연결점을 생성하면 각각의 연결 자체는 thread safe이다.
  • 그러나 그 연결이 가리키는 데이터베이스의 사용은 thread safe가 아닐 수 있다.
  • 예를 들어 두 쓰레드가 레코드X를 확인하고 존재하지 않으면 X 레코드 삽입이라는 코드를 실행할 경우, 두 쓰레드가 동시에 실행되고 X 레코드가 같은 레코드일 경우 도 쓰레드 모두 X를 삽입할 위험이 존재한다.
  • 이러한 상황은 쓰레드가 file 이나 다른 공유 자원을 사용할 경우 발생 할 수 있다.
  • 그러므로 쓰레드가 컨트롤하는 객체가 리소스인지 리소스의 레퍼런스인지를 구별하는 것이 중요하다.

Thread Safety and Immutability

  • 경쟁 조건은 여러 쓰레드가 같은 리소스에 접근해 하나 이상의 쓰레드가 리소스에 write할 경우 발생한다.
  • 만약 여러 쓰레드가 같은 자원에 대해 읽기만 한다면 경쟁 조건은 일어나지 않는다.
  • 쓰레드간 공유하는 객체를 immutable로 만듦은 어느 쓰레드도 공유 자원을 업데이트 할 수 없게 하므로 thread safe 이다.
    • setter가 없는 클래스는 immutable하다.
    • getter를 통해 read해도 immutable과 상관x
    • 만약 immutable한 객체를 업데이트하고 싶으면 새로운 객체를 반환하게 한다.

The Reference is not Thread Safe!

  • 객체가 immutable하여 thread safe하다고 해도 그 객체에 대한 레퍼런스는 thread safe하지 않을 수 있다.

출처 : http://tutorials.jenkov.com/java-concurrency/thread-safety.html

profile
안녕하세요

0개의 댓글