자바 다 중 스 레 드 - 잠 금 상세 해석 및 예제 코드

6963 단어
자바 5 부터 자바 util. concurrent. locks 패키지 에는 자물쇠 의 실현 이 포함 되 어 있 기 때문에 자 물 쇠 를 실현 할 필요 가 없습니다.하지만 이 자 물 쇠 를 어떻게 사용 하 는 지 알 아야 한다.
간단 한 자물쇠
자바 의 동기 화 블록 부터 시작 합 니 다:

public class Counter{
  private int count = 0;

  public int inc(){
    synchronized(this){
      return ++count;
    }
  }
}


inc () 방법 에 synchronized (this) 코드 블록 이 있 는 것 을 볼 수 있 습 니 다.이 코드 블록 은 같은 시간 에 하나의 스 레 드 만 return + count 를 실행 할 수 있 도록 보장 합 니 다.synchronized 의 동기 화 블록 에 있 는 코드 는 더욱 복잡 할 수 있 지만 + count 라 는 간단 한 조작 은 스 레 드 동기 화 의 미 를 충분히 표현 할 수 있 습 니 다.
아래 의 Counter 클래스 는 synchronized 대신 Lock 로 같은 목적 을 달성 했다.

public class Counter{
  private Lock lock = new Lock();
  private int count = 0;

  public int inc(){
    lock.lock();
    int newCount = ++count;
    lock.unlock();
    return newCount;
  }
}


lock () 방법 은 Lock 인 스 턴 스 대상 에 자 물 쇠 를 추가 하기 때문에 이 대상 에 대해 lock () 방법 을 호출 하 는 모든 스 레 드 가 막 힐 것 입 니 다. 이 Lock 대상 의 unlock () 방법 이 호출 될 때 까지.
여기에 Lock 류 의 간단 한 실현 이 있 습 니 다.

public class Counter{
public class Lock{
  private boolean isLocked = false;

  public synchronized void lock()
    throws InterruptedException{
    while(isLocked){
      wait();
    }
    isLocked = true;
  }

  public synchronized void unlock(){
    isLocked = false;
    notify();
  }
}


while (isLocked) 순환 에 주의 하 세 요. '자전 자물쇠' 라 고도 부 릅 니 다.isLocked 가 true 일 때 lock () 을 호출 하 는 스 레 드 는 wait () 호출 에서 차단 되 어 기 다 립 니 다.이 스 레 드 가 notify () 호출 을 받 지 못 하고 wait () 에서 되 돌아 오 는 것 을 방지 하기 위해 서 이 스 레 드 는 isLocked 조건 을 다시 검사 하여 현재 안전하게 계속 실행 할 수 있 는 지, 아니면 다시 기 다 려 야 하 는 지 를 결정 합 니 다. 스 레 드 가 깨 어 나 면 안전하게 계속 실행 할 수 있다 고 생각 하 는 것 이 아 닙 니 다.isLocked 가 false 라면 현재 스 레 드 는 while (isLocked) 순환 을 종료 하고 isLocked 를 true 로 설정 하여 lock () 방법 을 호출 하고 있 는 다른 스 레 드 가 Lock 인 스 턴 스 에 자 물 쇠 를 추가 할 수 있 도록 합 니 다.
스 레 드 가 임계 구역 (lock () 과 unlock () 사이 에 있 는 코드 를 완성 하면 unlock () 을 호출 합 니 다.unlock () 을 실행 하면 isLocked 를 false 로 다시 설정 하고 그 중 하 나 를 (있 으 면) lock () 방법 에서 wait () 함 수 를 호출 하여 대기 상태 에 있 는 스 레 드 를 알 립 니 다.
자물쇠 의 재 입 성
자바 의 synchronized 동기 화 블록 은 다시 들 어 갈 수 있 습 니 다.이것 은 자바 스 레 드 가 코드 에 있 는 synchronized 동기 화 블록 에 들 어가 서 이 동기 화 블록 이 사용 하 는 동기 화 대상 에 대응 하 는 파이프 의 자 물 쇠 를 얻 었 다 면 이 스 레 드 는 같은 파이프 대상 이 동기 화 하 는 다른 자바 코드 블록 에 들 어 갈 수 있 음 을 의미 합 니 다.다음은 하나의 예 이다.

public class Reentrant{
  public synchronized outer(){
    inner();
  }

  public synchronized inner(){
    //do something
  }
}


outer () 와 inner () 는 모두 synchronized 로 밝 혀 졌 습 니 다. 이것 은 자바 에서 synchronized (this) 블록 과 같은 효 과 를 가 집 니 다.하나의 스 레 드 가 outer () 를 호출 하면 outer () 에서 inner () 를 호출 하 는 데 문제 가 없습니다. 이 두 가지 방법 (코드 블록) 은 모두 같은 관리 대상 이기 때 문 입 니 다.("this") 와 동기 화 됩 니 다. 하나의 스 레 드 가 하나의 스 레 드 대상 에 있 는 자 물 쇠 를 가지 고 있다 면, 이 스 레 드 대상 에 의 해 동기 화 된 모든 코드 블록 에 접근 할 수 있 습 니 다. 이것 은 다시 들 어 갈 수 있 습 니 다. 스 레 드 는 이미 가지 고 있 는 자물쇠 와 동기 화 된 코드 블록 에 들 어 갈 수 있 습 니 다.
앞에서 제시 한 자 물 쇠 는 다시 들 어 갈 수 있 는 것 이 아 닙 니 다. 아래 와 같이 Reentrant 류 를 다시 쓰 면 스 레 드 가 outer () 를 호출 할 때 inner () 방법의 lock. lock () 에서 막 힙 니 다.

public class Reentrant2{
  Lock lock = new Lock();

  public outer(){
    lock.lock();
    inner();
    lock.unlock();
  }

  public synchronized inner(){
    lock.lock();
    //do something
    lock.unlock();
  }
}


outer () 를 호출 하 는 스 레 드 는 먼저 Lock 인 스 턴 스 를 잠 그 고 inner () 를 계속 호출 합 니 다. inner () 방법 에서 이 스 레 드 는 Lock 인 스 턴 스 를 다시 잠 그 려 고 시도 합 니 다. 그 결과 이 동작 은 실패 합 니 다 (즉, 이 스 레 드 가 막 힐 것 입 니 다). 이 Lock 인 스 턴 스 는 이미 outer () 방법 에서 잠 겨 있 기 때 문 입 니 다.
두 번 째 lock () 사이 에 unlock () 을 호출 하지 않 으 면 두 번 째 lock 호출 이 막 히 고 lock () 이 실현 되 는 것 을 보면 원인 이 뚜렷 하 다.

public class Lock{
  boolean isLocked = false;

  public synchronized void lock()
    throws InterruptedException{
    while(isLocked){
      wait();
    }
    isLocked = true;
  }

  ...
}


하나의 스 레 드 가 lock () 을 종료 할 수 있 는 지 여 부 는 while 순환 (자 회전 자물쇠) 의 조건 에 의 해 결 정 됩 니 다. 현재 판단 조건 은 isLocked 가 false 일 때 만 lock 작업 이 허용 되 며, 어떤 스 레 드 가 잠 겨 있 는 지 는 고려 하지 않 습 니 다.
이 Lock 류 가 다시 들 어 갈 수 있 도록 작은 변경 이 필요 합 니 다.

public class Lock{
  boolean isLocked = false;
  Thread lockedBy = null;
  int lockedCount = 0;

  public synchronized void lock()
    throws InterruptedException{
    Thread callingThread =
      Thread.currentThread();
    while(isLocked && lockedBy != callingThread){
      wait();
    }
    isLocked = true;
    lockedCount++;
    lockedBy = callingThread;
 }

  public synchronized void unlock(){
    if(Thread.curentThread() ==
      this.lockedBy){
      lockedCount--;

      if(lockedCount == 0){
        isLocked = false;
        notify();
      }
    }
  }

  ...
}


현재 while 순환 (자동 잠 금) 도 이 Lock 인 스 턴 스 가 잠 겨 있 는 스 레 드 를 고려 하고 있 습 니 다. 현재 잠 금 대상 이 잠 겨 있 지 않 거나 (isLocked = false) 현재 호출 스 레 드 가 잠 겨 있 지 않 으 면 while 순환 이 실행 되 지 않 습 니 다. lock () 스 레 드 를 호출 하면 이 방법 을 종료 할 수 있 습 니 다.현재 의미 에서 wait () 를 호출 하지 않 아 차단 되 는 것 을 말한다.
이 외 에 도 같은 스 레 드 에서 잠 금 대상 에 게 잠 금 을 추가 하 는 횟수 를 기록 해 야 합 니 다. 그렇지 않 으 면 unblock () 호출 이 한 번 에 전체 잠 금 을 해제 합 니 다. 현재 잠 금 이 여러 번 추가 되 었 더 라 도 unlock () 호출 이 lock () 호출 횟수 에 미 치지 못 하기 전에 잠 금 이 해제 되 기 를 원 하지 않 습 니 다.
이제 이 Lock 류 는 다시 들 어 갈 수 있 습 니 다.
자물쇠 의 형 평성
자바 의 synchronized 블록 은 스 레 드 에 들 어 가 려 는 순 서 를 보장 하지 않 습 니 다. 따라서 여러 스 레 드 가 같은 synchronized 동기 화 블록 을 계속 경쟁 하면 하나의 위험 이 존재 합 니 다. 그 중 하나 또는 여러 스 레 드 는 영원히 접근 권 을 얻 지 못 합 니 다. 즉, 방문 권 은 항상 다른 스 레 드 에 분 배 됩 니 다. 이러한 상황 을 스 레 드 배 고 픔 이 라 고 합 니 다. 이 를 피하 기 위해 서 입 니 다.문 제 는 자물쇠 가 공정 성 을 실현 해 야 한다. 본 고 에서 보 여 준 자 물 쇠 는 내부 에서 synchronized 동기 화 블록 으로 이 루어 지기 때문에 공정 성 을 보장 하지 않 는 다.
finally 구문 에서 unlock () 을 호출 합 니 다.
Lock 으로 임계 구역 을 보호 하고 임계 구역 에 이상 이 생 길 수 있다 면 finally 구문 에서 unlock () 을 호출 하 는 것 이 중요 합 니 다. 이 잠 금 대상 이 다른 스 레 드 가 계속 잠 금 을 추가 할 수 있 도록 잠 금 을 풀 수 있 도록 해 줍 니 다. 다음은 예시 입 니 다.

lock.lock();
try{
  //do critical section code,
  //which may throw exception
} finally {
  lock.unlock();
}

이 간단 한 구 조 는 임계 구역 에서 이상 을 던 졌 을 때 Lock 대상 이 잠 겨 있 는 것 을 보증 합 니 다. finally 구문 에서 호출 된 unlock () 이 아니라면 임계 구역 에서 이상 을 던 졌 을 때 Lock 대상 은 잠 겨 있 는 상태 에 영원히 머 물 러 있 습 니 다. 이 Lock 대상 에서 lock () 을 호출 하 는 다른 모든 스 레 드 가 계속 막 힐 수 있 습 니 다.
이상 은 자바 다 중 스 레 드 잠 금 에 관 한 자료 정리 입 니 다. 추 후 관련 자 료 를 계속 보충 하 겠 습 니 다. 본 사이트 에 대한 지원 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기