>Java >java지도 시간 >JAVA 동시 프로그래밍 요약: 스레드 안전성, 객체 공유

JAVA 동시 프로그래밍 요약: 스레드 안전성, 객체 공유

php是最好的语言
php是最好的语言원래의
2018-08-09 14:03:111633검색

1장 소개

발췌

  1. 스레드는 메모리 핸들 및 파일 핸들과 같은 프로세스 전체 리소스를 공유하지만 각 스레드에는 자체 프로그램 카운터(프로그램 카운터), 스택 및 로컬 변수 대기가 있습니다.

  2. 동일한 프로그램의 여러 스레드가 동시에 여러 CPU에서 실행되도록 예약할 수도 있습니다.

2장 스레드 안전

발췌

  1. Java의 주요 동기화 메커니즘은 독점적인 잠금 방법을 제공하는 동기화된 키워드이지만 "동기화"라는 용어에는 휘발성 유형 변수, 명시적 잠금 및 원자성 잠금도 포함됩니다. 변수.

  2. 여러 스레드가 동일한 변경 가능 상태 변수에 액세스할 때 적절한 동기화가 사용되지 않으면 프로그램에 오류가 발생합니다. 이 문제를 해결하는 세 가지 방법이 있습니다.

  • 스레드 간에 상태 변수를 공유하지 마세요.

  • 상태 변수를 불변 변수로 수정합니다.

  • 상태 변수에 액세스할 때 동기화를 사용하세요.

  • 스레드 안전성 정의: 여러 스레드가 클래스에 액세스할 때 이 클래스는 항상 올바른 동작을 보여줄 수 있으며, 이 클래스는 스레드로부터 안전하다고 합니다.

  • 상태 비저장 객체는 스레드로부터 안전해야 합니다.

  • 대부분의 경쟁 조건의 본질은 잠재적으로 유효하지 않은 관찰을 기반으로 판단하거나 계산을 수행하는 것입니다. 이러한 유형의 경쟁 조건을 "실행 전 확인"이라고 합니다. 먼저 조건이 참인 것으로 관찰된 다음(예: 파일 X가 존재하지 않음) 이 관찰을 기반으로 적절한 조치가 취해집니다(파일이 이 결과를 관찰하는 시간 사이에). 파일 생성을 시작하면 관찰이 유효하지 않게 될 수 있습니다(다른 스레드가 생성한 파일 손상 등).

  • 두 가지 작업 A와 B가 있다고 가정합니다. A를 실행하는 스레드의 관점에서 볼 때 다른 스레드가 B를 실행할 때 모든 B가 실행되거나 B가 전혀 실행되지 않으면 A와 B는 서로 반대라고 합니다. 원자적 작업은 동일한 상태에 액세스하는 모든 작업(작업 자체 포함)에 대해 이 작업이 원자적으로 수행됨을 의미합니다.

  • 실제 상황에서는 가능할 때마다 기존 스레드로부터 안전한 개체(예: AtomicLong)를 사용하여 클래스 상태를 관리해야 합니다. 스레드로부터 안전하지 않은 개체에 비해 스레드로부터 안전한 개체의 가능한 상태와 해당 상태 전환을 확인하는 것이 더 쉽기 때문에 스레드 안전을 유지하고 확인하는 것이 더 쉽습니다.

  • 상태 일관성을 유지하려면 모든 관련 상태 변수를 단일 원자 연산으로 업데이트해야 합니다.

  • 재진입을 구현하는 한 가지 방법은 가져오기 개수와 소유자 스레드를 각 잠금과 연결하는 것입니다. count 값이 0이면 어떤 스레드도 잠금을 보유하지 않는 것으로 간주됩니다. 스레드가 보유되지 않은 잠금을 요청하면 JVM은 잠금 보유자를 기록하고 획득 횟수를 1로 설정합니다. 동일한 스레드가 다시 잠금을 획득하면 카운터가 증가하고 스레드가 동기화된 블록을 종료하면 그에 따라 카운터가 감소됩니다. 개수가 0이 되면 잠금이 해제됩니다.

  • 모든 데이터를 잠금으로 보호할 필요는 없습니다. 동시에 여러 스레드에서 액세스하는 가변 데이터만 잠금으로 보호하면 됩니다.

  • 긴 계산을 수행하거나 빠르게 완료되지 않는 작업(예: 네트워크 IO 또는 콘솔 IO)을 수행할 때는 잠금을 유지하지 마세요.

    1. 상태에 대한 이해를 경험해 보세요. 클래스의 멤버 변수라고 생각합니다. 상태 비저장 개체는 멤버 변수가 데이터를 저장할 수 없거나 데이터를 저장할 수 있지만 데이터를 변경할 수 없음을 의미합니다. 상태 비저장 객체는 스레드로부터 안전합니다. 메서드에 멤버 변수가 있는 경우 이 멤버 변수에 대해 스레드로부터 안전한 관련 작업을 수행해야 합니다.

    2. 메서드 앞에 맹목적으로 동기화를 추가하지 마세요. 이렇게 하면 스레드 안전성을 보장할 수 있지만 메서드의 동시성 기능이 약화되어 동시성을 지원할 수 있는 메서드가 차단되어 프로그램 처리 속도가 느려집니다. .

    3. Synchronized로 둘러싸인 코드는 최대한 짧아야 하지만 영향을 받는 모든 멤버 변수는 함께 유지되어야 합니다. 관련되지 않은 멤버 변수는 여러 개의 동기화로 둘러싸일 수 있습니다.

    3장 객체 공유

    발췌

    1. 잠금의 의미는 상호 배제 동작에만 국한되지 않고 메모리 가시성도 포함됩니다. 모든 스레드가 공유 변수의 최신 값을 볼 수 있도록 하려면 읽기 또는 쓰기 작업을 수행하는 모든 스레드가 동일한 잠금에서 동기화되어야 합니다.

    2. Java 언어는 변수 업데이트 작업을 다른 스레드에 알릴 수 있도록 약간 약한 동기화 메커니즘, 즉 휘발성 변수를 제공합니다. 변수가 휘발성으로 선언되면 컴파일러와 런타임은 변수가 공유된다는 것을 인식하므로 변수에 대한 작업은 다른 메모리 작업과 함께 재정렬되지 않습니다. 휘발성 변수는 레지스터나 다른 프로세서에 보이지 않는 곳에 캐시되지 않으므로 휘발성 유형의 변수를 읽으면 항상 가장 최근에 작성된 값이 반환됩니다.

    3. 휘발성 변수에 액세스할 때는 잠금 작업이 수행되지 않으므로 실행 스레드가 차단되지 않습니다. 따라서 휘발성 변수는 동기화된 키워드보다 더 가벼운 동기화 메커니즘입니다.

    4. 휘발성 변수는 일반적으로 작업 완료, 중단 또는 상태 플래그를 나타내는 데 사용됩니다. 단 하나의 스레드만이 변수에 대한 쓰기 작업을 수행하도록 보장할 수 없는 한 휘발성의 의미 체계는 증가 작업(count++)의 원자성을 보장하기에 충분하지 않습니다.

    5. 잠금 메커니즘은 가시성과 원자성을 모두 보장할 수 있는 반면, 휘발성 변수는 가시성만 보장할 수 있습니다.

    6. 다음 조건이 모두 충족되는 경우에만 휘발성 변수를 사용해야 합니다.

    • 변수에 대한 쓰기 작업은 변수의 현재 값에 의존하지 않거나 단일 스레드는 변수 값을 업데이트합니다.

    • 이 변수는 다른 상태 변수와 함께 불변 조건에 포함되지 않습니다.

    • 이 변수에 액세스할 때는 잠금이 필요하지 않습니다.

  • 개체를 "게시"한다는 것은 개체를 현재 범위 밖의 코드에서 사용할 수 있도록 만드는 것을 의미합니다.

  • 공개하면 안되는 객체가 공개되었을 때 이런 상황을 Escape라고 합니다.

  • 건설 과정에서 이 단서가 빠져나가지 않도록 하세요.

  • 이벤트 리스너를 등록하거나 생성자에서 스레드를 시작하려는 경우 잘못된 생성을 방지하기 위해 전용 생성자와 공용 팩토리 메서드를 사용할 수 있습니다.

  • 스택 클로저는 스레드 클로저의 특별한 경우입니다. 스택 클로저에서는 로컬 변수를 통해서만 객체에 액세스할 수 있습니다.

  • 스레드 클로저를 유지하는 보다 표준화된 방법은 ThreadLocal을 사용하는 것입니다. 이 클래스는 스레드의 특정 값을 값을 보유하는 객체와 연결할 수 있습니다.

  • ThreadLocal 개체는 일반적으로 변경 가능한 단일 인스턴스 개체(싱글톤) 또는 전역 변수가 공유되는 것을 방지하는 데 사용됩니다.

  • 다음 조건이 충족되면 객체는 변경할 수 없습니다.

    • 객체가 생성된 후에는 객체의 상태를 수정할 수 없습니다.

    • 객체의 모든 필드는 최종 유형입니다.

    • 객체가 올바르게 생성되었습니다(이 참조는 객체 생성 중에 이스케이프되지 않았습니다).

  • 불변 객체는 스레드로부터 안전해야 합니다.

  • 객체를 안전하게 게시하려면 객체의 참조와 객체의 상태가 동시에 다른 스레드에 표시되어야 합니다. 적절하게 구성된 객체는 다음을 통해 안전하게 해제될 수 있습니다.

    • 정적 초기화 함수에서 객체 참조를 초기화합니다.

    • 객체의 참조를 휘발성 유형 필드 또는 AtomicReferance 객체에 저장하세요.

    • 객체 참조를 올바르게 구성된 객체의 최종 유형 필드에 저장하세요.

    • 객체에 대한 참조를 자물쇠로 보호되는 필드에 저장하세요.

  • 안전하게 게시된 사실상 불변 객체는 추가 동기화 없이 모든 스레드에서 안전하게 사용할 수 있습니다.

  • 객체의 게시 요구 사항은 해당 변경 가능성에 따라 다릅니다.

    • 불변 객체는 모든 메커니즘으로 게시될 수 있습니다.

    • 사실 불변 객체는 안전한 방법으로 게시되어야 합니다.

    • 변경 가능한 객체는 안전한 방법으로 해제되어야 하며 스레드로부터 안전하거나 잠금으로 보호되어야 합니다.

  • 다음을 포함하여 동시 프로그램에서 객체를 사용하고 공유할 때 사용할 수 있는 몇 가지 실용적인 전략이 있습니다.

    • 스레드 제한. 스레드로 둘러싸인 개체는 하나의 스레드만 소유할 수 있고 개체는 해당 스레드에 포함되어 있으며 이 스레드에 의해서만 수정될 수 있습니다.

    • 읽기 전용 공유. 추가 동기화 없이 공유 읽기 전용 개체는 여러 스레드에서 동시에 액세스할 수 있지만 어떤 스레드도 이를 수정할 수 없습니다. 공유된 읽기 전용 객체에는 불변 객체와 사실상 불변 객체가 포함됩니다.

    • 스레드로부터 안전한 공유. 스레드로부터 안전한 개체는 내부적으로 동기화되므로 여러 스레드가 추가 동기화 없이 개체의 공용 인터페이스를 통해 해당 개체에 액세스할 수 있습니다.

    • 보호된 개체. 보호된 개체는 특정 잠금을 보유해야만 액세스할 수 있습니다. 보호되는 객체에는 다른 스레드로부터 안전한 객체에 캡슐화된 객체뿐만 아니라 특정 잠금으로 해제되고 보호되는 객체도 포함됩니다.

    Experience

    1. 릴리스 및 이스케이프 이해: 이는 클래스의 멤버 변수 또는 객체를 다른 클래스에서 참조하고 사용할 수 있음을 의미합니다(예: static으로 수정된 정적 변수 또는 현재 호출 메서드 객체). Escape는 여러 스레드에서 참조해서는 안되는 멤버 변수나 객체가 노출되어 참조되어 해당 값이 잘못 수정되는 문제를 말합니다. 한마디로, 클래스와 내부적으로 사용되는 멤버 변수 및 메소드의 범위를 확장하지 마십시오. 이는 포장이 고려해야 할 문제이기도 합니다.

    2. 이 탈출: 즉, 이 개체를 참조하기 위해 생성자의 내부 클래스에서 다른 스레드가 시작되지만 개체가 아직 생성되지 않았으므로 예기치 않은 오류가 발생할 수 있습니다. 해결 방법은 팩토리 메서드를 만든 다음 생성자를 비공개로 만드는 것입니다.

    3. final로 수정된 멤버 변수는 생성자에서 초기화되어야 합니다. 그렇지 않으면 개체가 인스턴스화된 후 멤버 변수에 값을 할당할 수 없습니다. final로 수정되는 멤버변수가 객체를 참조하는 경우 객체의 주소는 수정이 불가능하지만, 객체의 값은 수정이 가능하다.

    4. 클래스 A의 클래스 B에 대한 참조와 같이 객체를 안전하게 게시하는 네 가지 방법 이해:

    • A의 정적 초기화 방법(예: public static A a = new A(b) like) this 정적 팩토리 클래스에서는 B가 참조될 때 B가 초기화됩니다.

    • 클래스 A의 B 멤버 변수는 휘발성 b 또는 AtomicReferance b로 수정됩니다.

    • 클래스 A의 B 멤버 변수는 최종 Bb로 이렇게 수정됩니다.

    • 클래스 A의 메소드가 B를 사용하는 경우 동기화(잠금){B...}로 둘러싸여 있습니다.

  • 불변 객체에 대한 간단한 이해는 기술적으로는 변경 가능하지만 비즈니스 로직 처리 중에 수정되지 않는다는 것입니다.

  • 관련 권장 사항:

    Java의 완전한 스레드 및 공유 리소스

    java 스레드 안전 및 불변

    위 내용은 JAVA 동시 프로그래밍 요약: 스레드 안전성, 객체 공유의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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