我正在学习 OCJP,现在我在“线程”章节,我有一些关于等待和通知方法的问题。我想我明白这里发生了什么,但我只是想确保我走在正确的道路上。我编写了这段代码作为示例:
package threads;
public class Main {
static Object lock = new Object();
public static void main(String[] args) {
new Main().new FirstThread().start();
new Main().new SecondThread().start();
}
class FirstThread extends Thread {
public void run() {
synchronized (lock) {
lock.notify();
System.out.println("I've entered in FirstThread");
}
}
}
class SecondThread extends Thread {
public void run() {
synchronized (lock) {
try {
lock.wait();
System.out.println("I'm in the second thread");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
在此示例中,控制台输出为I've entered in FirstThread
,因为第一个线程启动,调用了notify()方法,然后第二个线程启动,调用了wait()方法,并没有打印String“我在第二个线程”。
下一个场景是我颠倒位置new Main().new FirstThread().start();
and new Main().new SecondThread().start();
输出是
I've entered in FirstThread
I'm in the second thread
因为第二个线程启动,调用了wait()方法,然后第一个线程启动,调用了notify()方法,控制台打印I've entered in FirstThread
,等待被释放并且I'm in the second thread
打印在控制台中。
发生这种情况是因为计算机速度太快并且线程按顺序运行吗?理论上,我认为可以首先调用第二个 start() 方法,是吗?
我的最后一个问题是为什么锁对象必须是静态的,因为如果我删除静态修饰符,输出总是I've entered in FirstThread
?
我知道静态字段是在类加载时在JVM中加载的,但是我无法理解锁定Object的逻辑。
线程按顺序启动,理论上线程 1 将在线程 2 之前执行,尽管它是不保证(很确定在这个简单的情况下它会是一致的,因为没有真实或模拟的偶然延迟)。
这就是为什么当线程 2 稍微提前启动时,它有机会等待随后(由线程 1)通知的锁,而不是永远等待已经通知过一次的锁(因此,不打印)。
On the static
lock Object
: 你正在绑定你的[First/Second]Thread
嵌套类到实例 of Main
,因此如果您希望它们在同一锁上同步,则该锁必须是两者共用的。
如果它是一个实例对象,您的线程将在不同的锁上访问和同步,就像您的线程一样new Main()...
习语会得到两个实例Main
以及随后的两个实例lock
.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)