>  기사  >  Java  >  Java의 어떤 클래스가 스레드로부터 안전합니까?

Java의 어떤 클래스가 스레드로부터 안전합니까?

(*-*)浩
(*-*)浩원래의
2019-05-21 13:36:398055검색

스레드로부터 안전한 코드 작성의 핵심은 상태 액세스 작업, 특히 공유 및 변경 가능한 상태에 대한 액세스를 관리하는 것입니다. 여러 스레드가 상태 변수에 액세스하고 하나의 스레드가 쓰기 작업을 수행하는 경우 변수에 대한 스레드의 액세스를 조정하기 위해 동기화 메커니즘을 사용해야 합니다. 상태 비저장 객체는 스레드로부터 안전해야 합니다.

Java의 어떤 클래스가 스레드로부터 안전합니까?

상태 비저장 객체에 상태를 추가하면 어떻게 되나요?

서블릿에 "히트 카운터"를 추가하여 다음과 같은 방식으로 요청 수를 관리한다고 가정합니다. 서블릿에 긴 유형 필드를 추가하고 요청이 처리될 때마다 이 값에 1을 추가합니다.

public class UnsafeCountingFactorizer implements Servlet {
     private long count = 0;
 
     public long getCount() {
            return count ;
     }
 
     @Override
     public void service(ServletRequest arg0, ServletResponse arg1)
                 throws ServletException, IOException {
            // do something
           count++;
     }
}

안타깝게도 위 코드는 count++가 원자 연산이 아니기 때문에 스레드로부터 안전하지 않습니다. 실제로 여기에는 count 값을 읽고 값에 1을 더한 다음 계산 결과 count를 쓰는 세 가지 별도의 작업이 포함되어 있습니다. 스레드 A가 개수가 10이라는 것을 읽으면 스레드 B는 즉시 개수도 10이라는 것을 읽습니다. 스레드 A는 1을 추가하고 11에 씁니다. 스레드 B는 이미 개수가 10이라는 것을 읽었으므로 1을 더하고 쓴 후에도 여전히 11입니다. 따라서 카운트가 손실됩니다.

동시 프로그래밍에서 부적절한 실행 타이밍으로 인해 발생하는 이러한 잘못된 결과는 매우 중요한 상황입니다. 정식 명칭은 경쟁 조건입니다. 가장 일반적인 유형의 경쟁 조건은 "먼저 확인한 후 실행" 작업입니다. 즉, 잘못된 관찰 결과가 다음 작업을 결정하는 데 사용됩니다.

지연 초기화는 경쟁 조건의 일반적인 상황입니다.

public class LazyInitRace {
     private SomeObject instance = null;
     public SomeObject getInstance() {
            if(instance == null)
                 instance = new SomeObject();
            return instance ;
     }
}

in LazyInitRace 경쟁 조건이 포함되어 있습니다. 먼저 스레드 A가 인스턴스가 null임을 확인한 다음 스레드 B가 인스턴스도 null임을 확인합니다. 그런 다음 스레드 A와 스레드 B가 각각 개체를 생성하므로 개체가 두 번 초기화되고 오류가 발생합니다.

정적 조건을 방지하려면 스레드가 변수를 수정할 때 다른 스레드가 어떤 방식으로든 이 변수를 사용하지 못하도록 해야 합니다. 이를 통해 다른 스레드는 수정 작업이 완료된 후가 아니라 수정 작업이 완료되기 전이나 후에만 상태를 읽고 수정할 수 있도록 해야 합니다. 상태를 수정하는 과정.
UnsafeCountingFactorizer 예제에서 스레드가 안전하지 않은 이유는 count++가 원자성 작업이 아니기 때문입니다. 원자 클래스를 사용하면 추가 작업이 원자성임을 확인할 수 있습니다.

이 클래스는 스레드로부터 안전합니다.

 public class CountingFactorizer implements Servlet {
     private final AtomicLong count = new AtomicLong(0);
 
    public long getCount() {
          return count .get() ;
   }
 
    @Override
    public void service(ServletRequest arg0, ServletResponse arg1)
               throws ServletException, IOException {
          // do something
          count.incrementAndGet();
   }
}

AtomicLong은 java입니다. .util.concurrent.atomic 패키지의 원자 변수 클래스는 원자 자동 증가 작업을 구현할 수 있으므로 스레드로부터 안전합니다.

관련 학습 권장사항: Java 기본 튜토리얼

위 내용은 Java의 어떤 클래스가 스레드로부터 안전합니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.