**注意:**无效的问题 - 请参阅评论 of_1_Vladimir
假设我们有以下代码:
public class Main {
private Object monitor = new Object();
public static void main(String[] args) throws InterruptedException {
Main main = new Main();
main.test();
new Thread() {
@Override
public void run() {
try {
main.changeMonitor();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
private void test() throws InterruptedException {
synchronized (monitor) {
Thread.sleep(100);
monitor = new Object();
Thread.sleep(1000);
System.out.println("test finished");
}
}
private void changeMonitor() throws InterruptedException {
Thread.sleep(600);
monitor = new Object();
System.out.println("monitor changed");
}
}
这里我们有两个线程 - 主线程和另一个工作线程。我们还有monitor
对象。在工作线程内部,我们有下一步的动作 -
-
锁定
monitor
-
等待 100ms
-
指定监视器引用以指向新对象
-
再等 1000ms
在主线程中,我们等待 600 毫秒并尝试将监视器重新分配给新对象。结果 - 主线程被阻塞 - 直到工作线程释放对monitor
对象的锁定。我有两个问题
-
根据
Concurrency in practice
书 - 锁定水分过程阻止的唯一方法 - 是进入同步块。那么为什么主线程被阻塞直到工作线程释放锁定 - 在主线程中我们不会尝试进入同步块 -
工作线程在 100ms 后将新对象分配给
monitor
引用,为什么主线程在 600ms 后无法获取对新重新分配的对象的锁定?我的意思是 - 在monitor
ref 中 600ms 之后是新对象 - 所以锁定应该准备好获取行为很有趣 - 因为我在官方 Oracle 文档或Concurrency in practice
书中找不到任何关于它的信息。
1 回答
这段代码
就好像
i.e。只读发生一次,并且在不是 thread-safe 的上下文中。
这意味着
一旦它获得了一个要锁定的对象,它就不会继续读取循环中的最新值以查看它是否可以锁定另一个对象。
即使在读取之前更改了引用,它也可以看到旧值,因为读取不是线程安全的。