Java同步游戏:同步&&等待&&通知

时间:2009-12-17 14:43:02

标签: java android multithreading synchronization

我来自.NET世界,不幸的是.NET看着Java来源。

以下代码来自Android应用程序(虽然根本不是Android专用):

    private class Worker implements Runnable {
        private final Object mLock = new Object();
        private Looper mLooper;

        Worker(String name) {
            Thread t = new Thread(null, this, name);
            t.start();
            synchronized (mLock) {
                while (mLooper == null) {
                    try {
                        mLock.wait();
                    } catch (InterruptedException ex) {
                    }
                }
            }
        }

        public Looper getLooper() {
            return mLooper;
        }

        public void run() {
            synchronized (mLock) {
                Looper.prepare();
                mLooper = Looper.myLooper();
                mLock.notifyAll();
            }
            Looper.loop();
        }

        public void quit() {
            mLooper.quit();
        }
    }

我对synchronized的工作原理并不清楚。 首先我认为synchronized是锁定mLock对象,但是如果在t.start()构造函数线程首先进入同步块后,它将在mLock.wait()阻止它,并通过阻止它进入synchronized来隐式阻止线程“t”块。

这显然是错误的,因为我的电话按照假设:)

接下来的想法是同步同步“代码块”(在这种情况下,有两个同步块是独立的=>线程可以同时无限制地输入两个不同的同步块),并且完全适合......

...直到我的同事告诉我mLock.wait()释放锁定mLock并使其他线程同时进入mLock的关键部分。

我不确定自己是否足够清楚,所以很乐意回答任何进一步的问题。

4 个答案:

答案 0 :(得分:8)

查看Object.wait()上的javadoc。这是“神奇的”,因为它会丢弃进入synchronized {}块时获取的监视器。这允许另一个线程获取监视器并调用Object.notify()

当另一个线程调用notify()从wait()调用中唤醒等待线程时,等待线程必须重新获取监视器并将阻塞直到它可以 - 监视器仅在等待期间被丢弃()打电话。并且通知线程在新唤醒的等待线程可以继续之前完成其同步块。所有事情都可以预测。

答案 1 :(得分:1)

synchronized使用对象监视器。在对象上调用wait()以原子方式释放对象监视器(否则没有其他线程可以使用监视器并向服务员发出notify)。

答案 2 :(得分:1)

是。如果您阅读wait()方法的描述,您将了解到它导致线程释放锁并阻塞,直到另一个线程在锁上调用notifynotifyAll。当前线程等待它可以重新获取锁定,一旦它执行,它就会继续执行。

显示的代码遵循不良的做法,因为它在完全构造之前“发布”(即,它使对象可以访问其他线程)Worker实例。在这种方法中使用额外的障碍,结合类的private性质,可能会使这种情况安全,但总的来说,它不是。

答案 3 :(得分:0)

让我解释一下:

构造函数启动一个将执行run()方法的新线程。 这个新线程将获得一个新的Looper对象,将其存储在mLooper字段中,然后运行Looper消息循环。在它之间它将通知()第一个已经设置了mLooper的线程。

第一个线程因此只有在设置了mLooper之后才会从构造函数返回,这意味着第二个线程对Looper.loop()的处理必然会很快启动/已经开始。