关于java:浅谈synchronized与Objectwaitnotify原理

5次阅读

共计 2158 个字符,预计需要花费 6 分钟才能阅读完成。

synchronized 是 Java 中罕用的锁机制,synchronized+Object.wait/notify是罕用的期待唤醒机制,那它们的实现原理是什么呢?本文就 synchronized 与 Object.wait/notify 为例谈谈以下内容。

  • synchronized 锁降级。
  • synchronized 是如何工作的。
  • synchronized 同步队列和期待队列是如何配合的。
  • 为什么 Object.wait 必须在 synchronized 中。

synchronized 在 JVM 里的实现是基于进入和退出 Monitor 对象来实现办法同步和代码块同步的。monitor enter指令是在编译后插入到同步代码块的开始地位,而 monitor exit 是插入到办法完结处和异样处,JVM 要保障每个 monitor enter 必须有对应的 monitor exit 与之配对。任何对象都有一个 monitor 与之关联,当且一个 monitor 被持有后,它将处于锁定状态。

Java 1.6 为了缩小取得锁和开释锁带来的性能耗费,引入了“偏差锁”和“轻量级锁”,在 Java SE 1.6 中,锁一共有 4 种状态,级别从低到高顺次是:无锁状态 偏差锁状态 轻量级锁状态 重量级锁状态,这几个状态会随着竞争状况逐步降级。

留神:synchronized 能够润饰某个办法,也能够润饰某个对象。

执行 monitor enter 指令如果获取锁不胜利,会将该线程增加到该 monitor 对象对应的同步队列 SynchronizedQueue,当占用该 monitor 对象的线程执行 monitor out 时就会唤醒同步队列中的线程。

那么问题来了,唤醒线程时是抉择同步队列上哪一个线程呢?java8 默认抉择最近增加到同步队列中的那个线程。能够应用如下代码验证:

private static Object obj = new Object();

public static void main(String[] args) throws Exception {synchronized (obj) {newThread("t1");
        newThread("t2");
        newThread("t3");
        newThread("t4");
        newThread("t5");

        Thread.sleep(1000);
        System.out.println("main release");
    }

    System.out.println("main end");
    Thread.sleep(2000);
}

private static void newThread(String name) throws Exception {new Thread(() -> {synchronized (obj) {System.out.println(Thread.currentThread().getName() + "get");
        }
    }, name).start();
    Thread.sleep(100L);
}
复制代码

输入后果为:

同步队列和期待队列

晓得了 synchronized 基本概念之后,一起来看下Object.wait()/notify(),Monitor 对象 中蕴含一个同步队列(由 _cxq_EntryList 组成)和一个期待队列(_WaitSet)。

  • 被 notify 或 notifyAll 唤醒时依据 policy 策略抉择退出的队列(policy 默认为 0)
  • 退出同步块时依据 QMode 策略来唤醒下一个线程(QMode 默认为 0)

留神:synchronized 的同步队列和期待队列 与 基于 AQS(lock/condition) 的同步队列和期待队列实现原理相似,只不过前者是一个同步队列对应一个期待队列,而后者是一个同步队列能够对应多个期待队列。

synchronized 的同步队列和期待队列流程图如下所示:

到这里为止,咱们大抵理解了 synchronized 是如何工作的,以及它的同步队列和期待队列是如何配合的。

最初咱们思考 2 个问题:

1、为什么要有 Object.wait/notify,只应用 synchronized 不能也能实现线程阻塞而后被其余线程唤醒(告诉)么

2、执行 Object.wait/notify,为什么必须要在 synchronized 中呢

这里小伙伴们略微劳动片刻,思考下上述 2 个问题的起因。

对于第一个问题,只应用 synchronized 是为了简略的加解锁,而应用 Object.wait/notify 是为了实现被告诉后,再执行下一步动作的逻辑。如果 Object.wait 后没有任何逻辑的话,这里的 Object.wait 是没有意义的,能够间接去掉。

对于第二个问题,为什么必须要在 synchronized 中呢,咱们都晓得 synchronized 锁机制大都是为了保障原子性,因而咱们有理由置信,这里的起因大概率就是原子性。那么是为了什么的原子性呢?是为了保障在 Object.wait 时,将以后线程增加到_WaitSet 期待队列和 monitor out 唤醒其余线程的原子性;为了保障在 Object.notify 时,在将以后线程从 WaitSet 移到同步队列时,锁相干的线程状态不会发生变化。

参考:《2020 最新 Java 根底精讲视频教程和学习路线!》
链接:https://juejin.cn/post/694228…

正文完
 0