简体   繁体   English

通过使用notify代替notifyAll来减少线程竞争

[英]Reduce thread competition by using notify in place of notifyAll

I saw this self implemented bounded blocking queue .我看到了这个自我实现的有界blocking queue
A change was made to it, aiming to eleminate competition by replacing notifyAll with notify .对其进行了更改,旨在通过将notifyAll替换为notify来消除竞争。

But I don't quite get what's the point of the 2 extra variables added: waitOfferCount and waitPollCount .但我不太明白添加的 2 个额外变量有什么意义: waitOfferCountwaitPollCount
Their initial values are both 0.它们的初始值都是 0。

Diff after and before they're added is below:添加前后的差异如下:
Offer : Offer 在此处输入图片说明

Poll : Poll 在此处输入图片说明

My understanding is that the 2 variables purpose is that you won't do useless notify calls when there's nothing wait on the object.我的理解是,2 个变量的目的是当对象没有任何wait时,您不会进行无用的notify调用。 But what harm would it do if not done this way?但是如果不这样做会有什么危害呢?
Another thought is that they may have something to do with the switch from notifyAll to notify , but again I think we can safely use notify even without them?另一个想法是它们可能与从notifyAllnotify的切换有关,但我再次认为即使没有它们我们也可以安全地使用notify

Full code below:完整代码如下:

class FairnessBoundedBlockingQueue implements Queue {
    protected final int capacity;

    protected Node head;

    protected Node tail;

    // guard: canPollCount, head
    protected final Object pollLock = new Object();
    protected int canPollCount;
    protected int waitPollCount;

    // guard: canOfferCount, tail
    protected final Object offerLock = new Object();
    protected int canOfferCount;
    protected int waitOfferCount;

    public FairnessBoundedBlockingQueue(int capacity) {
        this.capacity = capacity;
        this.canPollCount = 0;
        this.canOfferCount = capacity;
        this.waitPollCount = 0;
        this.waitOfferCount = 0;
        this.head = new Node(null);
        this.tail = head;
    }

    public boolean offer(Object obj) throws InterruptedException {
        synchronized (offerLock) {
            while (canOfferCount <= 0) {
                waitOfferCount++;
                offerLock.wait();
                waitOfferCount--;
            }
            Node node = new Node(obj);
            tail.next = node;
            tail = node;
            canOfferCount--;
        }
        synchronized (pollLock) {
            ++canPollCount;
            if (waitPollCount > 0) {
                pollLock.notify();
            }
        }
        return true;
    }

    public Object poll() throws InterruptedException {
        Object result;
        synchronized (pollLock) {
            while (canPollCount <= 0) {
                waitPollCount++;
                pollLock.wait();
                waitPollCount--;
            }

            result = head.next.value;
            head.next.value = null;
            head = head.next;
            canPollCount--;
        }
        synchronized (offerLock) {
            canOfferCount++;
            if (waitOfferCount > 0) {
                offerLock.notify();
            }
        }
        return result;
    }
}

You would need to ask the authors of that change what they thought they were achieving with that change.您需要询问该更改的作者,他们认为他们通过该更改实现了什么。

My take is as follows:我的看法如下:

  • Changing from notifyAll() to notify() is a good thing.notifyAll()更改为notify()是一件好事。 If there are N threads waiting on a queue's offerLock or pollLock , then this avoids N - 1 unnecessary wakeups.如果有N线程在等待队列的offerLockpollLock ,那么这将避免N - 1不必要的唤醒。

  • It seems that the counters are being used avoid calling notify() when there is nothing waiting to ne notified.似乎正在使用计数器避免在没有任何等待notify()时调用notify() This looks to me like a doubtful optimization.这在我看来像是一个可疑的优化。 AFAIK a notify on a mutex when nothing is waiting is very cheap. AFAIK 在没有任何东西等待时在互斥锁上发出notify非常便宜。 So this may make a small difference ... but it is unlikely to be significant.所以这可能会产生很小的差异……但它不太可能是显着的。

  • If you really want to know, write some benchmarks.如果您真的想知道,请编写一些基准测试。 Write 4 versions of this class with no optimization, the notify optimization, the counter optimization and both of them.编写这个类的 4 个版本,没有优化,通知优化,计数器优化和它们。 Then compare the results ... for different levels of queue contention.然后比较结果......对于不同级别的队列争用。


I'm not sure what "fairness" is supposed to mean here, but I can't see anything in this class to guarantee that threads that are waiting in offer or poll get treated fairly.我不确定这里的“公平”是什么意思,但我在这个类中看不到任何东西来保证等待offerpoll线程得到公平对待。

Another thought is that they may have something to do with the switch from notifyAll to notify, but again I think we can safely use notify even without them?另一个想法是它们可能与从 notifyAll 到 notify 的切换有关,但我再次认为即使没有它们我们也可以安全地使用 notify ?

Yes, since two locks ( pollLock and offerLock ) are used, it is no problem to change notyfiAll to notify without these two variables.是的,因为使用了两个锁( pollLockofferLock ),所以如果没有这两个变量,将notyfiAll改为notify是没有问题的。 But if you are using a lock, you must use notifyAll .但如果您使用锁,则必须使用notifyAll

My understanding is that the 2 variables purpose is that you won't do useless notify calls when there's nothing wait on the object.我的理解是,2 个变量的目的是当对象没有任何等待时,您不会进行无用的通知调用。 But what harm would it do if not done this way?但是如果不这样做会有什么危害呢?

Yes, these two variables are to avoid useless notify calls.是的,这两个变量是为了避免无用的notify调用。 These two variables also bring in additional operations.这两个变量也带来了额外的操作。 I think benchmarking may be needed to determine performance in different scenarios.我认为可能需要进行基准测试来确定不同场景下的性能。

Besides,除了,

1.As a blocking queue, it should implement the interface BlockingQueue , and both poll and offer methods shoule be non-blocking . 1.作为阻塞队列,它应该实现接口BlockingQueue ,并且polloffer方法都应该是non-blocking It should use take and add .它应该使用takeadd

2.This is not a Fairness queue. 2.这不是Fairness队列。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM