【问题标题】:What will be if reassign reference to lock object inside synchronization block?如果重新分配对同步块内锁定对象的引用会怎样?
【发布时间】:2019-05-13 08:15:53
【问题描述】:

注意:无效问题 - 请参阅@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");
    }
}

这里我们有两个线程——主线程和另一个工作线程。我们还有monitor 对象。在工作线程内部,我们有下一个动作序列 -

  • 获取锁定monitor
  • 等待 100 毫秒
  • 分配监视器引用以指向新对象
  • 再等 1000 毫秒

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

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

【问题讨论】:

  • >>> 结果 - 主线程被阻塞 - 直到工作线程释放对监视器对象的锁定。如果在主线程从“test”方法返回后由“main”线程启动的“worker”线程,“worker”线程如何在“test”方法中阻塞主线程?看起来您在那里发布的代码与您观察到的主线程被阻塞的代码不同。

标签: java concurrency


【解决方案1】:

这段代码

 synchronized (monitor) {

就像

Object m = monitor;
synchronized (m) {

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

为什么主线程不能锁定新对象 - 在工作线程内重新分配。

这意味着

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

【讨论】:

  • 我无法理解你的回答 - 为什么Object m - 从未使用过参考?目前尚不清楚为什么main 线程被锁定 - 我们没有进入main 线程内的synchronization 块。其次,为什么main 线程无法锁定新对象 - 在工作线程内重新分配。您能否在官方文档或至少其他来源中提供参考 - 我找不到?
  • @OleksandrPapchenko 当你引用一个变量时,它只会被读取一次,它不会被重复读取。注意:您没有锁定字段,而是该字段引用的对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-01
相关资源
最近更新 更多