java 병발(21) 분석 동기화기

8102 단어 java 병발
많은 동기화기(예를 들어 자물쇠, 신호량, 차단 대기열 등)의 기능은 각각 다르지만 그들의 내부 설계는 차이가 크지 않다.다시 말하면 그들 내부의 기초 부분은 같거나 비슷하다.
대부분의 동기화기는 특정한 구역 (임계 구역) 을 보호하는 데 사용되는 코드로, 이 코드들은 여러 라인에 동시에 접근할 수 있다.이 목표를 달성하려면 동기화기는 일반적으로 다음과 같은 기능을 지원해야 한다.
  • 상태
  • 액세스 조건
  • 상태 변화
  • 알림 정책
  • Test-and-set 방법
  • Set 방법
  • 모든 동기화기가 상술한 부분을 포함하는 것은 아니며, 일부는 위의 내용을 완전히 따르지 않는다.그러나 보통 너는 그 중에서 이 부분의 하나 또는 여러 개를 발견할 수 있다.
    컨디션
    동기화기의 상태는 어떤 라인에 접근 권한이 있는지 확인하는 데 사용됩니다.Lock에서 상태는 boolean 유형이며 현재 Lock 객체가 잠겨 있는지 여부를 나타냅니다.BoundedSemaphore에서 내부 상태는 카운터 (int 형식) 와 상한 (int 형식) 을 포함하며, 각각 현재 얻은 허가수와 최대 얻은 허가수를 표시합니다.BlockingQueue의 상태는 대기열의 요소 목록과 대기열의 최대 용량입니다.
    다음은 Lock과 BoundedSemaphore의 두 코드 세그먼트입니다.
    public class Lock{
      //state is kept here
      private boolean isLocked = false;
      public synchronized void lock()
      throws InterruptedException{
        while(isLocked){
          wait();
        }
        isLocked = true;
      }
      ...
    }
    public class BoundedSemaphore {
      //state is kept here
      private int signals = 0;
      private int bound   = 0;
      public BoundedSemaphore(int upperBound){
        this.bound = upperBound;
      }
      public synchronized void take() throws InterruptedException{
        while(this.signals == bound) wait();
        this.signal++;
        this.notify();
      }
      ...
    }

    액세스 조건
    액세스 조건은test-and-set-state 방법을 호출하는 라인이 상태를 설정할 수 있는지 여부를 결정합니다.액세스 조건은 일반적으로 동기화기 상태를 기반으로 합니다.거짓 깨우침을 피하기 위해 보통while 순환에 넣는다.접근 조건의 계산 결과는true 또는false입니다.
    Lock의 액세스 조건은 isLocked의 값만 간단하게 검사합니다.Bounded Semaphore에서 실제로 두 가지 액세스 조건이 있는 것은 실행 중인 동작이 가져오기 또는 해제 여부에 따라 달라집니다.만약 어떤 라인이 허가를 얻으려면signals 변수가 상한선에 도달했는지 검사합니다.만약 어떤 라인이 허가를 풀려고 한다면,signals 변수가 0인지 확인합니다.
    Lock과 Bounded Semaphore에서 온 두 개의 코드 세션이 있는데, 모두 접근 조건이 있습니다.조건이while 순환에서 어떻게 검사되는지 주의해서 관찰하세요.
    public class Lock{
      private boolean isLocked = false;
      public synchronized void lock()
      throws InterruptedException{
        //access condition
        while(isLocked){
          wait();
        }
        isLocked = true;
      }
      ...
    }
    public class BoundedSemaphore {
      private int signals = 0;
      private int bound = 0;
      public BoundedSemaphore(int upperBound){
        this.bound = upperBound;
      }
      public synchronized void take() throws InterruptedException{
        //access condition
        while(this.signals == bound) wait();
        this.signals++;
        this.notify();
      }
      public synchronized void release() throws InterruptedException{
        //access condition
        while(this.signals == 0) wait();
        this.signals--;
        this.notify();
      }
    }

    상태 변화
    일단 한 라인이 임계 구역에 접근할 수 있는 권한을 얻으면, 동기화기의 상태를 바꾸어 다른 라인이 임계 구역에 들어가는 것을 막아야 한다.다시 말하면, 이 상태는 임계 구역에 라인이 실행 중인 코드를 나타낸다.다른 라인이 임계 구역에 접근하려고 할 때, 이 상태는 접근 조건의 결과에 영향을 주어야 한다.
    Lock에서 isLocked=true를 코드로 설정하여 상태를 변경합니다. 신호량에서 상태를 바꾸는 것은signals – 또는signals++입니다.
    여기에는 두 개의 상태 변화 코드 세션이 있습니다.
    public class Lock{
      private boolean isLocked = false;
      public synchronized void lock()
      throws InterruptedException{
        while(isLocked){
          wait();
        }
        //state change
        isLocked = true;
      }
      public synchronized void unlock(){
        //state change
        isLocked = false;
        notify();
      }
    }
    public class BoundedSemaphore {
      private int signals = 0;
      private int bound   = 0;
      public BoundedSemaphore(int upperBound){
        this.bound = upperBound;
      }
      public synchronized void take() throws InterruptedException{
        while(this.signals == bound) wait();
        //state change
        this.signals++;
        this.notify();
      }
      public synchronized void release() throws InterruptedException{
        while(this.signals == 0) wait();
        //state change
        this.signals--;
        this.notify();
      }
    }

    알림 정책
    일단 어떤 스레드가 동기화기의 상태를 바꾸면 다른 대기 스레드의 상태가 바뀌었다는 것을 알려야 할 수도 있습니다.이 상태의 변화가 다른 라인의 접근 조건을true로 바꿀 수도 있기 때문이다.
    일반적으로 공지 정책은
  • 모든 대기 스레드 알림
  • N개의 대기 스레드 중 임의의 알림
  • N개의 대기 스레드 중 지정된 스레드 알림
  • 모든 대기 라인을 알리는 것은 매우 간단하다.모든 기다리는 루틴은 같은 대상의wait () 방법을 사용합니다. 어떤 루틴은 이 대상에서notifyAll () 방법을 호출하기만 하면 알립니다.
    알림 대기 루트 중 임의의 것도 간단합니다. notify All () 호출을 notify () 로 바꾸면 됩니다.notify 방법을 사용하면 깨어난 라인이 어떤 라인인지 확인할 수 없습니다. 즉, '대기 라인 중 임의의 라인' 입니다.
    때때로 임의의 대기 라인이 아닌 지정한 라인을 알려야 할 수도 있습니다.예를 들어, 만약 라인이 통지되는 순서가 동기화 블록에 들어가는 순서와 일치하도록 보장하거나, 어떤 우선순위의 순서에 따라 통지하려고 한다면.이러한 요구를 실현하려면 모든 대기 라인은 자신의 대상에서wait () 를 호출해야 한다.알림 루틴이 특정한 대기 루틴을 알릴 때, 이 루틴의 자체 대상인 notify () 방법을 사용하면 됩니다.배고픔과 공평함에는 이런 예가 있다.
    다음은 공지 정책의 예입니다(대기 스레드를 임의로 공지).
    public class Lock{
      private boolean isLocked = false;
      public synchronized void lock()
      throws InterruptedException{
        while(isLocked){
          //wait strategy - related to notification strategy
          wait();
        }
        isLocked = true;
      }
      public synchronized void unlock(){
        isLocked = false;
        notify(); //notification strategy
      }
    }

    Test-and-set 방법
    동기화기에서 가장 흔히 볼 수 있는 방법은 두 가지가 있는데 테스트-and-set이 첫 번째(set은 다른 것이다).Test-and-set은 이 방법을 호출한 루틴이 접근 조건을 검사한다는 뜻입니다. 만약 만족한다면, 이 루틴은 동기화기의 내부 상태를 설정해서 접근 권한을 얻었다는 것을 나타냅니다.
    상태의 변화는 일반적으로 접근 권한을 얻으려는 다른 라인의 조건 상태를 계산할 때false의 결과를 얻지만, 반드시 그렇지는 않습니다.예를 들어 읽기 자물쇠에서 읽기 자물쇠를 가져오는 루틴은 읽기 자물쇠의 상태를 업데이트해서 읽기 자물쇠를 가져오는 것을 표시하지만, 루틴이 없으면 다른 읽기 자물쇠를 요청하는 루틴도 성공할 수 있다.
    테스트-and-set은 원자가 필요합니다. 즉, 어떤 라인이 상태를 검사하고 설정하는 동안 테스트-and-set 방법에서 다른 라인이 실행되는 것을 허용하지 않습니다.
    test-and-set 메서드의 프로그램 흐름은 일반적으로 다음 순서를 따릅니다.
    필요한 경우 검사 전에 상태 설정
    액세스 조건 확인
    액세스 조건이 충족되지 않으면 대기 중
    액세스 조건이 충족되면 상태를 설정하고 필요할 경우 대기 라인에 통지합니다
    다음 ReadWriteLock 클래스의 lockWrite () 방법은test-and-set 방법을 보여 줍니다.lockWrite () 를 호출하는 루틴은 검사하기 전에 상태 (writeRequests++) 를 설정합니다.그런 다음 canGrantWriteAccess()에서 액세스 조건을 확인하고 체크가 통과되면 메소드를 종료하기 전에 내부 상태를 다시 설정합니다.이 방법에는 대기 라인을 알리지 않았다.
    public class ReadWriteLock{
        private Map<Thread, Integer> readingThreads = new HashMap<Thread, Integer>();
        private int writeAccesses    = 0;
        private int writeRequests    = 0;
        private Thread writingThread = null;
        ...
        public synchronized void lockWrite() throws InterruptedException{
          writeRequests++;
          Thread callingThread = Thread.currentThread();
          while(! canGrantWriteAccess(callingThread)){
            wait();
          }
          writeRequests--;
          writeAccesses++;
          writingThread = callingThread;
        }
        ...
    }

    다음 BoundedSemaphore 클래스에는 두 가지test-and-set 방법이 있습니다:take ()와release ().두 방법 모두 내부 상태를 검사하고 설정하는 것이 있다.
    소스 코드 인쇄 도움말 보기
    public class BoundedSemaphore {
      private int signals = 0;
      private int bound   = 0;
      public BoundedSemaphore(int upperBound){
        this.bound = upperBound;
      }
      public synchronized void take() throws InterruptedException{
        while(this.signals == bound) wait();
        this.signals++;
        this.notify();
      }
      public synchronized void release() throws InterruptedException{
        while(this.signals == 0) wait();
        this.signals--;
        this.notify();
      }
    }

    set 메서드
    set 방법은 동기화기에서 흔히 볼 수 있는 두 번째 방법이다.set 방법은 동기화기의 내부 상태를 설정하는 것일 뿐 검사를 먼저 하지 않습니다.set 메서드의 대표적인 예는 Lock 클래스의 unlock() 메서드입니다.자물쇠를 가지고 있는 어떤 라인은 항상 잠금 해제에 성공할 수 있으며, 이 자물쇠가 잠금 해제 상태에 있는지 검사할 필요가 없다.
    set 메서드의 프로그램 흐름은 일반적으로 다음과 같습니다.
    내부 상태 설정
    대기 스레드 알림
    다음은 unlock() 방법의 한 예입니다.
    public class Lock{
      private boolean isLocked = false;
      public synchronized void unlock(){
        isLocked = false;
        notify();
      }
    }

    좋은 웹페이지 즐겨찾기