如果在同步块内重新分配对象的锁定对象会是什么?

Ole*_*nko 3 java concurrency

注意:无效的问题 - 请参阅@Bukhtoyarov 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");
    }
}
Run Code Online (Sandbox Code Playgroud)

这里我们有两个线程 - 主线程和另一个工作线程.我们也有monitor对象.在工作线程内部,我们有下一步的动作 -

  • 获得锁定 monitor
  • 等待100ms
  • 指定监视器引用以指向新对象
  • 再等1000ms

在主线程中,我们等待600毫秒并尝试将监视器重新分配给新对象.结果 - 主线程被阻塞 - 直到工作线程释放锁定monitor对象.我有两个问题

  1. 根据这Concurrency in practice本书 - 锁定水分过程阻止的唯一方法 - 是进入同步块.那么为什么主线程被阻塞直到工作线程释放锁定 - 在主线程中我们不会尝试进入同步块
  2. 工作线程monitor在100ms后分配新对象引用,为什么主线程在600ms后无法获取新重新分配对象的锁定?我的意思是 - 在refms中600ms之后monitor是新对象 - 所以锁定应该准备好了.行为很有意思 - 因为我在官方的Oracle文档或Concurrency in practice书中找不到任何关于它的信息.

Pet*_*rey 5

这段代码

 synchronized (monitor) {
Run Code Online (Sandbox Code Playgroud)

就好像

Object m = monitor;
synchronized (m) {
Run Code Online (Sandbox Code Playgroud)

即只读一次,并且在非线程安全的上下文中.

为什么主线程无法锁定新对象 - 在工作线程内部重新分配.

这意味着

  • 一旦它获得了一个要锁定的对象,它就不会继续读取循环中的最新值以查看它是否可以锁定另一个对象.
  • 即使在读取之前更改了引用,它也可以看到旧值,因为读取不是线程安全的.