Synchronized 原理:
方法级的同步是隐式, 即无需通过字节码指令来控制的, 它实现在方法调用和返回操 作之中。JVM 可以从方法常量池中的方法表结构(method_info Structure) 中的 ACC_SYNCHRONIZED 访问标志区分一个方法是否同步方法 。当方法调用时, 调用指 令将会 检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置, 如果设置了, 执行线 程将先持有 monitor (虚拟机规范中用的是管程一词), 然后再执行方法, 最后再方 法完成(无论是正常完成还是非正常完成)时释放 monitor 。
代码块的同步是利用 monitorenter 和 monitorexit 这两个字节码指令 。它们分别位于 同步代码块的开始和结束位置 。当 jvm 执行到 monitorenter 指令时, 当前线程试图 获取 monitor 对象的所有权, 如果未加锁或者已经被当前线程所持有, 就把锁的计数 器+1; 当执行 monitorexit 指令时, 锁计数器-1; 当锁计数器为 0 时, 该锁就被释放 了 。如果获取 monitor 对象失败, 该线程则会进入阻塞状态, 直到其他线程释放锁。
Lock原理:
-
Lock 的存储结构: 一个 int 类型状态值 (用于锁的状态变更), 一个双向链表 (用于存储等待中的线程)
-
Lock 获取锁的过程: 本质上是通过 CAS 来获取状态值修改, 如果当场没获取 到, 会将该线程放在线程等待链表中 。
-
Lock 释放锁的过程: 修改状态值, 调整等待链表 。
4.Lock 大量使用 CAS+自旋 。因此根据 CAS 特性, lock 建议使用在低锁冲突的 情况下 。
Lock 与 synchronized 的区别:
1.Lock 的加锁和解锁都是由 java 代码配合 native 方法 (调用操作系统的相关方 法) 实现的, 而 synchronize 的加锁和解锁的过程是由 JVM 管理的
2.当一个线程使用 synchronize 获取锁时, 若锁被其他线程占用着, 那么当前只 能被阻塞, 直到成功获取锁 。而 Lock 则提供超时锁和可中断等更加灵活的方式, 在未 能获取锁的 条件下提供一种退出的机制 。
3.一个锁内部可以有多个 Condition 实例, 即有多路条件队列, 而 synchronize 只有一路条件队列; 同样 Condition 也提供灵活的阻塞方式, 在未获得通知之前可以 通过中断线程以 及设置等待时限等方式退出条件队列 。
4.synchronize 对线程的同步仅提供独占模式, 而 Lock 即可以提供独占模式, 也 可以提供共享模式