본문 바로가기

병렬처리

스레드 안전성

java 동기화 기본 수단

 - 자바에서 동기화를 위한 기본 수단은 syncronized 키워드로서 베타적인 락을 통해 보호 기능을 제공 함.

 - volatile 변수, 명시적 락, 단일 연산 변수 (atomic variable)을 사용하는 경우에도 동기화 용어를 사용함.


여러 스레드가 변경할 수 있는 하나의 상태 변수를 적절한 동기화 없이 접근하면 그 프로그램은 잘못된 것.

 프로그램을 고치는 3가지 방법

  - 해당 상태 변수를 스레드 간에 공유하지 않거나

  - 해당 상태 변수를 변경할 수 없도록 만들거나

  - 해당 상태 변수에 접근할 땐 언제나 동기화를 사용



상태 없는 서블릿

 - 서블릿 기반 인수분해 서비스를 만들고 스레드 안정성을 유지하면서 하나하나 기능 추가

@ThreadSafe
public class StatelessFactorizer implements Servlet{
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
BigInteger i = extracFromRequest(req);
BigInteger[] factors = factor(i);
encodeIntoResponse(res, factors);
}
}

 - StatelessFactorize는 대부분의 서블릿처럼 상태가 없다. 즉 선언한 변수가 없고 다른 클랫의 변수를 참조하지도 않는다.

 - 상태 없는 스레드는 객체에 접근하는 스레드가 어떤 일을 하든 동작의 정확성에 영향을 끼칠 수 없기 때문에 상태 없는 객체는 항상 스레드 안전하다.



단일 연산


@ThreadSafe
public class StatelessFactorizer implements Servlet{
private long count = 0;

public long getCount() {return count;}

@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
BigInteger i = extracFromRequest(req);
BigInteger[] factors = factor(i);
++count;
encodeIntoResponse(res, factors);
}
}

- 단일 스레드 환경에서는 잘 동작하지만 스레드에 안전하지 않다.

- 여러 번 호출했을 때 같은 값을 돌려주는 사소한 문제가 심각한 데이터 무결성 문제의 원인이 된다. 

- 병령 프로그램의 입장에서 타이밍 안 좋을때 결과가 잘못될 가능성은 굉장히 중요한 개념이기 때문에 경쟁 조건이라는 별도의 용어로 정의



경쟁조건(race condition)과 데이터 경쟁(data race)차이

 - 데이터 경쟁은 공유된 final이 아닌 필드에 대한 접근을 동기화로 보호하지 않았을 때 발생

 - 경쟁조건은 두 개 이상의 동작을 동시에 수행하려고 할 때 발생하는 비정상적 상태


점검 후 행동

 - 어떤 사실을 확인하고 그 관찰에 기반해 행동을 하지만 해당 관찰은 관찰한 시각과 행동한 시각 사이에 더 이상 유효하지 않게 됐을 수도 있다.

 - 늦은 초기화 프로그래밍 패턴이 예이다.

 - 스레드 B가 살펴보는 그 시점에 instance가 null이면 getInstance를 호출한 두 스레드가 각각 서로 다른 인스턴르르 가져갈 수 있다.



@ThreadSafe
public class StatelessFactorizer implements Servlet{
private final AtomicLong count = new AtomicLong(0);

public long getCount() {return count.get();}

@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
BigInteger i = extracFromRequest(req);
BigInteger[] factors = factor(i);
count.incrementAndGet();
encodeIntoResponse(res, factors);
}
}


 - long의 카운터를 AtomicLong 단일 연산 변수로 변경함으로 스레드에 안전하다.

   





'병렬처리' 카테고리의 다른 글

스레드 소개  (0) 2019.01.21
  (0) 2017.05.17