Java concurrency之非公平锁_动力节点Java学院整理

发布时间 - 2026-01-11 01:50:50    点击率:

获取非公平锁(基于JDK1.7.0_40)

非公平锁和公平锁在获取锁的方法上,流程是一样的;它们的区别主要表现在“尝试获取锁的机制不同”。简单点说,“公平锁”在每次尝试获取锁时,都是采用公平策略(根据等待队列依次排序等待);而“非公平锁”在每次尝试获取锁时,都是采用的非公平策略(无视等待队列,直接尝试获取锁,如果锁是空闲的,即可获取状态,则获取锁)。 

1. lock()

lock()在ReentrantLock.java的NonfairSync类中实现,它的源码如下:
final void lock() {
  if (compareAndSetState(0, 1))
    setExclusiveOwnerThread(Thread.currentThread());
  else
    acquire(1);
}

说明:

lock()会先通过compareAndSet(0, 1)来判断“锁”是不是空闲状态。是的话,“当前线程”直接获取“锁”;否则的话,调用acquire(1)获取锁。

(01) compareAndSetState()是CAS函数,它的作用是比较并设置当前锁的状态。若锁的状态值为0,则设置锁的状态值为1。

(02) setExclusiveOwnerThread(Thread.currentThread())的作用是,设置“当前线程”为“锁”的持有者。

“公平锁”和“非公平锁”关于lock()的对比

  1. 公平锁   -- 公平锁的lock()函数,会直接调用acquire(1)。
  2. 非公平锁 -- 非公平锁会先判断当前锁的状态是不是空闲,是的话,就不排队,而是直接获取锁。

2. acquire()

acquire()在AQS中实现的,它的源码如下:

public final void acquire(int arg) {
  if (!tryAcquire(arg) &&
    acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
    selfInterrupt();
}

(01) “当前线程”首先通过tryAcquire()尝试获取锁。获取成功的话,直接返回;尝试失败的话,进入到等待队列依次排序,然后获取锁。

(02) “当前线程”尝试失败的情况下,会先通过addWaiter(Node.EXCLUSIVE)来将“当前线程”加入到"CLH队列(非阻塞的FIFO队列)"末尾。

(03) 然后,调用acquireQueued()获取锁。在acquireQueued()中,当前线程会等待它在“CLH队列”中前面的所有线程执行并释放锁之后,才能获取锁并返回。如果“当前线程”在休眠等待过程中被中断过,则调用selfInterrupt()来自己产生一个中断。

“公平锁”和“非公平锁”关于acquire()的对比

公平锁和非公平锁,只有tryAcquire()函数的实现不同;即它们尝试获取锁的机制不同。这就是我们所说的“它们获取锁策略的不同所在之处”!

非公平锁的tryAcquire()在ReentrantLock.java的NonfairSync类中实现,源码如下:

protected final boolean tryAcquire(int acquires) {
  return nonfairTryAcquire(acquires);
}

nonfairTryAcquire()在ReentrantLock.java的Sync类中实现,源码如下:

final boolean nonfairTryAcquire(int acquires) {
  // 获取“当前线程”
  final Thread current = Thread.currentThread();
  // 获取“锁”的状态
  int c = getState();
  // c=0意味着“锁没有被任何线程锁拥有”
  if (c == 0) {
    // 若“锁没有被任何线程锁拥有”,则通过CAS函数设置“锁”的状态为acquires。
    // 同时,设置“当前线程”为锁的持有者。
    if (compareAndSetState(0, acquires)) {
      setExclusiveOwnerThread(current);
      return true;
    }
  }
  else if (current == getExclusiveOwnerThread()) {
    // 如果“锁”的持有者已经是“当前线程”,
    // 则将更新锁的状态。
    int nextc = c + acquires;
    if (nextc < 0) // overflow
      throw new Error("Maximum lock count exceeded");
    setState(nextc);
    return true;
  }
  return false;
}

说明:

根据代码,我们可以分析出,tryAcquire()的作用就是尝试去获取锁。

(01) 如果“锁”没有被任何线程拥有,则通过CAS函数设置“锁”的状态为acquires,同时,设置“当前线程”为锁的持有者,然后返回true。

(02) 如果“锁”的持有者已经是当前线程,则将更新锁的状态即可。

(03) 如果不术语上面的两种情况,则认为尝试失败。

“公平锁”和“非公平锁”关于tryAcquire()的对比
公平锁和非公平锁,它们尝试获取锁的方式不同。

公平锁在尝试获取锁时,即使“锁”没有被任何线程锁持有,它也会判断自己是不是CLH等待队列的表头;是的话,才获取锁。

而非公平锁在尝试获取锁时,如果“锁”没有被任何线程持有,则不管它在CLH队列的何处,它都直接获取锁。

释放非公平锁(基于JDK1.7.0_40)

非公平锁和公平锁在释放锁的方法和策略上是一样的。

总结

公平锁和非公平锁的区别,是在获取锁的机制上的区别。表现在,在尝试获取锁时 —— 公平锁,只有在当前线程是CLH等待队列的表头时,才获取锁;而非公平锁,只要当前锁处于空闲状态,则直接获取锁,而不管CLH等待队列中的顺序。

只有当非公平锁尝试获取锁失败的时候,它才会像公平锁一样,进入CLH等待队列排序等待。


# Java  # 非公平锁  # concurrency  # Java线程公平锁和非公平锁的差异讲解  # java 线程公平锁与非公平锁详解及实例代码  # java非公平锁知识点实例详解  # 都是  # 会先  # 类中  # 它在  # 而非  # 值为  # 则将  # 是在  # 也会  # 就不  # 这就是  # 是一样的  # 之处  # 两种  # 我们可以  # 会像  # 过程中  # 情况下  # 简单点  # 直接调用 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 如何在万网开始建站?分步指南解析  Laravel如何发送系统通知_Laravel Notifications实现多渠道消息通知  如何基于云服务器快速搭建网站及云盘系统?  Laravel如何生成API文档?(Swagger/OpenAPI教程)  Laravel如何使用Eloquent进行子查询  使用豆包 AI 辅助进行简单网页 HTML 结构设计  Laravel怎么配置S3云存储驱动_Laravel集成阿里云OSS或AWS S3存储桶【教程】  Laravel如何升级到最新的版本_Laravel版本升级流程与兼容性处理  Laravel如何实现模型的全局作用域?(Global Scope示例)  javascript中的try catch异常捕获机制用法分析  微信小程序 配置文件详细介绍  Laravel如何实现本地化和多语言支持?(i18n教程)  详解jQuery中的事件  Win11怎么开启自动HDR画质_Windows11显示设置HDR选项  为什么php本地部署后css不生效_静态资源加载失败修复技巧【技巧】  Laravel如何集成微信支付SDK_Laravel使用yansongda-pay实现扫码支付【实战】  惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?  如何快速配置高效服务器建站软件?  Android GridView 滑动条设置一直显示状态(推荐)  HTML5空格和nbsp有啥关系_nbsp的作用及使用场景【说明】  Laravel如何设置自定义的日志文件名_Laravel根据日期或用户ID生成动态日志【技巧】  通义万相免费版怎么用_通义万相免费版使用方法详细指南【教程】  西安专业网站制作公司有哪些,陕西省建行官方网站?  公司网站制作价格怎么算,公司办个官网需要多少钱?  如何安全更换建站之星模板并保留数据?  Win11应用商店下载慢怎么办 Win11更改DNS提速下载【修复】  微信小程序 input输入框控件详解及实例(多种示例)  网站页面设计需要考虑到这些问题  Laravel队列由Redis驱动怎么配置_Laravel Redis队列使用教程  如何基于云服务器快速搭建个人网站?  如何注册花生壳免费域名并搭建个人网站?  Python面向对象测试方法_mock解析【教程】  Laravel如何安装使用Debugbar工具栏_Laravel性能调试与SQL监控插件【步骤】  Laravel如何使用Seeder填充数据_Laravel模型工厂Factory批量生成测试数据【方法】  消息称 OpenAI 正研发的神秘硬件设备或为智能笔,富士康代工  Laravel如何处理文件上传_Laravel Storage门面实现文件存储与管理  Laravel如何使用Vite进行前端资源打包?(配置示例)  南京网站制作费用,南京远驱官方网站?  如何在阿里云域名上完成建站全流程?  桂林网站制作公司有哪些,桂林马拉松怎么报名?  如何使用 jQuery 正确渲染 Instagram 风格的标签列表  怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?  Laravel事件监听器怎么写_Laravel Event和Listener使用教程  Laravel Facade的原理是什么_深入理解Laravel门面及其工作机制  音响网站制作视频教程,隆霸音响官方网站?  企业网站制作这些问题要关注  简单实现Android验证码  Laravel如何连接多个数据库_Laravel多数据库连接配置与切换教程  jQuery中的100个技巧汇总  如何选择可靠的免备案建站服务器?