首页 > 编程知识 正文

java异常分类,java 锁的使用场景

时间:2023-05-03 14:04:39 阅读:155986 作者:3822

[基础科目]--[锁]----锁分类mp.weixin.qq.com

前言

Java提供了丰富的锁种类,每个锁根据其特性可以在适当的场景中表现出非常高的效率。 本文旨在通过实例向读者介绍锁相关的源代码(本文的源代码来自JDK 8)、使用场景,介绍主流锁的知识点以及应用不同锁的场景。

锁的分类

Java中出现的几个锁的基本概念如图所示

乐观摇滚和悲观摇滚

乐观锁和悲观锁是广义的概念,体现了看线程同步的不同角度。在Java和数据库中都有与这个概念对应的实用。

悲观锁:对于同一数据的并发操作,悲观锁认为自己使用数据时一定会有另一个线程修改数据,所以在获取数据时先锁定,避免其他线程修改数据。 在Java中,同步关键字和Lock的实现类是悲观锁定。

乐观锁:认为其他线程在使用数据时不会修改数据,所以不添加锁,只是在更新数据时确定其他线程是否更新了数据。 如果数据没有更新,当前线程将成功写入自己修改的数据。 如果其他线程正在更新数据,请根据实现方法执行不同的操作(例如报告错误或自动重试)。

乐观锁定在Java中通过使用无锁定编程来实现,最常用的是CAS算法,在Java原子类中的增量操作通过CAS自旋来实现。

从上述概念说明可以看出,以下内容。

悲观锁定适用于写入操作较多的场景,先锁定可以保证写入操作时的数据正确。

乐观锁适用于读取操作较多的场景,不上锁的特点可以大幅度提高读取操作的性能。

虽然仅从概念上来说是抽象的,但是让我们看一下如何调用乐观锁和悲观锁的示例:

调用方法示例表明,悲观锁基本上先显式锁定,然后再操作同步资源,而乐观锁直接操作同步资源。

自旋锁定VS自适应自旋锁定

在介绍自旋锁之前,为了理解自旋锁的概念,需要介绍一些前提知识。 您知道,要阻止或唤醒Java线程,操作系统必须在CPU状态之间切换才能完成,这种切换需要花费一些处理器时间。 如果同步代码块的内容过于简单,则状态转换可能比用户代码的执行时间长。 此时,为了优化该消耗,引入了自旋锁。当存在具有锁的线程时,不是其他线程直接挂起,而是等一下,等待上一个线程的执行结束,从而实现线程切换的额外开销

从定义中也可以看出,自旋锁有缺陷,如果待机的线程长时间不解除锁定,自选待机的效果就会变低,比线程切换更费时间。 因此,需要添加限制旋转次数的阈值。 将默认值更改为10,-XX:PreBlockSpin。 数量到达后就不再旋转,挂起线程。

自旋锁的实现原理也同样是CAS,在AtomicInteger中调用unsafe进行自增量操作的源代码do-while循环是一种自旋操作,如果数值修正失败,循环将执行自旋直到修正成功

旋转锁在JDK1.4.2中引入,并使用-XX: UseSpinning打开。 在JDK 6中默认启用,引入了自适应自旋锁定(自适应自旋锁定)。

适应意味着自旋的时间(次数)不再固定,是由上次花在同一把钥匙上的自旋时间和钥匙所有者的状态决定的。 如果旋转等待刚刚在同一锁定对象上被锁定,且具有锁定的线程正在运行,则虚拟机可以认为这次旋转很可能再次成功,并且旋转等待可以持续相对较长的时间。 如果对于特定的锁很少可能成功获取自旋,则在稍后尝试获取该锁时可以省略自旋过程,而不直接阻塞线程从而浪费处理器资源。

自旋锁还有其他三种常见的锁定形式:TicketLock、CLHlock和MCSlock。 文中只作名词介绍,不作深入说明。 感兴趣的学生可以自己查阅相关资料。

公平锁定和非公平锁定

公平锁:的多个线程按照申请锁的顺序获得锁。

异步锁:以非顺序取得锁,多个线程取得锁顺序不是申请锁的顺序、之后有可能申请的先取得锁、优先顺序反转、或引起饥饿现象.

如图所示,打水人排队从管理者处取得打水资格后打水,与行列一样先出后顺序执行。 谁先拿钥匙,公平锁门。

如图所示,打水的人排队从管理员那里取得打水的资格,然后可以插队拿钥匙。 是不公平的关键。

可重入锁和非可重入锁

可重构锁:也称为递归锁,可以在多个层获得锁。 当外层申请锁后,内层仍然可以使用锁且不发生锁(前提是它们是同一对象或类)的锁称为可配置锁。 例如,返回锁定、同步等

图为可以突入锁定同步的使用

可重构锁:与可重构锁相反,不能进行递归调用,在递归调用中会发生死锁。

独占锁和共享锁

简朴的导师和共享锁是一个概念,类似于悲观锁和乐观锁。 垄断锁:也称为列

他锁,该锁每一次只能有一个线程持有。比如当数据A被线程T加锁后,其他线程不可用再对数据A加任何其他的锁.只有获取该排它锁的线程可以对数据进行查看和修改.JDK中的synchronized和Lock实现类都是独占锁.

共享锁:该锁可以被多个线程共有.如果线程T对数据A加上共享锁后,则其他线程只能对A再加共享锁,不能加排它锁。获得共享锁的线程只能读数据,不能修改数据.

俭朴的导师与共享锁也是通过AQS来实现的,通过实现不同的方法,来实现独享或者共享.

分段锁

分段锁 其实是一种锁的设计思想,他并不是一种锁.典型的实现就是ConcurrentHashMap,其并发操作就是使用分段锁来设计实现的以达到高效的并发操作.

结语

本文Java中常用的锁以及常见的锁的概念进行了基本介绍,接下来的章节小哈会对照JDK的源码实现来详解介绍各个类型锁的实现和原理.

其实Java本身已经对锁本身进行了良好的封装,降低了研发同学在平时工作中的使用难度。但是研发同学也需要熟悉锁的底层原理,不同场景下选择最适合的锁。而且源码中的思路都是非常好的思路,也是值得大家去学习和借鉴的。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。