자바 동시 프로그래밍 기초 - 스레드 안전

스레드로부터의 안전성

다중 스레드 환경에서 참조, 동시 프로그램의 정확성을 대신하여 안전을 스레드 응용 프로그램은 항상 올바른 동작을 보여 할 수있을 것입니다.

문제의 뿌리

공유 변수의 상태 : 스레드 안전 문제는 모두 같은 원인에 기인 할 수있다. "공유"변수가 여러 스레드가 동시에 액세스 할 수 있다는 것을 의미한다 "변수"변수의 값이 변화의 수명주기 동안 발생할 수 있다는 것을 의미한다.
공유 가변 상태 액세스 동작하는 코어의 도입에 의해 관리되는 인 스레드 안전성 코드 작성 동기화 메커니즘을 보장하기를 공유하는 가변 상태 언제든지 액세스에서 하나의 스레드.

공유 변경 가능한 객체

동시 프로그래밍에서 공유 변수 객체는 다음과 같은 세 가지 질문에 직면하게 될 것이다 :

원자 수가

경쟁 조건

계산의 정확성은 번갈아 수행하는 복수의 스레드의 순서에 의존 할 때, 매우 경쟁 상태가 발생할 수있다. 정적 모드의 일반적인 이가지 :

  • 읽기 - 수정 - 쓰기 (읽기 - 변경 - 쓰기)의 단계 정교화 작업 : 공유 변수 값 (읽기)를 읽고, 다음 계산을을 (수정)의 값에 따라, 값 (쓰기) 공유 변수를 업데이트 .
  • 체크 그때 행동 (동작을 모니터링 한 후)을 정제하는 단계 : 상기 공유 변수의 값을 읽고,이 값은 어떻게 판정 예에 따른 다음 동작.

읽기 수정 - 쓰기 예를 :

@NotThreadSafe
public class UnsafeCounter {
  private int value;

  public int getNext() {
      return value++;
  }
}
复制代码

값 증가 연산자는 ++ 세 단계를 포함하는 것을 특징으로 : 값의 값을 읽고, 플러스 1의 값을, 최종 계산 결과는 vlue 값, 일반적인 읽기 다시 쓰기 레이스 모드에 기록됩니다.
체크인 당시 행동 예 :

@NotThreadSafe
public class UnsafeSequence {
  private int sequence;
  
  public int getSequence() {
      if(sequence >= 99){ // 步骤1 检查共享变量
          return 0;      // 步骤2 act 检查后操作
      } else {
          return sequence++;
      }
  }
}
复制代码

공유 변수의 수정 과정에서 그 특정 스레드를 보장하기 위해 원자 작업을 소개 할 필요가 어떻게 경쟁 조건의 문제를 방지 할 수있는, 다른 스레드가 작동 할 수없는 다른 스레드 전이나 원자 원자 수술 후 공유 변수의 상태를 읽고 수정할 수 있습니다. 여기에서 우리는 원자 작업이 무엇인지 살펴 :

원자 조작

뷰의 스레드가 아닌 다른 스레드에서 수행되는 동작을 분리 할 경우 공유 변수에 대한 액세스와 관련된 동작은, 다음 동작 원자 동작은 원자 동작이다. 다음 사항에주의 참조의 개념에서 :

  • 아토믹 조작 공유 변수에 액세스 동작의 목적을 위해, 그것은 로컬 변수 원자 여부 상관 없다
  • 멀티 스레드 환경 말이 위해 원자 작업입니다

두 가지 의미 다음과 불가분 동시에 :

  • 액세스보기의 실행 포인트의 스레드가 아닌 다른 스레드에서 공유 변수를 (읽기, 쓰기),이 작업이 상태에서 존재하지 않는, 중 종료 또는 아직 일어나지도 않은 수행 된
  • 액세스가 엇갈리게 할 수없는 공유 운영 변수의 설정 통합.

두 가지 방법의 자바 자성 :

  1. 사용 잠금 (잠금) (잠금은 하나의 장을 공유해야합니다에 대한) 하나의 스레드 만 액세스 할 수있는 시간에 공유 변수를 보호하기 위해 관여 할 수있는 배타적 잠금이 있습니다.
  2. 이 레벨을 달성하기 위해 하드웨어 프로세서 및 메모리에 직접 CAS 명령, CAS 명령을 사용하여, (CAS 별도의 장을 공유하는) 하드웨어 로크로 볼 수있다.

시계

공유 변수의 쓰레드가 업데이트 된 후 다중 스레드 환경에서, 후속 변수 스레드에 방문을 즉시 업데이트 된 결과를 읽을 심지어 영구적없는 업데이트 된 결과를 읽을 수 없습니다. 가시성 : 이것은 또 다른 표현의 스레드 안전합니다.
문제의 가시성 자바 메모리 모델, 특정 기준의 결정에 기인 자바 병행 프로그래밍 - 메모리 모델의
시인성을 확보하는 방법을 자바 플랫폼 :

  • 휘발성 키워드는 통지가 다른 스레드의 동작 변수를 업데이트 할 수 있도록하는 데 사용됩니다
  • 장치를 잠그면 모두 시인성을 확보 할 수 있으며 자성을 보장 할 수 있습니다
  • 최종 가시성 : 완료되면 생성자의 필드의 마지막 수정 후 다른 스레드는 최종 필드 값을 볼 수 있습니다

온화

제 (아웃 오브 오더 실행) 효율성을 개선하기 위해 상기 프로세서에 더하여, 자바 JIT 편집기 자체 재주문 명령 할 것이다 기계어 최종적으로 생성 될 수있다 바이트 순서가 실행 현대 마이크로 프로세서 명령어 코드 시퀀스는 일치하지 않습니다. 동시 프로그램이 순서가 실행될 수있는 문에서 멀티 스레드 실행 스레드에서, 예를 들면 다음과 같은 프로그램으로 예기치 않은 결과가 발생할 수 있습니다 명령 실행 순서를, FLG가 앞에 수 사실 = = 1 실행 스레드 2 예기치 않게 = 2를 출력 할 수있다.

어떻게 자바 플랫폼 순차 메모리를 확인하는 액세스 :

  • 메모리 장벽 명령의 특정 유형을 추가하여 프로세서의 재 배열을 해제하는 휘발성 키워드
  • 재정렬을 금지하는 잠금

스레드 안전 문제 해결

공유 상태를 피하십시오

무 상태 객체 자체가 서로 고립 상태를 유지하지 않는 각 서블릿, 그들은 서로 간섭하지 않는 스레드 안전, 일반적인 서블릿 프로그램이 있어야합니다. 홀드 상태가 불가피한 경우,이 기술을 밀봉 실을 사용할 수 있으며, "숨겨진"의 상태가 다른 스레드에 대한 액세스를 방지합니다. 일반적인 접근 방식은 폐쇄 스택하는 것입니다 ThreadLoca 두 가지 형태. 청산 스레드 스택은 특별한 경우 닫혀 스택 폐쇄, 지역 변수는 객체를 통해 액세스 할 수 있습니다,이 지역 변수는 실행 스레드의 스택 내에 포함되며, 다른 스레드가 그들에게 액세스 할 수 없습니다.

    public int loadTheArk(Collection<Animal> candidates) {
        SortedSet<Animal> animals;
        int numPairs = 0;
        Animal candidate = null;

        // animals confined to method, don't let them escape!
        animals = new TreeSet<Animal>(new SpeciesGenderComparator());
        animals.addAll(candidates);
        for (Animal a : animals) {
            if (candidate == null || !candidate.isPotentialMate(a))
                candidate = a;
            else {
                ark.load(new AnimalPair(candidate, a));
                ++numPairs;
                candidate = null;
            }
        }
        return numPairs;
    }
复制代码

위의 코드에서, 동물과 후보의 지역 변수가 존재하는 경우,이 메소드는 스레드에 안전하고, 다른 스레드가 액세스 할 수있게 탈출하지 않습니다, 스택 프레임 내에서 제한되어야한다. 의 ThreadLocal는,이 확장되지 않은 설명을 도입에 특별 섹션이있을 것입니다.

변경 가능한 상태를 피하십시오

그 상태로 만든 후 수정 될 수없는 오브젝트 경우, 오브젝트는 불변 오브젝트를 호출한다. 불변의 객체는 스레드 안전해야합니다. 다음과 같은 조건이 충족되면, 객체는 불변입니다 :

  • 개체는 상태가 변경 될 수 없다는 만든 후
  • 모든 속성은 최종 Object 형식입니다
  • 객체가 제대로 생성 (작성 중,이 탈출하지 말합)

구아바 라이브러리는 또한 ImmutabelList, ImmutableSet이, 우리는 코드에서 가능한 한 많이 사용해야 불변 클래스의 세트를 제공합니다

동기화 메커니즘

스레드 안전을 보장하기 위해 동기화 메커니즘 - 공유 변수와 피할 수없는 경우에만 최악의를 사용합니다. 자바 코드, 일반적으로 동기화 키워드, 클래스 또는 개체 잠금에서 동기화를 달성했다. 다음 장에서 분석 자바 고유의 동기화 메커니즘.

추천

출처juejin.im/post/5d6a804f51882571532c98ae