Java同步游戏:synchronized &&等等&&通知
我来自 .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()
处阻塞它,并通过阻止线程“t”进入同步块来隐式阻止线程“t”。
这显然是错误的,因为我的手机按预期响了:)
接下来的想法是同步同步“代码块”(在这种情况下,有两个同步块是独立的=>线程可以同时进入两个不同的同步块,不受限制) ,这非常适合......
直到我的同事告诉我,mLock.wait()
释放了mLock上的锁,并允许其他线程同时进入mLock上的临界区。
我不确定我是否足够清楚,因此很乐意回答有关此问题的任何进一步问题。
I'm coming from .NET
world, and unfortunately looking Java source with .NET
's eyes.
Following code is from Android Apps (though not Android specific at all):
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();
}
}
I'm not precisely clear with how synchronized
works.
First I thought that synchronized is locking mLock object, but then if after t.start()
constructor thread enters sync block first, it would block it at mLock.wait()
, and implicitly block thread "t" by blocking it from entering synchronized block.
This is obviously wrong, because my phone rings as supposed :)
Next thought is that synchronize synchronizes "code block" (in which case, there two synchronized block are independent => threads can enter two different sync block at same time without restriction), and that fitted perfectly...
... until my colleague told me that mLock.wait()
releases lock on mLock and enables other thread to enter critical section on mLock in same time.
I'm not sure if I was clear enough, so will gladly answer any further questions on this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
查看 Object 上的 javadoc .wait()。它的“魔力”在于它会删除进入同步 {} 块时获取的监视器。这允许另一个线程获取监视器并调用 Object.notify()。
当另一个线程调用notify()将等待线程从wait()调用中唤醒时,等待线程必须重新获取监视器并且将阻塞直到它可以——监视器仅在wait()调用期间被删除。并且通知线程在新唤醒的等待线程可以继续之前完成其同步块。一切都按可预测的顺序进行。
Check out the javadoc on Object.wait(). It's "magic" in that it drops the monitor that was acquired when entering the synchronized {} block. That allows another thread to acquire the monitor and call Object.notify().
When another thread calls notify() to wake the waiting thread from its wait() call, the waiting thread must re-acquire the monitor and will block until it can -- the monitor is only dropped for the duration of the wait() call. And the notifying thread completes its synchronized block before the newly-awoken waiting thread can proceed. Everything is sequenced predictably.
synchronized
使用对象监视器。对对象调用wait()
会自动释放对象监视器(否则其他线程无法获取监视器并向等待者发出notify
)。synchronized
uses object monitors. Callingwait()
on the object atomically releases the object monitor (for otherwise no other thread could ever take the monitor and issue anotify
to the waiter(s)).是的。如果您阅读
wait()
方法,您将了解到它会导致线程释放锁并阻塞,直到另一个线程调用notify
或notifyAll< /code> 上锁。当前线程会等待,直到可以重新获取锁,一旦获得锁,就继续执行。
然而,显示的代码遵循了不好的做法,因为它在完全构造之前“发布”(即,它使其他线程可以访问该对象)
Worker
实例。在此方法中使用额外的屏障,再加上类的私有性质,可能会使这种情况变得安全,但通常情况并非如此。Yes. If you read the description of the
wait()
method, you'll learn that it causes the thread to release the lock and block until another thread invokesnotify
ornotifyAll
on the lock. The current thread waits until it can re-acquire the lock, and once it does, it continues execution.The code shown follows poor practice, however, because it "publishes" (that is, it makes the object accessible to other threads) the
Worker
instance before it is fully constructed. The use of additional barriers in this method, combined with theprivate
nature of the class, probably make this case safe, but in general, it is not.让我解释一下:
构造函数启动一个新线程来执行 run() 方法。
这个新线程将获取一个新的Looper对象,将其存储在mLooper字段中,然后运行Looper消息循环。在这之间,它将通知()第一个线程,mLooper 已被设置。
因此,只有在设置 mLooper 后,第一个线程才会从构造函数返回,这意味着第二个线程对 Looper.loop() 的处理必然会很快开始/已经开始。
Let me explain:
The constructor launches a new thread that will execute the run() method.
This new thread will obtain a new Looper object, store it in the mLooper field and then run the Looper message loop. In between it will notify() the first thread that mLooper has been set.
The first thread will therefore return from the constructor only after mLooper has been set which means that processing of Looper.loop(), by the 2nd thread, is bound to start shortly/has already started.