【问题标题】:Java Multithreading - What Really Happens When Accessing A "Locked" Object?Java 多线程 - 访问“锁定”对象时真正发生了什么?
【发布时间】:2015-06-07 05:53:15
【问题描述】:

给定在包装类中定义和初始化的以下对象:

// (thread-safe) List of Requests made by users
private static List<Request> requests = Collections.synchronizedList(new ArrayList<Request>());

在更新循环中不断调用以下代码:

// <-- (Thread 1 executes the following code @ Runtime=1.0000000ms)
    synchronized(requests) {
        for (Request request : requests)
            request.handle();
        requests.clear();
    }

这也是“同时”发生的。

// (Thread 2 executes the following code also @ Runtime=1.0000000ms)
    synchronized(requests) {
        (requests.add(new Request());
    }

据我了解,在这种情况下保证会发生以下情况:其中一个线程将成功锁定请求列表,执行其各自的任务,并在退出同步块时释放其锁定。

在我对“线程安全”的理解中,这就是我觉得奇怪的地方。假设线程 1 已经在请求列表上获得了锁定,并且首先进入了它的同步块,尽管线程 2 试图做同样的事情。

1) 由于未实现对象的同步性而无法调用的同步块内的代码会发生什么情况?(在这种情况下,使用线程 2 和 new Request( ) 该线程正在尝试添加到列表中 - 它会发生什么? - 请求是否只是 poof 并且由于线程 1 已锁定对象而从未添加到请求列表中?

2) 线程 2 是否真的在等待线程 1 释放它的锁,然后线程 2 重新审视对象并添加请求?(假设陷阱)如果这是案例 - 如果线程 1 需要 60 秒对 List 中的所有请求对象执行 handle() - 导致线程 2 等待这 60 秒怎么办?

额外问题)关于 Collections.synchronizedList 的 1 和 2 的答案是否遵循与 ConcurrentHashMap 相同的行为?

【问题讨论】:

  • 线程 2 进入等待状态并保持在那里,直到线程 1 通过退出同步块释放锁。然后线程 2 和任何其他等待锁的线程进入就绪状态。是的,如果线程 1 需要 60 秒,线程 2 会等待 60 秒。
  • 真的应该使用并发队列实现之一。
  • 至于奖金,没有。 ConcurentHashMap 并发,不同步。在我的脑海中,它大部分时间都是无锁的。这是由于 Brian Goetz & co 实现的算法 jimbly-jumbly-unsafe-magic。但是,在失败的原子操作中,可能需要锁定映射以更新状态。最好阅读 javadoc 以获取更多技术信息,甚至您需要了解一切的来源。

标签: java multithreading locking synchronized


【解决方案1】:

1) 由于对象的同步性未实现而无法调用的同步块内的代码会发生什么情况?

其他线程将被阻塞,直到获得的线程释放了锁。之后,持有线程释放锁,任何等待线程都可以获取它。获得锁的一方可以继续,另一方则必须再次等待。

2) 线程 2 是否真的在等待线程 1 释放其锁定,然后线程 2 重新审视对象并添加请求?

是的,线程 2 必须等到线程 1 释放锁。只有这样它才能获得锁。

每个锁都有一个关联的监视器,用于控制谁可以访问与锁关联的关键区域。一次只有一个线程可以获取此监视器并可以访问相关的临界区。所有其他线程都必须等待获取监视器。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    • 2013-10-25
    • 1970-01-01
    • 1970-01-01
    • 2021-12-15
    • 2021-05-13
    相关资源
    最近更新 更多