1.xdb中的使用例子

在xdb中,我们大概执行业务时的流程简化如下:

package org.example.testReentrantLock;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;public class Main {public static final ReentrantLock lock = new ReentrantLock();public static void main(String[] args) throws InterruptedException {new Thread(() -> {try {lock.lock();// 这里相当于执行业务逻辑,在事务内再次持有一次锁,加入到自己本地的LockList中lock.lock();System.out.println("1111");TimeUnit.SECONDS.sleep(2);lock.unlock();} catch (InterruptedException e) {e.printStackTrace();} finally {lock.unlock();}}, "a").start();TimeUnit.SECONDS.sleep(1);new Thread(() -> {try {lock.lock();System.out.println("2222");} finally {lock.unlock();}}, "b").start();}
}/*
1111
2222*/

思考:为啥我们用ReentrankLock而不是synchronized呢?因为:我们需要提供可重入的特性,而且释放是要控制在:事务完成后(不管是回滚了还是提交成功了)才释放锁,因此要使用这种显式锁。

2.源码分析

step1

public static final ReentrantLock lock = new ReentrantLock();

实现如下:

  public ReentrantLock() {sync = new NonfairSync();}

可以看出来,默认情况下,是非公平锁,想想目前我还没有遇到要用公平锁的情况。

step2

接下来是上锁:

lock.lock();
/*** Acquires the lock.获取锁** <p>Acquires the lock if it is not held by another thread and returns* immediately, setting the lock hold count to one.如果这个锁没有被其它线程持有,那么会立即获取锁,并且设置锁的持有次数为1** <p>If the current thread already holds the lock then the hold* count is incremented by one and the method returns immediately.如果当前线程已经持有锁,那么就会增加锁的持有数量,然后立即返回** <p>If the lock is held by another thread then the* current thread becomes disabled for thread scheduling* purposes and lies dormant until the lock has been acquired,* at which time the lock hold count is set to one.如果此锁被其它线程持有了,那么此线程立即变成不可用然后进入睡眠状态,直到锁被获取到那时,锁的持有数量被设置为1*/public void lock() {sync.acquire(1);}

进入到acquire里面:// && 符号的使用,前面为true才会走后门

    public final void acquire(int arg) {if (!tryAcquire(arg) &&// 这个很重要,如果没有获取到,也就是返回了false,那么肯定要检查阻塞acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();}

这里走非公平下的获取:

    static final class NonfairSync extends Sync {private static final long serialVersionUID = 7316153563782823691L;protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}}

再次进入看下非公平模式下如何获取锁的:

abstract static class Sync extends AbstractQueuedSynchronizer {private static final long serialVersionUID = -5179523762034025860L;/*** Performs non-fair tryLock.  tryAcquire is implemented in* subclasses, but both need nonfair try for trylock method.*/@ReservedStackAccessfinal boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();// 查看下当前的状态,这个state是加了volatile的,volatile int state;int c = getState();// 根据此状态位判断出来,如果没有被其它线程持有if (c == 0) {// 使用cas,如果当前是0,则设置为1if (compareAndSetState(0, acquires)) {// 设置当前线程占有了setExclusiveOwnerThread(current);return true;}}// 如果不是0,而且就是这个线程持有的else if (current == getExclusiveOwnerThread()) {  // 计数+1int nextc = c + acquires;if (nextc < 0) // overflowthrow new Error("Maximum lock count exceeded");// 设置下最新的计数setState(nextc);return true;}// 走到这,说明其它线程已经持有了(state既不是0,也不是自己占有)return false;}

既然没有获取到,那么肯定就要阻塞自己了

      acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

如何实现阻塞的呢?进去  // 可以发现aqs在没有获取到的时候,其实是先cas死心不改尝试获取下

/** Various flavors of acquire, varying in exclusive/shared and* control modes.  Each is mostly the same, but annoyingly* different.  Only a little bit of factoring is possible due to* interactions of exception mechanics (including ensuring that we* cancel if tryAcquire throws exception) and other control, at* least not without hurting performance too much.*//*** Acquires in exclusive uninterruptible mode for thread already in* queue. Used by condition wait methods as well as acquire.** @param node the node* @param arg the acquire argument* @return {@code true} if interrupted while waiting*/final boolean acquireQueued(final Node node, int arg) {boolean interrupted = false;try {for (;;) {// 可以看出来这里是aqs相对于synchronized的优化,没获取到暂时不死心// 这里依然再走一下尝试获取final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {// 走这里,说明还真获取到了setHead(node);p.next = null; // help GCreturn interrupted;}// 走到这说明真是获取不到了,那么应该是进入阻塞状态了if (shouldParkAfterFailedAcquire(p, node))// 这里可以看出来,是调用的park实现的阻塞interrupted |= parkAndCheckInterrupt();}} catch (Throwable t) {cancelAcquire(node);if (interrupted)selfInterrupt();throw t;}}

真的没办法了,阻塞自己呗

    private final boolean parkAndCheckInterrupt() {LockSupport.park(this);return Thread.interrupted();}

park

   public static void park(Object blocker) {// 要被阻塞的线程Thread t = Thread.currentThread();setBlocker(t, blocker);// 这里是真的阻塞了,是一个native方法U.park(false, 0L);setBlocker(t, null);}

【ReentrantLock源码分析】1.xdb中的使用 2.获取和阻塞(阻塞前的一些死心不改)的源码相关推荐

  1. 「源码分析」CopyOnWriteArrayList 中的隐藏知识,你Get了吗?

    前言 本觉 CopyOnWriteArrayList 过于简单,寻思看名字就能知道内部的实现逻辑,所以没有写这篇文章的想法,最近又仔细看了下 CopyOnWriteArrayList 的源码实现,大体 ...

  2. lodash源码分析之compact中的遍历

    小时候, 乡愁是一枚小小的邮票, 我在这头, 母亲在那头. 长大后,乡愁是一张窄窄的船票, 我在这头, 新娘在那头. 后来啊, 乡愁是一方矮矮的坟墓, 我在外头, 母亲在里头. 而现在, 乡愁是一湾浅 ...

  3. apollo源码分析 感知_Kitty中的动态线程池支持Nacos,Apollo多配置中心了

    目录 回顾昨日 nacos 集成 Spring Cloud Alibaba 方式 Nacos Spring Boot 方式 Apollo 集成 自研配置中心对接 无配置中心对接 实现源码分析 兼容 A ...

  4. lodash源码分析之baseFindIndex中的运算符优先级

    我悟出权力本来就是不讲理的--蟑螂就是海米:也悟出要造反,内心必须强大到足以承受任何后果才行. --北岛<城门开> 本文为读 lodash 源码的第十篇,后续文章会更新到这个仓库中,欢迎 ...

  5. 【FFMPEG源码分析】ffmpeg中context与AVClass,AVOption之间的关系

    通过前面三篇文章的分析大致了解了ffmpeg中demuxer/decoder模块的内部大致结构和数据处理流程.在阅读源码的过程中经常会看到XXXContext,AVClass xxx_class, A ...

  6. [pig4cloud框架源码分析] 03 - MyBatis中的sql语句日志打印

    文章目录 导读 pig4cloud框架配置 Mybatis Log Plugin 插件开启方式 插件说明 [TODO]源码分析 拦截器方案实现sql日志查看 参考资料 导读 使用MyBatis开发过程 ...

  7. UGUI源码分析:LayoutGroup中的纵横布局组件(HorizontalOrVerticalLayoutGroup)

    系列 UGUI源码分析系列总览 相关前置: UGUI CanvasUpdateSystem源码分析 UGUI源码分析:LayoutSystem布局系统 文章目录 系列 UML图一览 LayoutGro ...

  8. Linux内核源码分析—Linux内核中的嵌入式汇编

    转载请注明出处: http://blog.csdn.net/weifenghai/article/details/52794872   概述: 内核中分配文件描述符时找第一个0的位置的一个底层函数,了 ...

  9. java 最少使用(lru)置换算法_「Redis源码分析」Redis中的LRU算法实现

    如果对我的文章感兴趣.希望阅读完可以得到你的一个[三连],这将是对我最大的鼓励和支持. LRU是什么 LRU(least recently used)是一种缓存置换算法.即在缓存有限的情况下,如果有新 ...

最新文章

  1. python免费入门手册-python基础入门手册。。。。。。
  2. IT知识架构和操作系统简介1
  3. 你不得不掌握的thinkphp5
  4. html文本最小长度,CSS中处理不同长度文本的几种小技巧
  5. LeetCode-116. 填充每个节点的下一个右侧节点指针
  6. CSS3/jQuery创意盒子动画菜单
  7. matlab 查找脉冲产生时间,脉冲时间信号MATLAB表示
  8. 免费 | 开源操作系统年度盛会最新日程曝光,邀您一同开启烧脑模式!
  9. mysql 优化器提示_Mysql查询优化器
  10. 通信原理-数字基带传输
  11. python控制苹果手机触摸屏失灵怎么办_iPhone6触屏失灵,用一会就失灵,很恼火?...
  12. xpub ypub zpub ---- btc address
  13. 电脑win7系统开机密码忘记
  14. 【读书笔记】关键影响力:如何调动团队力量
  15. 【华为云会议开发指南】开发流程
  16. 关于insight数据库价格与价值的双重选择
  17. html盒子里的内容溢出,[经验] HTML页面中子盒子溢出了怎么办
  18. 王子与公主的爱情故事新结局
  19. vim的替换字符串的命令
  20. 高一计算机组装与维护教学总结,计算机组装与维护教学总结

热门文章

  1. CF Edu 47E. InterCity Travelling 期望线性,打表
  2. 详尽可能性模型(转载)
  3. Libra-Platform微服务平台之全链路蓝绿灰度发布
  4. 奋斗吧,程序员——第三十三章 今朝此为别,何处还相遇
  5. 程序员辞职信走红职场!干活累还是读书累?答:不快乐才是最累的
  6. 《SolidWorks 2012中文版从入门到精通》一6.2 查询
  7. .NET基础笔记(C#)
  8. SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord)
  9. r3 4300u和i3 10110u有什么区别
  10. B2C免运费1年记:京东拖垮小企业后再收费