| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> Java知识库 -> 深入理解 synchronized 关键字(关于对象头和锁的升级) -> 正文阅读 |
|
[Java知识库]深入理解 synchronized 关键字(关于对象头和锁的升级) |
文章目录深入理解 volatile 关键字 synchronized 关键字1. 概述?先需要明确的?点是:Java多线程的锁都是基于对象的,Java中的每?个对象都可以作为?个锁。 说到锁,我们通常会谈到 synchronized 这个关键字。它翻译成中?就是“同步”的意思。
2. synchronized 的四种锁状态Java 6 为了减少获得锁和释放锁带来的性能消耗,引?了“偏向锁”和“轻量级锁“。 在Java 6 以前,所有的锁都是”重量级“锁。所以在Java 6 及其以后,?个对象其实有四种锁状态,它们级别由低到?依次是:
?锁就是没有对资源进?锁定,任何线程都可以尝试去修改它,?锁在这?不再细讲。
2.1 Java对象头前?我们提到,Java的锁都是基于对象的。?先我们来看看?个对象的“锁”的信息是存放在什么地?的。 可以看到,当对象状态为偏向锁时, Mark Word 存储的是偏向的线程ID;当状态为轻量级锁时, Mark Word 存储的是指向线程栈中 Lock Record 的指针;当状态为重量级锁时, Mark Word 为指向堆中的 monitor 对象的指针。 2.2 偏向锁Hotspot的作者经过以往的研究发现?多数情况下锁不仅不存在多线程竞争,?且总是由同?线程多次获得,于是引?了偏向锁。 偏向锁会偏向于第?个访问锁的线程,如果在接下来的运?过程中,该锁没有被其他的线程访问,则持有偏向锁的线程将永远不需要触发同步。也就是说,偏向锁在资源?竞争情况下消除了同步语句,连CAS操作都不做了,提?了程序的运?性能。
偏向锁实现原理 ?个线程在第?次进?同步块时,会在对象头和栈帧中的锁记录?存储锁的偏向的线程ID。当下次该线程进?这个同步块时,会去检查锁的Mark Word??是不是放的??的线程ID。 如果是,表明该线程已经获得了锁,以后该线程在进?和退出同步块时不需要花费CAS操作来加锁和解锁 ; 如果不是,就代表有另?个线程来竞争这个偏向锁。这个时候会尝试使?CAS来替换Mark Word??的线程ID为新线程的ID,这个时候要分两种情况:
CAS: Compare and Swap 线程竞争偏向锁 图中涉及到了lock record指针指向当前堆栈中的最近?个lock record,是轻量级锁按照先来先服务的模式进?了轻量级锁的加锁。 偏向锁的升级 偏向锁会等到有竞争情况下时才会进行升级。 在偏向锁升级的过程中,会先暂停持有偏向锁的线程,将偏向锁升级为轻量级锁,最后再将其唤醒,这个过程还是比较耗费资源的。
所以如果应用程序中的锁一般处于竞争状态,可以关闭偏向锁,让其默认开始时为轻量级锁 2.3 轻量级锁轻量级锁主要使用自旋的方式来进行加锁。 ?旋:不断尝试去获取锁,?般?循环来实现。 轻量级锁的加锁 JVM会为每个线程在当前线程的栈帧中创建?于存储锁记录的空间,我们称为Displaced Mark Word。如果?个线程获得锁的时候发现是轻量级锁,会把锁的Mark Word复制到??的Displaced Mark Word??。 然后线程尝试?CAS将锁的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,表示Mark Word已经被替换成了其他线程的锁记录,说明在与其它线程竞争锁,当前线程就尝试使??旋来获取锁。 ?旋是需要消耗CPU的,如果?直获取不到锁的话,那该线程就?直处在?旋状态,??浪费CPU资源。解决这个问题最简单的办法就是指定?旋的次数,例如让其循环10次,如果还没获取到锁就进?阻塞状态。 但是JDK采?了更聪明的?式——适应性?旋,简单来说就是线程如果?旋成功了,则下次?旋的次数会更多,如果?旋失败了,则?旋的次数就会减少。 ?旋也不是?直进?下去的,如果?旋到?定程度(和JVM、操作系统相关),依然没有获取到锁,称为?旋失败,那么这个线程会阻塞。同时这个锁就会升级成重量级锁。 2.4 重量级锁重量级锁依赖于操作系统的互斥量(mutex) 实现的,?操作系统中线程间状态的转换需要相对?较?的时间,所以重量级锁效率很低,但被阻塞的线程不会消耗CPU。 前?说到,每?个对象都可以当做?个锁,当多个线程同时请求某个对象锁时,对象锁会设置?种状态?来区分请求的线程:
当?个线程尝试获得锁时,如果该锁已经被占?,则会将该线程封装成? 当线程释放锁时,会从Contention List或EntryList中挑选?个线程唤醒,被选中的线程叫做 Heir presumptive 即假定继承?,假定继承?被唤醒后会尝试获得锁,但 synchronized 是?公平的,所以假定继承?不?定能获得锁。这是因为对于重量级锁,线程先?旋尝试获得锁,这样做的?的是为了减少执?操作系统同步操作带来的开销。如果?旋不成功再进?等待队列。这对那些已经在等待队列中的线程来说,稍微显得不公平,还有?个不公平的地?是?旋线程可能会抢占了Ready线程的锁。 如果线程获得锁后调? Object.wait ?法,则会将线程加?到WaitSet中,当 2.5 总结锁的升级流程
2.6 各个锁的优缺点对比 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 12:06:50- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |