CodeGym/Java Course/모듈 3/다중 스레드 패턴

다중 스레드 패턴

사용 가능

3.1 활성 객체

활성 개체는 메서드의 실행 스레드를 호출된 스레드와 분리하는 디자인 패턴입니다. 이 패턴의 목적은 비동기 메서드 호출 및 요청 처리 스케줄러를 사용하여 병렬 실행을 제공하는 것입니다.

단순화된 버전:

활성 객체

클래식 변형:

활성 개체 2

이 템플릿에는 6개의 요소가 있습니다.

  • 클라이언트의 공용 메서드에 대한 인터페이스를 제공하는 프록시 개체입니다.
  • 활성 개체에 대한 액세스 방법을 정의하는 인터페이스입니다.
  • 클라이언트로부터 들어오는 요청 목록입니다.
  • 쿼리가 실행되는 순서를 결정하는 스케줄러입니다.
  • 활성 개체 메서드의 구현.
  • 클라이언트가 결과를 수신하기 위한 콜백 프로시저 또는 변수입니다.

3.2 잠금

잠금 패턴은 여러 스레드 간에 공유 리소스에 대한 독점 액세스를 허용하는 동기화 메커니즘입니다. 잠금은 동시성 제어 정책을 적용하는 한 가지 방법입니다.

기본적으로 각 스레드가 해당 공유 리소스에 액세스하기 전에 "잠금 획득"을 시도한다는 가정하에 소프트 잠금이 사용됩니다.

그러나 일부 시스템에서는 필수 잠금 메커니즘을 제공하여 잠긴 리소스에 대한 무단 액세스 시도가 액세스를 시도한 스레드에서 예외를 발생시켜 중단됩니다.

세마포어 는 가장 간단한 잠금 유형입니다. 데이터 액세스 측면에서 공유(읽기 전용) 또는 배타적(읽기-쓰기) 액세스 모드 사이에 구분이 없습니다. 공유 모드에서 여러 스레드는 읽기 전용 모드에서 데이터에 액세스하기 위해 잠금을 요청할 수 있습니다. 독점 액세스 모드는 업데이트 및 삭제 알고리즘에도 사용됩니다.

잠금 패턴

잠금 유형은 스레드 실행의 연속을 차단하는 전략으로 구별됩니다. 대부분의 구현에서 잠금 요청은 잠긴 리소스를 사용할 수 있을 때까지 스레드가 계속 실행되지 않도록 합니다.

spinlock은 액세스가 허용될 때까지 루프에서 대기하는 잠금입니다. 이러한 잠금은 스레드가 짧은 시간 동안 잠금을 대기하는 경우 매우 효율적이므로 스레드의 과도한 재스케줄링을 피할 수 있습니다. 스레드 중 하나가 오랫동안 잠금을 유지하는 경우 액세스 대기 비용이 상당합니다.

잠금 패턴 2

잠금 메커니즘을 효과적으로 구현하려면 하드웨어 수준의 지원이 필요합니다. 하드웨어 지원은 "test-and-set", "fetch-and-add" 또는 "compare-and-swap"과 같은 하나 이상의 원자적 작업으로 구현될 수 있습니다. 이러한 지침을 사용하면 잠금이 해제되었는지 중단 없이 확인할 수 있으며, 그렇다면 잠금을 획득할 수 있습니다.

3.3 모니터

모니터 패턴은 공유 리소스에 대한 액세스를 제공하는 높은 수준의 프로세스 상호 작용 및 동기화 메커니즘입니다. 일반적으로 하드웨어 또는 변수 집합과 같은 공통 리소스를 사용하여 두 개 이상의 컴퓨터 작업을 동기화하는 접근 방식입니다.

모니터 기반 멀티태스킹에서 컴파일러 또는 인터프리터는 프로그래머에게 투명하게 적절하게 형식이 지정된 루틴에 잠금 해제 코드를 투명하게 삽입하여 프로그래머가 명시적으로 동기화 프리미티브를 호출하지 않도록 합니다.

모니터는 다음으로 구성됩니다.

  • 공유 리소스와 상호 작용하는 일련의 절차
  • 뮤텍스
  • 이 리소스와 관련된 변수
  • 경쟁 조건을 피하기 위한 조건을 정의하는 불변

모니터 프로시저는 작업을 시작하기 전에 뮤텍스를 획득하고 프로시저가 종료되거나 특정 조건이 대기될 때까지 이를 보유합니다. 각 프로시저가 뮤텍스를 해제하기 전에 불변이 참임을 보장하면 어떤 태스크도 경쟁 조건에서 리소스를 획득할 수 없습니다.

이것은 동기화된wait() 연산자가 및 메서드를 사용하여 Java에서 작동하는 방식입니다 notify().

3.4 이중 확인 잠금

이중 확인 잠금은 잠금을 얻는 오버헤드를 줄이기 위한 병렬 디자인 패턴입니다.

먼저 동기화 없이 차단 조건을 확인합니다. 스레드는 확인 결과 잠금을 획득해야 한다고 표시되는 경우에만 잠금을 획득하려고 시도합니다.

//Double-Checked Locking
public final class Singleton {
private static Singleton instance; //Don't forget volatile modifier

public static Singleton getInstance() {
     if (instance == null) {                //Read

         synchronized (Singleton.class) {    //
             if (instance == null) {         //Read Write
                 instance = new Singleton(); //
             }
         }
     }
 }

스레드로부터 안전한 환경에서 싱글톤 객체를 생성하는 방법은 무엇입니까?

public static Singleton getInstance() {
   if (instance == null)
    instance = new Singleton();
}

다른 스레드에서 Singleton 개체를 만드는 경우 여러 개체가 동시에 생성되는 상황이 있을 수 있으며 이는 허용되지 않습니다. 따라서 개체 생성을 동기화된 문으로 래핑하는 것이 합리적입니다.

public static Singleton getInstance() {
    synchronized (Singleton.class) {
        if (instance == null)
        instance = new Singleton();
    }
}

이 접근 방식은 효과가 있지만 작은 단점이 있습니다. 객체가 생성된 후 향후 가져오려고 할 때마다 동기화된 블록에서 검사가 수행됩니다. 즉, 현재 스레드와 연결된 모든 항목이 잠깁니다. 따라서 이 코드는 약간 최적화될 수 있습니다.

public static Singleton getInstance() {
     if (instance != null)
        return instance;

    synchronized (Singleton.class) {
        if (instance == null)
        instance = new Singleton();
    }
}

일부 언어 및/또는 일부 시스템에서는 이 패턴을 안전하게 구현하는 것이 불가능합니다. 따라서 안티 패턴이라고도 합니다. 이러한 기능으로 인해 Java 메모리 모델 및 C++ 메모리 모델에서 "이전에 발생"하는 엄격한 순서 관계가 나타납니다.

일반적으로 Singleton 디자인 패턴과 같은 다중 스레드 프로그램에서 지연 초기화를 구현하는 오버헤드를 줄이는 데 사용됩니다. 변수의 지연 초기화에서는 변수 값이 계산에 필요할 때까지 초기화가 지연됩니다.

3.5 스케줄러

스케줄러는 스케줄링 정책을 구현하기 위한 메커니즘을 제공하지만 특정 정책과는 독립적인 병렬 설계 패턴입니다. 대기 중인 스레드의 시퀀스를 명시적으로 지정하는 개체를 사용하여 스레드가 순차적 코드를 실행해야 하는 순서를 제어합니다.

1
과제
모듈 3,  레벨 17레슨 2
잠금
Trust, but Verify
task4123
코멘트
  • 인기
  • 신규
  • 이전
코멘트를 남기려면 로그인 해야 합니다
이 페이지에는 아직 코멘트가 없습니다