Program Tip

조건 대 대기 알림 메커니즘

programtip 2020. 11. 18. 09:40
반응형

조건 대 대기 알림 메커니즘


기존 대기 알림 메커니즘에 비해 조건 인터페이스 / 구현을 사용하면 어떤 이점이 있습니까? 여기에 Doug Lea가 쓴 의견을 인용합니다.

조건은 개체 모니터 메서드 (wait, notify 및 notifyAll)를 별개의 개체로 분해하여 임의의 잠금 구현을 사용하여 개체 당 여러 개의 대기 집합을 갖는 효과를 제공합니다. 잠금이 동기화 된 메소드 및 명령문의 사용을 대체하는 경우 조건은 오브젝트 모니터 메소드의 사용을 대체합니다.

이것이 대기 / 알림 메커니즘을 구현하는보다 객체 지향적 인 방법이라고 생각합니다. 그러나 전자에 비해 건전한 이점이 있습니까?


조건 인터페이스 에 대해 위에서 언급 한 것과 같은 많은 이점 이 있습니다. 몇 가지 중요한 사항은 다음과 같습니다.

조건 인터페이스 에는 다음과 같은 두 가지 추가 메서드 가 있습니다.

1) boolean awaitUntil (Date deadline) throws InterruptedException : 현재 스레드가 신호를 받거나 중단되거나 지정된 데드 라인이 경과 할 때까지 대기하도록합니다.

2) awaitUninterruptibly () : 현재 스레드가 신호를받을 때까지 기다리도록합니다.

이 메서드에 들어갈 때 현재 스레드의 인터럽트 상태가 설정되거나 대기 중에 인터럽트되면 신호를받을 때까지 계속 대기합니다. 마지막으로이 메서드에서 반환되면 중단 된 상태가 계속 설정됩니다.

위의 두 메서드는 개체 클래스에있는 기본 모니터에 존재하지 않습니다. 어떤 상황에서는 스레드가 대기하는 데드 라인을 설정하고 나서 Condition 인터페이스에서이를 수행 할 수 있습니다.

어떤 상황에서는 쓰레드가 중단되는 것을 원하지 않고 현재 쓰레드가 신호를받을 때까지 기다리기를 원하는 경우 Condition Interface에있는 awaitUninterruptibly 메소드를 사용할 수 있습니다.

자세한 내용은 Condition Interface Java 문서 :

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Condition.html#awaitUntil%28java.util.Date%29


가장 큰 문제는 대기 / 알림이 새로운 개발자에게 오류가 발생하기 쉽다는 것입니다. 주요 문제는 올바르게 처리하는 방법을 모르면 모호한 버그가 발생할 수 있습니다.

  • wait () 전에 notify ()를 호출하면 손실됩니다.
  • 동일한 객체에서 notify () 및 wait ()가 호출되는지 여부가 때때로 불분명 할 수 있습니다.
  • 대기 / 알림에는 상태 변경이 필요한 것은 없지만 대부분의 경우에 필요합니다.
  • wait ()는 가짜로 반환 할 수 있습니다.

Condition은이 기능을 전용 구성 요소로 래핑하지만 거의 동일하게 작동합니다.

이 1 분 전에 게시 된 대기 / 무시에 관한 질문과 더 많은 검색 [java] + wait + notify


사용할 때 Condition: await()/signal()어떤 개체 또는 개체 / 스레드 그룹이 특정 신호를 받는지 구분할 수 있습니다. 다음은 일부 스레드 (생산자)가 isEmpty신호를 받고 소비자가 신호를 받는 간단한 예입니다 isFull.

private volatile boolean usedData = true;//mutex for data
private final Lock lock = new ReentrantLock();
private final Condition isEmpty = lock.newCondition();
private final Condition isFull = lock.newCondition();

public void setData(int data) throws InterruptedException {
    lock.lock();
    try {
        while(!usedData) {//wait for data to be used
            isEmpty.await();
        }
        this.data = data;
        isFull.signal();//broadcast that the data is now full.
        usedData = false;//tell others I created new data.          
    }finally {
        lock.unlock();//interrupt or not, release lock
    }       
}

public void getData() throws InterruptedException{
    lock.lock();
    try {
        while(usedData) {//usedData is lingo for empty
            isFull.await();
        }
        isEmpty.signal();//tell the producers to produce some more.
        usedData = true;//tell others I have used the data.
    }finally {//interrupted or not, always release lock
        lock.unlock();
    }       
}

여러 개의 waitset이있는 것이 장점 인 이유를 구체적으로 해결하려면 다음을 수행하십시오.

With wait/notify if there are different things that threads are waiting for (the common example is a fixed size blocking queue, with some threads putting things in the queue and blocking when the queue is full, and other threads taking from the queue and blocking when the queue is empty) then if you use notify, causing the scheduler to pick one thread from the wait set to notify, you can have corner cases where the chosen thread isn't interested in being notified for a particular situation. For instance the queue will notify for adding something to the queue, but if the chosen thread is a producer and the queue is full then it can't act on that notification, which you would rather have gone to a consumer. With intrinsic locking you have to use notifyAll in order to make sure that notifications don't get lost.

But notifyAll incurs churn with every call, where every thread wakes up and contends for the lock, but only one can make progress. The other threads all bump around contending for the lock until, one at a time, they can acquire the lock and most likely go back to waiting. It generates a lot of contention for not much benefit, it would be preferable to be able to use notify and know only one thread is notified, where the notification is relevant to that thread.

This is where having separate Conditions to wait on is a big improvement. The queue can invoke signal on a condition and know it will wake up only one thread, where that thread is specifically waiting for the condition.

The API doc for Condition has a code example that shows using multiple conditions for a bounded buffer, it says:

We would like to keep waiting put threads and take threads in separate wait-sets so that we can use the optimization of only notifying a single thread at a time when items or spaces become available in the buffer.


@AfterWorkGuinness

Shouldn't you be setting usedData=true/false before signaling

After signal code go until end of lock block and release it, so order doesn't matter

참고URL : https://stackoverflow.com/questions/10395571/condition-vs-wait-notify-mechanism

반응형