[java] 동기화 된 (this)을 사용할 수 있다면 왜 ReentrantLock을 사용합니까?

동시성 잠금이 중요한 이유를 이해하려고합니다 synchronized (this). 아래의 더미 코드에서 다음 중 하나를 수행 할 수 있습니다.

  1. 전체 방법을 동기화하거나 취약한 영역을 동기화합니다 ( synchronized(this){...})
  2. 또는 ReentrantLock으로 취약한 코드 영역을 잠그십시오.

암호:

    private final ReentrantLock lock = new ReentrantLock();
    private static List<Integer> ints;

    public Integer getResult(String name) {
        .
        .
        .
        lock.lock();
        try {
            if (ints.size()==3) {
                ints=null;
                return -9;
            }

            for (int x=0; x<ints.size(); x++) {
                System.out.println("["+name+"] "+x+"/"+ints.size()+". values >>>>"+ints.get(x));
            }

        } finally {
            lock.unlock();
        }
        return random;
}



답변

ReentrantLock와는 이다 구조화 달리, synchronized구조 – 즉, 당신이 잠금에 대한 블록 구조를 사용할 필요가 없습니다, 심지어 방법에서 잠금을 보유 할 수 있습니다. 예를 들면 :

private ReentrantLock lock;

public void foo() {
  ...
  lock.lock();
  ...
}

public void bar() {
  ...
  lock.unlock();
  ...
}

이러한 흐름은 synchronized구조 에서 단일 모니터를 통해 표현할 수 없습니다 .


그 외에, ReentrantLock지원은 폴링 잠금인터럽트 잠금 대기 지원하는 타임 아웃 . ReentrantLock또한 구성 가능한 공정성 정책 을 지원 하므로보다 유연한 스레드 스케줄링이 가능합니다.

이 클래스의 생성자는 선택적 공정성 매개 변수를 승인합니다 . 로 설정하면 true경합 상태에서 잠금이 가장 오래 기다리는 스레드에 대한 액세스 권한을 부여합니다. 그렇지 않으면이 잠금은 특정 액세스 순서를 보장하지 않습니다. 많은 스레드가 액세스하는 페어 잠금을 사용하는 프로그램은 기본 설정을 사용하는 프로그램보다 전체 처리량이 낮을 수 있습니다 (즉, 느리지 만 종종 훨씬 느림). 그러나 잠금을 획득하고 기아 부족을 보장하기 위해 시간의 차이가 더 작습니다. 그러나 잠금의 공정성이 스레드 스케줄링의 공정성을 보장하지는 않습니다. 따라서 페어 잠금을 사용하는 많은 스레드 중 하나가 여러 번 스레드를 연속해서 얻을 수 있지만 다른 활성 스레드는 진행되지 않고 현재 잠금을 유지하지 않습니다. 또한 시간 제한이 없습니다tryLock방법은 공정성 설정을 존중하지 않습니다. 다른 스레드가 대기중인 경우에도 잠금을 사용할 수 있으면 성공합니다.


ReentrantLock 높은 확장 성으로 인해 더 높은 경합에서 더 나은 성능을 발휘할 수도 있습니다 . 이에 대한 자세한 내용은 여기를 참조 하십시오 .

그러나이 주장은 논쟁의 여지가있다. 다음 주석을 참조하십시오.

재진입 잠금 테스트에서 매번 새 잠금이 작성되므로 독점 잠금이없고 결과 데이터가 유효하지 않습니다. 또한 IBM 링크는 기본 벤치 마크에 대한 소스 코드를 제공하지 않으므로 테스트가 올바르게 수행되었는지 여부를 특성화 할 수 없습니다.


언제 ReentrantLocks 를 사용해야 합니까? 그 developerWorks 기사에 따르면 …

대답은 매우 간단합니다. 실제로 synchronized시간 초과 잠금 대기, 인터럽트 가능 잠금 대기, 비 블록 구조 잠금, 다중 조건 변수 또는 잠금 폴링과 같이 제공 하지 않는 것이 필요할 때 사용하십시오 . ReentrantLock또한 확장 성 이점이 있으므로 실제로 경합이 많은 상황이있는 경우 사용해야합니다. 그러나 대부분의 synchronized블록은 경합이 아닌 경합이 거의 없습니다. 사용하는 경우 단순히 “성능이 더 나을 것”이라고 가정하는 대신 동기화가 부적절하다고 입증 될 때까지 동기화로 개발하는 것이 좋습니다.ReentrantLock. 이들은 고급 사용자를위한 고급 도구입니다. (정말로 고급 사용자는 간단한 도구가 부적절하다고 확신 할 때까지 가장 간단한 도구를 선호하는 경향이 있습니다.) 항상 그렇듯이 먼저 올바르게 설정 한 다음 더 빨리 만들어야하는지 걱정하십시오.


답변

ReentrantReadWriteLock특수 잠금 장치 인 반면 synchronized(this)범용 잠금 장치입니다. 그것들은 비슷하지만 완전히 동일하지는 않습니다.

synchronized(this)대신 사용할 수 있다는 것이 ReentrantReadWriteLock맞지만 그 반대는 항상 사실이 아닙니다.

ReentrantReadWriteLock생산자-소비자 스레드 동기화에 대한 정보를 특별하게 찾는 이유를 더 잘 이해하려면

일반적으로 전체 메서드 동기화와 범용 동기화 ( synchronized키워드 사용)는 동기화의 의미에 대해 너무 많이 생각하지 않고도 대부분의 응용 프로그램에서 사용할 수 있지만 코드에서 성능을 짜야하는 경우에는 보다 정교하거나 특수한 목적의 동기화 메커니즘을 살펴보십시오.

그건 그렇고, synchronized(this)공개 클래스 인스턴스를 사용하여 일반적으로 잠금을 사용하면 문제가 발생할 수 있습니다. 다른 사람이 의도적으로 프로그램의 다른 곳에서 객체에 대해 잠그려고 시도 할 수 있기 때문에 잠재적 교착 상태로 코드를 열 수 있기 때문입니다.


답변

ReentrantLock 에 대한 오라클 문서 페이지에서 :

동기화 된 메소드 및 명령문을 사용하여 액세스하는 암시 적 모니터 잠금과 동일한 기본 동작 및 의미를 갖는 재진입 상호 배제 잠금.

  1. ReentrantLock와는 마지막에 락에 성공했지만 아직 락 해제하고 있지 않는 스레드가 소유하고 있습니다. 다른 스레드가 잠금을 소유하지 않으면 잠금을 호출하는 스레드가 리턴되어 잠금을 성공적으로 획득합니다. 현재 스레드가 이미 잠금을 소유 한 경우이 메소드는 즉시 리턴합니다.

  2. 이 클래스의 생성자는 선택적 공정성 매개 변수를 승인합니다 . true로 설정되면 경합 상태에서 잠금은 가장 긴 대기 스레드에 대한 액세스 권한을 부여합니다 . 그렇지 않으면이 잠금은 특정 액세스 순서를 보장하지 않습니다.

기사에 따른 ReentrantLock 주요 기능

  1. 방해 할 수있는 능력.
  2. 잠금 대기 중 시간 종료 가능
  3. 공정한 자물쇠를 만드는 힘.
  4. 잠금 대기중인 스레드 목록을 가져 오는 API
  5. 차단하지 않고 잠금을 시도 할 수있는 유연성.

ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock 을 사용 하여 읽기 및 쓰기 작업에 대한 세부 잠금을 추가로 제어 할 수 있습니다 .

다른 유형의 ReentrantLocks 사용법에 대한 Benjamen 의이 기사 를 살펴보십시오.


답변

스레드 기아를 피하기 위해 공정성 정책 또는 시간 초과와 함께 재진입 잠금을 사용할 수 있습니다. 스레드 공정성 정책을 적용 할 수 있습니다. 스레드가 리소스를 얻기 위해 영원히 기다리는 것을 피하는 데 도움이됩니다.

private final ReentrantLock lock = new ReentrantLock(true);
//the param true turns on the fairness policy. 

“공정성 정책”은 실행할 다음 실행 가능 스레드를 선택합니다. 우선 순위, 마지막 실행 이후의 시간, blah blah를 기반으로합니다.

또한 블록에서 벗어날 수없는 경우 동기화는 무기한으로 차단할 수 있습니다. 재진입 잠금은 시간 종료를 설정할 수 있습니다.


답변

동기화 된 잠금 은 하나의 스레드를 실행 한 후 병렬로 실행중인 스레드가 잠금을 획득 할 수있는 대기 큐 메커니즘을 제공하지 않습니다. 시스템에 존재하고 더 오랜 시간 동안 실행되는 스레드는 공유 리소스에 액세스 할 기회를 얻지 못해 기아로 이어집니다.

재진입 잠금 은 매우 융통성이 있으며 스레드가 더 오래 기다리는 경우와 현재 실행중인 스레드가 완료된 후 더 긴 대기 스레드가 공유 자원에 액세스 할 기회를 줄 이도록하는 공평성 정책이 있습니다. 시스템의 처리량과 더 많은 시간이 소요됩니다.


답변

이 코드가 스레드에서 실행되고 있다고 가정합니다.

private static ReentrantLock lock = new ReentrantLock();

void accessResource() {
    lock.lock();
    if( checkSomeCondition() ) {
        accessResource();
    }
    lock.unlock();
}

스레드가 잠금을 소유하고 있기 때문에 여러 호출이 lock ()을 허용하므로 잠금을 다시 입력합니다. 이는 참조 카운트로 달성 할 수 있으므로 다시 잠금을 획득 할 필요가 없습니다.


답변

명심해야 할 것은 :

ReentrantLock ‘ 이라는 이름 은 재진입 이 아닌 다른 잠금 메커니즘에 대한 잘못된 메시지를 제공합니다. 사실이 아닙니다. ‘동기화’를 통해 획득 한 잠금도 Java로 다시 입력됩니다.

중요한 차이점은 ‘동기화’는 본질적 잠금 (모든 객체에있는 잠금)을 사용하지만 잠금 API는 사용하지 않는다는 것입니다.