虚假唤醒,wait()和notifyAll() [英] Spurious wakeups, wait() and notifyAll()

查看:156
本文介绍了虚假唤醒,wait()和notifyAll()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有N个线程在循环中执行这些操作:增加共享变量,检查共享变量值是否为N(如果将值放入队列)并执行wait()。我还有一个威胁来检查q变量。如果queue为true,则执行notifyAll()。之后,N个线程应该唤醒,然后再进行一次循环。但似乎有些线程在没有通知的情况下醒来。我已经读过关于虚假唤醒的内容,但是我不知道应该在什么条件下()检查它是否是虚假的唤醒。

I have N threads that do these things in loop: increase shared variable, checks if shared variable value is N (if so put value to queue) and do wait(). I have one more threat that checks the q variable. If queue is true, it does notifyAll(). After that N threads should wake up, and do another run of loop. But it seems that some threads are waking up without notification. I've read about spurious wakeups, but I don't know what condition should I put to while() to check if it was spurious wake up.

Bellow是例子我的代码(不一样,但含义非常相似):

Bellow is example of my code (not the same, but very similar in meaning):

共享类在所有线程之间共享:

Shared class is shared between all threads:

class Shared {
    volatile int v = 0;
}

我创建10个线程并运行它们。

I create 10 threads and run them.

class NThreads implements Runnable {
    private Shared shared;
    private QThread q;
    static int N = 0; /* N - number of threads */

    public NThreads(QThread q, Shared shared) {
        this.q = q;
        this.shared = shared;
        ++N;
    }

    @Override
    public void run() {
        for (int i=0;i<1048575;++i) {
            doSomeCalculations();
            loop();
        }
    }

    private void loop() {
        synchronized (shared) {
            if (++shared.v == N) {
                shared.v = 0;
                synchronized (Q) {
                    q.q = true;
                }
                shared.wait();
            } else {
                shared.wait();
            }
        }
    }
}

那里只有一个QThread等待修改q然后调用notifyAll();

There is only one QThread that waits for modification of q and then invoke notifyAll();

class QThread implements Runnable {
    private Shared shared;
    volatile boolean q = false;

    public QThread(Shared shared) {
        this.shared = shared;
    }

    @Override
    public void run() {
        for (;;) {
            if (q) {
                synchronized (this) {
                    q = false;
                }
                synchronized (shared) {
                    shared.notifyAll();
                }
            }
            doSomethingElse();
            // or even: Thread.yield();
        }
    }
}

运行所有内容的主类:

Main class that runs everything:

class Main {
    public static void main(String[] args) {
        Shared shared = new Shared();
        QThread qt = new QThread(shared);
        NThread[] nt = new NThread[10];
        for (int i=0; i<nt.length; ++i) {
            nt[i] = new NThread(qt, shared);
        }
        Thread[] threads = new Thread[nt.length+1];
        threads[0] = new Thread(qt);
        for (int i=0; i<nt.length; ++i) {
            threads[1+i] = new Thread(nt[i]);
        }

        for (int i=0; i<threads.length; ++i) {
            threads[i].start();
        }

        for (int i=0; i<threads.length; ++i) {
            threads[i].join();
        }
    }
}

有时会有线程(来自NThreads)完成他们的循环,但其他线程没有。我认为这是因为虚假的唤醒。如何编写条件来获取虚假唤醒的蛋糕,并确保所有线程都可以继续工作?

Sometimes there are threads (from NThreads) that finishes their loops, but other threads no. I think that is because of spurious wakeups. How to write condition to take cake of spurious wakeups and be sure that all threads can continue their work?

也许java.util.concurrent中有用的类?但是我没有看到任何有趣的东西...... :(

Maybe there is useful class in java.util.concurrent? But I didn't see anything interesting... :(

推荐答案

Object.wait()讨论了虚假的唤醒可能性。还提到你应该在循环中使用wait(),它在离开wait循环之前检查外部条件。

The JavaDocs for Object.wait() discuss the spurious wakeup possibility. It also mentions that you should use the wait() in a loop that checks an external condition before leaving the wait loop.

你需要重构loop()方法一点来完成这个

You'll need to restructure the loop() method a bit to accomplish this

private void loop() {
    synchronized (shared) {
        shared.v++;
        while(shared.v < N) {
            shared.wait();
        }

        shared.v = 0;
        synchronized (Q) {
            q.q = true;
        } 
    }

最后,你应该找到一个内置了这个并发库,因为很容易让这些类型的东西出错。我会看看Google的Guava, java.util.concurrency或许多Apache Commons库中的一个作为起点。

In the end, you should probably find a concurrency library that has this built in since it's easy to get these types of things wrong. I'd look at Google's Guava, java.util.concurrency or one of the many Apache Commons libraries as a starting point.

这篇关于虚假唤醒,wait()和notifyAll()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆