范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

JDK内置锁深入探究

  一、序言
  本文讲述仅针对 JVM 层次的内置锁,不涉及分布式锁。
  锁有多种分类形式,比如公平锁与非公平锁、可重入锁与非重入锁、独享锁与共享锁、乐观锁与悲观锁、互斥锁与读写锁、自旋锁、分段锁和偏向锁/轻量级锁/重量级锁。
  下面将配合示例讲解各种锁的概念,期望能够达到如下目标:一是在生产环境中不错误地使用锁;二是在生产环境中选择恰当的锁。
  对锁了解不多的情况下,应该首先保证业务的正确性,然后考虑性能,比如万金油synchronized锁或者自带多重属性的ReentrantReadWriteLock锁。不因并发导致业务错误,不出现死锁。
  随着对锁的了解增多,需要更加精准地选择各类锁以保证更高的性能要求。 二、锁的分类
  Java 总共有两种加锁的方式:一是 synchronized 关键字,二是用 Lock 接口的实现类。
  需要通过加(互斥)锁来解决线程安全问题的锁称之为悲观锁;不通过加锁来解决线程安全问题的锁称之为乐观锁。
  锁的性能比较强:互斥锁 < 读写锁、自旋锁 < 乐观说。
  读写锁和自旋锁分别从两个不同角度提升锁的效率,前者通过共享读锁来提高效率;后者通过回避阻塞-唤醒上下文切换来提高效率。 (一)公平锁/非公平锁
  公平锁和非公平锁具体实现类有Semaphore、ReentrantLock和ReentrantReadWriteLock。
  公平与否是指参与竞争的线程是否都有机会获得锁,公平锁:多个线程按照申请锁的顺序来获取锁;非公平锁并不是按照申请锁的顺序来获取锁,极端情况下可能会有线程一直无法获取到锁。
  公平锁维护一个虚拟的先进先出队列,按照次序排队申请获取锁。 1、概念解读
  为何按锁的申请顺序按照先进先出的顺序获取锁能够保证公平?当采用先进先出的排队机制时,所有处于等待队列中的线程理论上都有机会获得锁,并且随着时间的推移,获得锁的机会越来越大。
  不是按照申请锁的顺序来获取锁如何解读?synchronized 锁是典型的非公平锁,表现形式是所有参与获取锁的线程是否能够获得锁是不可预测的。
  公平锁的深层次内涵是只要线程有获得锁的需求,在绝对的时间里,一定能够获得锁。比如服务器连接资源,不存在客户端连接不上的情况,这是公平锁的典型的应用。 2、锁代码层次表示
  Semaphore // 非公平锁 Semaphore unfairLock = new Semaphore(5); // 公平锁 Semaphore fairLock = new Semaphore(5,true);
  ReentrantLock // 非公平锁 ReentrantLock unfairLock = new ReentrantLock(); // 公平锁 ReentrantLock fairLock = new ReentrantLock(true);
  ReentrantReadWriteLock // 非公平锁 ReentrantReadWriteLock unfairLock = new ReentrantReadWriteLock(); // 公平可锁 ReentrantReadWriteLock fairLock = new ReentrantReadWriteLock(true);
  上面提到的 3 个锁的实现类能配置公平锁或者非公平锁,真正实现锁的公平与否是由AbstractQueuedSynchronizer抽象类的子类定义的。 3、优劣对比
  锁
  获取锁事件
  锁的效率
  备注
  公平锁
  可以乐观估计
  相对较低
  非公平锁
  饥饿状态
  相对较高
  如果对锁没有特别的要求,优先选用非公平锁
  公平锁的效率比非公平锁低的原因如下: 所有想获取锁的线程必须先到先进先出队列注册,排队才能获取锁,从获取锁的流程上增加额外的操作; 有队列必然涉及线程的阻塞与唤醒操作,增加了操作系统层次上下文切换调度开销。 (二)可重入锁/非可重入锁
  可重入锁是指某个线程获得特定锁后,在同一个线程内可以多次获得该锁。synchronized关键字、ReentrantLock和ReentrantReadWriteLock属于可重入锁,Jdk 内置除此之外其它的锁都是不可重新入锁。
  可重入锁有两个重要的特性:同一个线程、重复获取锁。 1、可重入锁必要性分析
  可重入锁能够避免同一线程多次获取锁时的死锁现象。 /**  * 竞争线程调用入口方法  */ public synchronized void facadeMethod(){     // 处理业务     innerMethod(); } public void innerMethod(){     // 处理业务 }
  只在调用入口方法上添加 synchronized 锁,内部调用链所涉及的方法都不添加锁,在线程竞争条件下也是线程安全的。这种条件下即使 synchronized 不是可重入锁,也不会发生死锁。原因如下:方法调用是以方法栈的形式调用的,在入口方法加锁相当于内部调用链的方法都锁的约束之下,因此是线程安全的。 2、非可重入锁危害程度分析
  假如 synchronized 不是可重入锁,业务层有死锁发生时,应用在测试环境压测必然能够发现,未进入生产环境便可提前处理。因为这种死锁是一种必然发生的事件,排查起来较为容易。
  当死锁发生时,第一步排查当前锁是否是可重入的,其次再考虑是否是业务层代码逻辑本身存在缺陷。 /**  * 竞争线程调用入口方法  */ public synchronized void facadeMethod(){     // 处理业务     innerMethod(); } public synchronized void innerMethod(){     // 处理业务 }
  可重入锁是对锁的一次改良,提高了开发效率是显而易见的,与此同时也给使用锁的用户造成不必要的困扰:在使用锁的过程中,是否可重入并不是避免死锁的充分条件。 (三)独享锁/共享锁
  独享锁是指该锁一次只能被一个线程所持有;共享锁是指该锁可被多个线程所持有。实现ReadWriteLock接口的锁,其中读锁是共享锁、写锁是独享锁。
  在内置的锁中,除了读写锁中的读锁是共享锁,其余皆是独享锁。 1、降低锁的颗粒度
  竞争线程在处理竞争资源时有如下四种情形:读读、读写、写读、写写,对于大部分应用来说,读操作的比写操作的频度要高,更清楚的表述是在大部分时间里读读是线程间处理竞争资源形态,因此降低锁的颗粒度现实意义比较明显。 2、共享读锁与乐观读锁
  共享锁是为了解决独占锁只能被一个线程占有的问题,它支持多个线程同时持有锁,本质上属于悲观锁的范畴。
  乐观读锁更为彻底,将加锁的环节取消,但通过特殊机制仍能够保证线程安全。
  加锁和释放锁是一个重操作,因此乐观读锁比共享读锁效率更高。
  锁的汇总 // 非公平可重入读写锁 ReentrantReadWriteLock unfairLock = new ReentrantReadWriteLock(); // 公平可重入读写锁 ReentrantReadWriteLock fairLock = new ReentrantReadWriteLock(true); (四)乐观锁/悲观锁
  乐观锁与悲观锁的内涵是当并发发生时处理并发同步的态度。悲观锁认为当并发事件发生时,被锁的对象一定会发生修改,如果放任不管,并发操作一定会给业务带来副作用。
  悲观锁需要加锁,乐观锁不加锁但仍能通过一定机制保证线程安全。
  互斥锁、自旋锁、读写锁都属于悲观锁。 1、典型乐观锁
  严格意义来讲,只有悲观锁才能称之为锁,乐观锁本身不通过加锁来解决并发问题,因此称之为乐观"锁"更合适。
  乐观"锁"处理并发问题有两种常见方式:一是以AtomicInteger为代表的原子操作类,这种处理方式本身不加锁,但仍能解决并发产生的问题;二是乐观锁StampedLock类中的乐观读。 (五)自旋锁
  自旋锁是相对于互斥锁而言的,本质上属于悲观锁的一种(仍然需要加锁)。 1、自旋锁的原理
  当线程申请获取锁时,发现已经被其它线程占有,此时不断的循环尝试获取锁,直到获取锁成功。线程自旋获取锁需要消耗 CPU,如果一直获取不到锁,线程会一直自旋,持续消耗 CPU。
  自旋锁是对线程申请获取锁时出现的阻塞与唤醒上下文切换的一种优化,即用 CPU 资源换取线程状态切换时间,当线程通过自旋获取锁的时间超过普通的阻塞-唤醒调度时间,那么就不适合选用自旋锁。 2、自旋锁使用场景及优缺点
  (1)使用场景
  如果持有锁的线程能在很短时间内释放锁资源,选用自旋锁非常合适。线程平均占有锁的时间很短,其它线程稍微等待(自旋)便能立刻获取锁,效率比阻塞-唤醒线程状态切换高得多。
  一般而言,竞争资源涉及内存计算时,占有锁的时间平均都比较短,适合自旋锁;对于磁盘读写 IO 操作、网络操作等,线程占有锁的时间平均较长,不适合使用自旋锁。
  代码块或者轻量级方法,线程竞争不激烈的场景下,适合自旋锁。
  (2)优缺点
  自旋锁尽可能的减少线程的阻塞,对于锁的竞争不激烈且占用锁时间非常短的代码块来说性能提升明显。自旋的时间消耗会小于线程阻塞挂起再唤醒的操作的消耗,回避了线程两次上下文切换。 3、自旋锁与乐观锁
  自旋锁与乐观锁的区别是很明显的,很多地方常用 CAS 技术对两者举例,以致于让它们的边界比较模糊。
  锁
  乐观(悲观)锁
  独占(共享)锁
  消耗 CPU 资源的目的
  提升效率优化核心点
  自旋锁
  悲观锁
  独占锁
  申请获取锁
  用 CPU 资源置换线程阻塞-唤醒调度时间
  乐观锁
  乐观锁
  共享锁
  比较与交换
  不加锁,如果需要处理线程问题,则采取相应的措施
  除了原子操作类中用乐观锁处理读写外,StampedLock类主要用到乐观读锁。 三、关键字锁
  synchronized关键字属于内置锁,可作用于对象和方法。添加到方法上的锁,锁到在哪里?
  对于实例方法,锁添加到持有方法的实例上;对于类方法,锁添加到类对象(Class 对象)上。 (一)感性认识
  关键字synchronized创建的是一把可重入的锁,不是简单的轻量级或者重量级的锁,也不是简单的公平与非公平锁。
  Java8 内置的synchronized是经过优化的锁,有偏向锁、轻量级锁、重量级锁等状态。
  重量级锁影响性能的根本原因是伴随着加锁与释放锁,竞争锁的工作线程发生上下文切换。 1、公平性分析
  锁处于轻量级时,因为不存在线程间获取锁的实质性碰撞行为,理论情况下"竞争"线程不存在饥饿状态的发生,因此属于公平锁。
  锁处于重量级时,无法保证竞争线程一定不存在饥饿状态发生,因此属于非公平锁。 2、非公平如何理解
  使用 synchronized 加锁的线程,没有先进先出的队列机制保证有序获取锁,因此它是非公平锁。
  (1)竞争线程随机获取锁?
  随机必然伴随着概率事件,获取锁既有成功的概率也有失败的概率,如果是严格随机,理论情况下是不存在饥饿状态发生的,这种情况下也就不属于非公平锁之说。
  竞争线程不是随机获取锁,尽管从线程的角度看像是一种"随机"行为,因此它是一把非公平锁。
  (2)竞争线程可预测获取锁?
  (重量级锁)在竞争锁条件下必然存在操作系统级别的(线程阻塞与唤醒)系统调度行为。操作系统的调度是按照既定的规则进行线程调度的,线程被操作系统唤醒,才有机会获取锁,因此可以粗略的理解获取锁的行为也是可以预测的。
  (3)可预测获取锁是公平锁?
  假如操作系统是按照优先级高低完成线程调度的,极端情况下,新申请获取锁的线程优先级永远比等待队列中线程优先级要高,那么等待队列必然会发生饥饿状态,因此尽管获取锁的行为是有规律的、能够预测的,它依然是非公平锁。 3、互斥锁
  互斥锁即重量级锁,互斥依靠通过操作系统来实现。
  互斥的表现形式如下:当多线程竞争资源条件下,未获得锁的其它线程均处于阻塞状态,当持有锁的线程释放锁后,阻塞状态的线程被唤醒竞争获取锁,未获取成功的锁继续阻塞,如此循环。线程调度需要操作系统切换上下文,占用 CPU 时间,影响性能。
  操作系统 CPU 时间片大致可分为两类,一是工作时间;二是调度时间,调度时间越长相应的便会缩短工作时长。 (二)锁的膨胀
  这里不讲锁的膨胀过程,只讲锁在膨胀过程中涉及的中间状态,以及如何理解。锁的膨胀是单向的,只能升级不能降级。 1、偏向锁
  线程间不存在锁的竞争行为,至多只有一个线程有获取锁的需求,常见场景为单线程程序。 2、轻量级锁
  线程间存在锁的伪竞争行为,即同一时刻绝对不会存在两个线程申请获取锁,各线程尽管都有使用锁的需求,但是是交替使用锁。 3、重量级锁
  线程间存在锁的实质性竞争行为,线程间都有获取锁的需求,但是时间不可交错,互斥锁的阻塞等待。 四、接口锁(一)Lock
  Lock是所有接口实现类的父类接口,定义了锁操作的基本规范。 public interface Lock {     // 阻塞等待获取锁     void lock();     // 阻塞等待获取锁(可相应中断)     void lockInterruptibly() throws InterruptedException;     // 非阻塞获取锁     boolean tryLock();     // 等待指定时间非阻塞获取锁     boolean tryLock(long time, TimeUnit unit) throws InterruptedException;     // 释放锁     void unlock(); } (二)StampedLock1、StampedLock优势高性能
  StampedLock在读线程非常多而写线程较少的场景下性能非常高,乐观读锁属于无锁编程,可以简单理解为没有加锁。 回避写锁饥饿
  非公平读写锁在读多写少的场景下可能发生写锁饥饿,而在高并发的场景下,都会优先使用非公平锁。StampedLock能解决这个矛盾问题:既能使用非公平读写锁,又能回避写锁饥饿。
  回避写锁饥饿的机制是能将任一读锁转化为写锁。 2、典型应用排它写锁/**  * 排它写锁(an exclusively locked method)  */ void move(double deltaX, double deltaY) {     long stamp = stampedLock.writeLock();     try {         x += deltaX;         y += deltaY;     } finally {         stampedLock.unlockWrite(stamp);     } }
  排它写锁能安全的修改数据,在为释放锁之前,其它线程无法获取锁。
  此种方式可能会发生写锁饥饿的情况。 排它写锁(改进)
  普通写锁可能会发生写锁饥饿,下面方式能够避免写锁饥饿——读锁转写锁。 /**  * 无饥饿写锁  */ void moveNoHunger(double deltaX, double deltaY) {     long stamp = stampedLock.readLock();     try {         while (x == 0.0 && y == 0.0) {             long ws = stampedLock.tryConvertToWriteLock(stamp);             if (ws != 0L) {                 stamp = ws;                 x += deltaX;                 y += deltaY;                 break;             } else {                 stampedLock.unlockRead(stamp);                 stamp = stampedLock.writeLock();             }         }     } finally {         stampedLock.unlock(stamp);     } } 乐观锁/**  * 乐观读锁  */ double distanceFromOrigin() { // A read-only method     long stamp = stampedLock.tryOptimisticRead();     double currentX = x, currentY = y;     if (!stampedLock.validate(stamp)) {         stamp = stampedLock.readLock();         try {             currentX = x;             currentY = y;         } finally {             stampedLock.unlockRead(stamp);         }     }     return Math.sqrt(currentX * currentX + currentY * currentY);

面对大数据杀熟你是沉默的大多数么?3月1日,北京市消协在官网公布了互联网消费大数据杀熟问题调查活动的最新结果86。91的受访者认为自己有过被大数据杀熟的经历,82。37的受访者认为互联网消费大数据杀熟问题普遍存在,在Ubuntu上有什么必装的实用软件?浏览器Ubuntu以Firefox为默认浏览器。自从Quantum版本发布以来,Firefox已有显著提升。就个人而言,我经常使用多个浏览器来应对不同的工作。GoogleChrom用以规避制裁?加密货币或许并非可行之选智通财经APP获悉,随着美国及其盟友对俄罗斯采取严厉的制裁措施,俄罗斯经济及货币都受到严重打击。据悉,美国正在尝试回应利用加密货币规避制裁的行为,比特币及以太坊等加密货币可能将受到华为从3200万销量到2。4亿,用了7年,再跌到3500万,仅2年虽然很多网友不愿意承认,但却又不得不接受一个事实,那就是华为手机在多轮打压之下,真的是跌入谷底了。按照2021年Odmi的数据,华为手机的销量为3500万台,排名全球第9,同比下滑自动洗碗机的使用体验作为一个懒惰的人,我真的不想洗碗。自从我开始使用洗碗机以来,我发现它不仅可以用来洗碗,还可以使用很多黑色技术,这给我的生活带来了充分的幸福感。接下来,让我告诉你。许多功能因为我的厨6000mAh和6400万三摄,跌至738元,还能防辐射千元机和百元机虽然差不多多钱,但是配置的差距就非常大了,站在小编的角度看,购买千元机是非常划算的,处理器有骁龙870,天玑1200,骁龙778G等等,口碑都不错,已经进入了千元市场spring事务失效的几种场景以及原因前言spring事务失效场景可能大家在很多文章都看过了,所以今天就水一篇,看大家能不能收获一些不一样的东西。直接进入主题spring事务失效场景以及原因1场景一service没有托营收缩水2574亿,芯片份额从7降至1,华为的冬天比想象中更寒冷文BU审核子扬校对知秋春天的脚步已近,各地纷纷回暖。但是,华为却依旧处于寒冬之中,而且这个冬天比想象中的更漫长,也更寒冷。营收缩水明显芯片断供危机与华为设备威胁国家安全的论调,华为为啥一到冬天起床就特别困难?真不是因为懒进入寒冷的冬季,很多人都有早上起床困难的问题。不管闹钟响了几次,总是感觉睡不醒,被窝里面好暖好舒服,哪里都不想伸出来。这是咋回事儿?难道一到冬天,人也会像有些动物一样需要冬眠吗?今上市公司探路元宇宙社区本报记者李乔宇元宇宙落地又添新例。一件件艺术品陈列在展厅两侧,人们可以超越空间的界限最大程度地近距离观察作品。也无须在意艺术管理禁止大声喧哗的规则,只需轻轻点击,即可与身边参观者艺中科院发布科技支撑双碳战略行动计划光明日报北京3月2日电(记者齐芳)中国科学院2日公布中国科学院科技支撑碳达峰碳中和战略行动计划(以下简称行动计划),将在科技战略研究基础前沿交叉创新关键核心技术突破新技术综合示范人
荣耀在马来西亚发布一款新机,售价约合1659。9起最近一段时间不少国产品牌都开始在海外发力,比如,小米就在海外发布了两款红米新机,而荣耀也在马来西亚发布了荣耀X95G。图源网络侵删外观方面,荣耀X95G总体来看颜值依然很高,正面配独家隆基股份新电池技术预计在第四季度量产21世纪经济报道记者曹恩惠上海报道4月2日,21世纪经济报道记者获悉,隆基股份新电池技术预计在今年第四季度实现量产。近期,隆基股份在下一代电池技术的布局和研发消息频频。今年3月14又是华为?鸿蒙有了编程语言,芯片也要架构自研我懂你要问的了,华为愿意和ARM继续合作,也研发了自主芯片架构这是华为消费者BG负责人余承东的表态,2019年9月9日那场IFA年度交流大会期间,如此令外界惊诧的重磅消息披露,回应工信部重拳推进打猫断卡全力整治电信网络诈骗如何进一步加强信息通信行业防范治理电信网络诈骗?工信部网络安全管理局相关负责人在接受记者专访时表示,当前新型诈骗手法层出不穷,各类即时通信工具社交网站等成为诈骗的主渠道。工信部高度全国AIOMO数字化转型优秀在线教学案例征集活动通知关于组织开展全国AIOMO数字化转型优秀在线教学案例征集活动通知近日全国经历了疫情倒春寒,在居家学习期间,学生们的线上学习效果能否保证是学校和家长的关切。各学校积极响应迅速行动,为MotoG22在印度发布在即,edgeS价比百元机,买早的网友直呼心碎上个月,摩托罗拉刚刚在欧洲推出了MotoG22。但现在,一份新报告显示,该公司正准备在不久的将来在印度推出这款智能手机。据知情人士透露,根据91Mobiles的一份报告,该品牌计划Edge100发布,iPhone12一夜跌至爱疯价,网友直呼太感人基于Chromium的MicrosoftEdge100正式发布,在更新日志中,微软重点介绍了5个值得注意的功能更新。首先,最明显的变化是新版本启用了三位数的UserAgent字符串小米11ultra降价,网友直呼真香小米11ultra这一阶段降价到了3999起步,小米11u各项都是非常能打的,GN2双imx586的影像组合,直接在今年依旧暴杀多数旗舰。而其双67w的充电,目前为止也不会太过落后手机丢了,支付宝和微信里的钱是不是就没了?里面的钱还安全吗?手机丢失,不仅仅意味著手机里的聊天记录照片文件账户信息有暴露的风险,在这个快捷支付电子现金的时代,手机已经成为绝大多数人钱包的替代品。和银行卡绑定的支付宝微信在手机丢失时也一样会对微信拍一拍撤回有痕迹吗?怎么进行撤回?微信拍一拍可谓是让大家又爱又恨的一个功能了,自上线以来就饱受大家的吐槽,如果不小心拍了别人,尤其是自己的上司和老板,那尴尬程度简直真的可以扣出个三室一厅。幸好,微信拍一拍是可以撤回数字货币概念中蕴藏潜能的4只优质股名单1楚天龙现价24。49主营高端智能卡及配套软件智能终端设备数字档案应用平台系统和安全解决方案的供应,热点题材数字货币电子身份解读,楚天龙今年2月公布公司在移动支付领域蓄积了多年技术