在进行更近一步的了解Java锁的知识之前,我们需要先了解与锁有关的两个概念 CAS 与 AQS。关注我的公众号「Java面典」了解更多 Java 相关知识点。

CAS(Compare And Swap/Set)

概念

CAS函数,是比较并交换函数,它是原子操作函数。

原理

CAS 是基于乐观锁的原理进行操作的。它总是认为自己可以成功完成操作。当多个线程同时使用 CAS 操作一个变量时,只有一个会胜出,并成功更新,其余均会失败。失败的线程不会被挂起,仅是被告知失败,并且允许再次尝试或放弃操作。

实现

  1. 构造:CAS 包含 3 个参数CAS(V,E,N)。V 表示要更新的变量(内存值),E 表示预期值(旧的),N 表示新值;
  2. 比较并交换:当且仅当 V 值等于 E 值时,才会将 V 的值设为 N;如果 V 值和 E 值不同,则说明已经有其他线程做了更新,当前线程什么都不做;
  3. 返回:CAS 返回当前 V 的真实值。

ABA 问题

CAS 会导致“ABA 问题”。CAS 算法实现一个重要前提需要取出内存中某时刻的数据,而在下时刻比较并替换,那么在这个时间差内会导致数据的变化。

ABA 例子:比如说一个线程 one 从内存位置 V 中取出 A,这时候另一个线程 two 也从内存中取出 A,并且two 进行了一些操作变成了 B,然后 two 又将 V 位置的数据变成 A,这时候线程 one 进行 CAS 操作发现内存中仍然是 A,然后 one 操作成功。尽管线程 one 的 CAS 操作成功,但是不代表这个过程就是没有问题的。

ABA 解决方案:部分乐观锁的实现是通过版本号(version)的方式来解决 ABA 问题,乐观锁每次在执行数据的修改操作时,都会带上一个版本号,一旦版本号和数据的版本号一致就可以执行修改操作并对版本号执行+1 操作,否则就执行失败。因为每次操作的版本号都会随之增加,所以不会出现 ABA 问题,因为版本号只会增加不会减少。

AQS

概念

AQS即AbstractQueuedSynchronizer (抽象的队列式的同步器),AQS 定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock/Semaphore/CountDownLatch。

AQS 维护了一个 volatile int state(代表共享资源)和一个 FIFO 线程等待队列(多线程争用资源被阻塞时会进入此队列)。这里 volatile 是核心关键词,具体 volatile 的语义,在此不述。state 的访问方式有三种:

getState()

setState()

compareAndSetState()

原理(state 资源状态计数)

计数器:同步器的实现是 ABS 核心,以 ReentrantLock 为例,state 初始化为 0,表示未锁定状态。A 线程 lock()时,会调用 tryAcquire() 独占该锁并将 state+1。此后,其他线程再 tryAcquire() 时就会失败,直到 A 线程 unlock() 到 state=0(即释放锁)为止,其它线程才有机会获取该锁。

可重入锁:在 A 线程释放锁之前,A 线程自己是可以重复获取此锁的(state 会累加),这就是可重入锁的实现。

但要注意,获取多少次就要释放多么次,这样才能保证 state 是能回到零态的

资源共享方式

AQS 定义了两种资源共享方式:

  • Exclusive 独占资源:Exclusive(独占,只有一个线程能执行,如 ReentrantLock);
  • Share 共享资源:Share(共享,多个线程可同时执行,如Semaphore/CountDownLatch)。

一般来说,自定义同步器要么是独占方法,要么是共享方式,他们也只需实现 tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared 中的一种即可。但 AQS 也支持自定义同步器同时实现独占和共享两种方式,如 ReentrantReadWriteLock.

实现方式

AQS 只是一个框架,具体资源的获取/释放方式交由自定义同步器去实现。自定义同步器实现时主要实现以下几种方法:

1.isHeldExclusively():该线程是否正在独占资源。只有用到 condition 才需要去实现它。

2.tryAcquire(int):独占方式,尝试获取资源。成功则返回 true,失败则返回 false。

3.tryRelease(int):独占方式,尝试释放资源。成功则返回 true,失败则返回 false。

4.tryAcquireShared(int):共享方式,尝试获取资源。负数表示失败;0 表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。

5.tryReleaseShared(int):共享方式,尝试释放资源。如果释放后允许唤醒后续等待结点返回true,否则返回 false。

多线程与并发系列推荐

Java多线程并发05——那么多的锁你都了解了吗

Java多线程并发04——合理使用线程池

Java多线程并发03——什么是线程上下文,线程是如何调度的

Java多线程并发02——线程的生命周期与常用方法,你都掌握了吗

Java多线程并发01——线程的创建与终止,你会几种方式

Java多线程并发06——CAS与AQS的更多相关文章

  1. Java多线程并发07——锁在Java中的实现

    上一篇文章中,我们已经介绍过了各种锁,让各位对锁有了一定的了解.接下来将为各位介绍锁在Java中的实现.关注我的公众号「Java面典」了解更多 Java 相关知识点. 在 Java 中主要通过使用sy ...

  2. Java多线程并发08——锁在Java中的应用

    前两篇文章中,为各位带来了,锁的类型及锁在Java中的实现.接下来本文将为各位带来锁在Java中的应用相关知识.关注我的公众号「Java面典」了解更多 Java 相关知识点. 锁在Java中主要应用还 ...

  3. Java多线程并发05——那么多的锁你都了解了吗

    在多线程或高并发情境中,经常会为了保证数据一致性,而引入锁机制,本文将为各位带来有关锁的基本概念讲解.关注我的公众号「Java面典」了解更多 Java 相关知识点. 根据锁的各种特性,可将锁分为以下几 ...

  4. Java多线程并发工具类-信号量Semaphore对象讲解

    Java多线程并发工具类-Semaphore对象讲解 通过前面的学习,我们已经知道了Java多线程并发场景中使用比较多的两个工具类:做加法的CycliBarrier对象以及做减法的CountDownL ...

  5. Java 多线程并发编程一览笔录

    Java 多线程并发编程一览笔录 知识体系图: 1.线程是什么? 线程是进程中独立运行的子任务. 2.创建线程的方式 方式一:将类声明为 Thread 的子类.该子类应重写 Thread 类的 run ...

  6. (转载)java高并发:CAS无锁原理及广泛应用

    java高并发:CAS无锁原理及广泛应用   版权声明:本文为博主原创文章,未经博主允许不得转载,转载请注明出处. 博主博客地址是 http://blog.csdn.net/liubenlong007 ...

  7. 从火箭发场景来学习Java多线程并发闭锁对象

    从火箭发场景来学习Java多线程并发闭锁对象 倒计时器场景 在我们开发过程中,有时候会使用到倒计时计数器.最简单的是:int size = 5; 执行后,size—这种方式来实现.但是在多线程并发的情 ...

  8. Java多线程-并发容器

    Java多线程-并发容器 在Java1.5之后,通过几个并发容器类来改进同步容器类,同步容器类是通过将容器的状态串行访问,从而实现它们的线程安全的,这样做会消弱了并发性,当多个线程并发的竞争容器锁的时 ...

  9. Java多线程并发技术

    Java多线程并发技术 参考文献: http://blog.csdn.net/aboy123/article/details/38307539 http://blog.csdn.net/ghsau/a ...

随机推荐

  1. axios统一封装

    本文代码参考了网上别人的资料,经过修改而来 /** * Created by zxf on 2017/9/6. * 封装统一的ajax请求,统一拦截请求,对不同的请求状态封装 * 通常说, ajax ...

  2. (三)mybatis级联的实现

    mybatis级联的实现 开篇         级联有三种对应关系: 1.一对一(association):如学号与学生  2.一对多(collection):如角色与用户  3.多对多(discri ...

  3. 那些被刻意“阉割”的名人名言

    "天才是百分之一的灵感,百分之九十九的汗水",这句名言大家都知道的吧!不过还有好多人不知道的是这句名言还有后半句:"但百分之一的灵感甚至比百分之九十九的汗水更重要.&qu ...

  4. Gnome Ubuntu16安装Nvidia显卡396驱动,CUDA9.2以及cudnn9.2

    深度学习环境配置,安装Nvidia显卡驱动,CUDA以及cudnn OS:ubuntu 16.04;driver: nvidia 396;CUDA: 9.2cudnn: 9.2 卸载原有Nvidia驱 ...

  5. Flutter Widgets 之 BottomNavigationBar 和 BottomNavigationBarItem

    注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 BottomNavigationBar 和 BottomN ...

  6. LeetCode~1033.移动石子直到连续

    1033.移动石子直到连续 三枚石子放置在数轴上,位置分别为 a,b,c. 每一回合,我们假设这三枚石子当前分别位于位置 x, y, z 且 x < y < z.从位置 x 或者是位置 z ...

  7. 《前端面试加分项目》系列 企业级Vue瀑布流

    本文 GitHub github.com/ponkans/F2E 已收录,有一线大厂面试点思维导图,也整理了很多我的文档,欢迎Star和完善,大家面试可以参照考点复习.文末有福利~~ 前言 接水怪又来 ...

  8. Harbor镜像漏洞扫描

    Harbor镜像漏洞扫描 闲聊:我们知道 镜像安全也是容器化建设中一个很重要的环节,像一些商业软件如:Aqua就很专业但是收费也是很昂贵的,今天我们介绍下Harbor自带的镜像扫描器. 一.安装最新版 ...

  9. Java程序员常用的@Component、@Repository、@Controller、@Service系列【案例demo3】

    Java程序员常用的@Component.@Repository.@Controller.@Service系列[案例demo3]   很多程序员通过在类上使用@Repository.@Componen ...

  10. Python神经网络编程笔记

    神经元 想一想便知道,当一个人捏你一下以至于你会痛得叫起来的力度便是神经元的阈值,而我们构建的时候也是把这种现象抽象成一个函数,叫作激活函数. 而这里便是我们使用sigmoid函数的原因,它是一个很简 ...