【问题标题】:How does multiple threads acquire and release lock in synchronized methods and synchronized blocks in java?java中的同步方法和同步块中的多线程如何获取和释放锁?
【发布时间】:2020-11-04 08:18:04
【问题描述】:

java 线程如何在同步块中使用的监视器或同步方法中使用的监视器上获取锁?

我在多篇文章中读到,在偏向锁定的情况下,此信息使用 CAS 操作存储在对象标头中,在竞争情况下,使用等待设置队列/监控队列,但最终锁定仅标记在对象标头中。 如果是这种情况,那么锁是如何释放的?如何将对象标记为空闲以获取另一个线程的锁?内部是否使用了等待和通知方法?如果是这种情况,那么为什么在同步块内设置监视器 null 不会引发任何异常。

下面的例子工作得很好,我期待 NullPointerException 假设同步块的结尾会尝试标记锁属性以释放锁。

例子:

Object monitor = new Object();
    synchronized (monitor){
        System.out.println("before null");
        monitor =null;
        System.out.println("after null");
    }

    System.out.println("successfully Exited");

【问题讨论】:

  • 请注意monitor 是一个变量。它存储对 object 的引用。将引用更改为指向null 不会删除对象或其他内容。
  • @akuzminykh 如果我的方法运行时间很长并且触发器 GC 将监控成为有资格收集?那会触发 NPE 吗?
  • 更新:因此监视器将不符合 GC 的条件,因为它仍被 synchronized 构造后面的代码引用。 @pveentjer 的回答更清楚了。

标签: java multithreading synchronization locking


【解决方案1】:

偏向锁的情况:如果锁偏向某个线程,则不需要CAS;只是一个不稳定的写。偏向锁信息保存在对象头的标记字中。偏向锁定将从 JDK 15 中移除。

如果争用锁,则使用对象监视器进行同步。默认情况下,对象监视器是放气的,但如果存在争用或您执行等待/通知,则监视器会膨胀并附加到对象。

在 Linux 上,阻塞行为是使用等待队列实现的。所以当一个线程需要等待一个锁时,它会从调度器中移除并添加到等待队列中。当锁解锁时,等待队列中的线程会重新插入调度程序。

代码没有抛出异常的原因是进入同步块时监视器只被读取一次。

PS:您的锁可能由于锁省略而被完全删除。如果 JIT 不能提供其他线程可以获取该锁,那么同步就没有意义。

【讨论】:

  • 这样看:``` Object tmp = monitor;同步输入(tmp);监视器=空;同步退出(tmp); ```
  • 有什么方法可以验证对象变为只读的吗?
  • 我想你理解错了。对于同步块,监视变量仅被读取一次(只读一次)。请参阅上面我的小代码示例。
猜你喜欢
  • 1970-01-01
  • 2023-02-10
  • 2012-11-15
  • 2015-04-15
  • 1970-01-01
  • 2011-07-14
  • 2016-09-27
  • 2016-01-23
  • 2022-12-10
相关资源
最近更新 更多