programing

Synchronized(이것)를 사용할 수 있는데 ReentrantLock을 사용하는 이유는 무엇입니까?

projobs 2022. 8. 9. 22:29
반응형

Synchronized(이것)를 사용할 수 있는데 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();
  ...
}

이러한 흐름은 1개의 모니터로 표시할 수 없습니다.synchronized건설하다.


그것 말고도ReentrantLock잠금 폴링과 타임아웃을 지원하는 인터럽트 가능한 잠금 대기지원합니다. ReentrantLock에는 설정 가능공정성 정책도 지원되므로 보다 유연한 스레드 스케줄링이 가능합니다.

이 클래스의 생성자는 선택적 공정성 매개 변수를 수락합니다.설정 시true경합 중인 잠금은 가장 긴 스레드에 대한 접근을 허용하는 데 유리합니다.그렇지 않으면 이 잠금이 특정 액세스 순서를 보장하지 않습니다.많은 스레드에 의해 액세스되는 균등 잠금을 사용하는 프로그램은 기본 설정을 사용하는 프로그램보다 전체적인 throughput이 낮을 수 있습니다(즉, 속도가 느리고, 종종 속도가 느립니다). 그러나 잠금을 취득하고 기아가 발생하지 않도록 하기 위해 시간 차이가 작습니다.단, 잠금이 공평하다고 해서 스레드 스케줄링이 공평해지는 것은 아닙니다.따라서 균등 잠금을 사용하는 많은 스레드 중 하나는 다른 활성 스레드가 진행되지 않고 현재 잠금을 유지하지 않는 동안 연속적으로 여러 번 취득할 수 있습니다.또, 타이밍이 맞지 않는 것은,tryLockmethod는 공정성 설정을 따르지 않습니다.다른 스레드가 대기 중인 경우에도 잠금을 사용할 수 있으면 성공합니다.


ReentrantLock 또한 확장성이 향상되어 경합이 높을 때 성능이 훨씬 향상될 수 있습니다.자세한 내용은 여기를 참조하십시오.

그러나 이 주장에 대해서는 이의를 제기하고 있습니다.다음의 코멘트를 참조해 주세요.

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


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

답은 매우 간단합니다.실제로 필요한 경우에 사용합니다.synchronized는, 타임 록 대기, 인터럽트 가능한 록 대기, 블록 구성의 비잠금, 복수의 조건 변수, 또는 록 폴링과 같이 하지 않습니다. ReentrantLockscalability의 이점도 있습니다.또한 실제로 경합이 심한 상황에 처했을 경우에는 scalability를 사용해야 합니다만, 대부분의 경우,synchronized블록은 경합은 말할 것도 없고 경합도 거의 보이지 않는다.동기화가 불충분하다는 것이 판명될 때까지 동기화하는 것이 좋습니다.단순히 '퍼포먼스가 향상된다'고 가정하는 것이 좋습니다.ReentrantLock이들은 상급 사용자를 위한 고급 도구입니다.(그리고 진정한 상급 사용자는 간단한 도구가 불충분하다고 확신할 때까지 가장 간단한 도구를 선호하는 경향이 있습니다.)항상 그렇듯이 먼저 바로잡고 나서 더 빨리 만들어야 할지 걱정하세요.


가까운 장래에 더욱 관련성이 높아지게 될 마지막 측면은 Java 15와 Project Loom에 관한 것입니다.(새로운) 가상 스레드 세계에서는 기본 스케줄러는 다음과 같이 훨씬 더 효율적으로 작업할 수 있습니다.ReentrantLock가 할 수 있는 것보다synchronized적어도 초기 Java 15 릴리즈에서는 해당되지만 나중에 최적화될 수 있습니다.

현재의 Loom 실장에서는 가상 스레드를 2가지 상황에서 핀 접속할 수 있습니다.스택상에 네이티브 프레임이 존재하는 경우, Java 코드가 Java에 콜백하는 네이티브 코드(JNI)에 콜하는 경우, 그리고 Java에 콜백하는 경우,synchronized블록 또는 메서드.이 경우 가상 스레드를 차단하면 해당 스레드를 전송하는 물리적 스레드가 차단됩니다.네이티브 콜이 완료되거나 모니터가 해방되면(synchronizedblock/displays exit) 스레드의 핀이 해제됩니다.

일반적인 I/O 조작이 보호되고 있는 경우synchronized, 모니터를 교환해 주세요.ReentrantLock모니터에 의한 핀 접속을 수정하기 전에 Loom의 scalability를 통해 어플리케이션을 최대한 활용할 수 있습니다(더 좋은 것은 고성능을 사용하는 것입니다).StampedLock할 수 있다면).

ReentrantReadWriteLock 전용 잠금 장치인 반면,synchronized(this)범용 잠금입니다.그들은 비슷하지만 완전히 같지는 않다.

당신이 사용할 수 있는 것은 옳습니다.synchronized(this)대신ReentrantReadWriteLock하지만 그 반대가 항상 맞는 것은 아니다.

만약 당신이 더 잘 이해하고 싶다면ReentrantReadWriteLockspecial은 생산자와 생산자의 스레드 동기화에 대한 정보를 검색합니다.

일반적으로 전체 방식 동기화 및 일반 목적 동기화(사용 시)를 기억할 수 있습니다.synchronized키워드)를 사용하면 대부분의 어플리케이션에서 동기의 의미에 대해 크게 생각하지 않고 사용할 수 있습니다.단, 코드에서 퍼포먼스를 짜낼 필요가 있는 경우는, 그 외의 보다 세밀한, 또는 특수한 목적의 동기 메카니즘을 조사할 필요가 있습니다.

그런데, 사용법은synchronized(this)또한 퍼블릭클래스 인스턴스를 사용한 일반적인 잠금에서는 문제가 발생할 수 있습니다.다른 사람이 모르는 사이에 프로그램의 다른 곳에서 당신의 오브젝트에 대해 잠금을 시도할 수 있기 때문입니다.

ReentrantLock에 대한 Oracle 문서 페이지에서 다음을 수행합니다.

재진입 상호 제외 동기화된 메서드 및 스테이트먼트를 사용하여 액세스되는 암묵적 모니터 잠금과 동일한 기본 동작 및 의미론을 가지지만 확장 기능을 가진 잠금.

  1. ReentrantLock은 마지막으로 정상적으로 잠겼지만 아직 잠금 해제되지 않은 스레드에 의해 소유됩니다.다른 스레드가 잠금을 소유하고 있지 않은 경우 스레드 호출 잠금이 반환되어 잠금을 성공적으로 획득합니다.현재 스레드가 이미 잠금을 소유하고 있는 경우 메서드가 즉시 반환됩니다.

  2. 이 클래스의 생성자는 선택적 공정성 매개 변수를 수락합니다.true로 설정하면 경합 중인 잠금은 가장 오래 대기하는 스레드에 대한 액세스 허용을 선호합니다.그렇지 않으면 이 잠금이 특정 액세스 순서를 보장하지 않습니다.

기사의 ReentrantLock 주요 기능

  1. 중단 없이 잠글 수 있습니다.
  2. 잠금을 기다리는 동안 시간 초과가 가능합니다.
  3. 공정한 잠금을 만들 수 있는 힘.
  4. 잠금 대기 스레드 목록을 가져오는 API입니다.
  5. 차단하지 않고 잠금을 시도할 수 있는 유연성.

ReentrantReadWriteLock을 사용할 수 있습니다.ReadLock, ReentrantReadWriteLock.WriteLock을 통해 읽기 및 쓰기 작업의 세밀한 잠금 제어를 더욱 강화할 수 있습니다.

Have a look at this article by Benjamen on usage of different type of ReentrantLocks

Synchronized locks does not offer any mechanism of waiting queue in which after the execution of one thread any thread running in parallel can acquire the lock. Due to which the thread which is there in the system and running for a longer period of time never gets chance to access the shared resource thus leading to starvation.

Reentrant locks are very much flexible and has a fairness policy in which if a thread is waiting for a longer time and after the completion of the currently executing thread we can make sure that the longer waiting thread gets the chance of accessing the shared resource hereby decreasing the throughput of the system and making it more time consuming.

You can use reentrant locks with a fairness policy or timeout to avoid thread starvation. You can apply a thread fairness policy. it will help avoid a thread waiting forever to get to your resources.

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

The "fairness policy" picks the next runnable thread to execute. It is based on priority, time since last run, blah blah

also, Synchronize can block indefinitely if it cant escape the block. Reentrantlock can have timeout set.

One thing to keep in mind is :

The name 'ReentrantLock' gives out a wrong message about other locking mechanism that they are not re-entrant. This is not true. Lock acquired via 'synchronized' is also re-entrant in Java.

Key difference is that 'synchronized' uses intrinsic lock ( one that every Object has ) while Lock API doesn't.

I think the wait/notify/notifyAll methods don't belong on the Object class as it pollutes all objects with methods that are rarely used. They make much more sense on a dedicated Lock class. So from this point of view, perhaps it's better to use a tool that is explicitly designed for the job at hand - ie ReentrantLock.

Lets assume this code is running in a thread:

private static ReentrantLock lock = new ReentrantLock();

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

Because the thread owns the lock it will allow multiple calls to lock(), so it re-enter the lock. This can be achieved with a reference count so it doesn't has to acquire lock again.

언급URL : https://stackoverflow.com/questions/11821801/why-use-a-reentrantlock-if-one-can-use-synchronizedthis

반응형