我想亲眼验证睡眠和等待之间的区别。
等待只能在同步块中完成,因为它释放了监视器锁的所有权。虽然睡眠与监视器锁无关,并且已经是监视器锁所有者的线程在睡眠时不应失去其所有权。
为此我做了一个测试:
脚步:
- 启动了一个在同步块中等待 5 秒的线程。
- 等待 3 秒并启动另一个获取监视器锁的线程(因为 Thread-A 正在等待)并在持有监视器锁的同时简单地休眠 5 秒。
预期结果:线程-A 8 秒后才重新获得锁,当线程-B 最终通过退出同步块释放监视器锁。
实际结果。线程 - A 在 5 秒后获取监视器锁。
有人可以向我解释这里发生了什么吗?
public static void main(String[] args) {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("r1 before synch block");
synchronized (this) {
System.out.println("r1 entered synch block");
try {
wait(5000);
System.out.println("r1 finished waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Runnable r2 = new Runnable() {
@Override
public void run() {
System.out.println("r2 before synch block");
synchronized (this) {
System.out.println("r2 entered synch block");
try {
Thread.currentThread();
Thread.sleep(5000);
//wait(5000);
System.out.println("r2 finished waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
try {
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
Thread.currentThread();
Thread.sleep(3000);
t2.start();
t1.join();
t2.join();
System.out.println(Thread.currentThread().getName() + " Finished joining");
} catch (Exception e) {
e.printStackTrace();
}
}
编辑:
好的,我理解我的错误 - 我正在等待这个 - r1/r2 而不是同一个对象。
现在我改变了它并且都在同一个对象上获取 - Main 的类实例。1. r1 获得 Main.this 的监控锁的所有权 2. r1 释放它。3. 当 r1 尝试重新获取它时,我得到一个异常:
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at Main$1.run(Main.java:28)
at java.lang.Thread.run(Unknown Source)
on synchronized (Main.this)
这里有什么问题?
public static void main(String[] args) {
Main main = new Main();
main.test();
}
public void test() {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("r1 before synch block");
synchronized (Main.this) {
System.out.println("r1 entered synch block");
try {
wait(5000);
System.out.println("r1 finished waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Runnable r2 = new Runnable() {
@Override
public void run() {
System.out.println("r2 before synch block");
synchronized (Main.this) {
System.out.println("r2 entered synch block");
try {
Thread.currentThread();
Thread.sleep(5000);
//wait(5000);
System.out.println("r2 finished waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
try {
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
Thread.currentThread();
Thread.sleep(3000);
t2.start();
t1.join();
t2.join();
System.out.println(Thread.currentThread().getName() + " Finished joining");
} catch (Exception e) {
e.printStackTrace();
}
}