前言

Java语言中有许多原生线程安全的数据结构,比如ArrayBlockingQueue、CopyOnWriteArrayList、LinkedBlockingQueue,它们线程安全的实现方式并非通过synchronized关键字,而是通过java.util.concurrent.locks.ReentrantLock来实现。
 

锁的底层实现

无论什么语言在操作系统层面锁的操作都会变成系统调用(System Call),以 Linux 为例,就是 futex 函数,可以把它理解为两个函数:futex_wait(s),对变量 s 加锁;futex_wake(s)释放 s 上的锁,唤醒其他线程。
在ReentrantLock中很明显可以看到其中同步包括两种,分别是公平的FairSync和非公平的NonfairSync。
公平锁的作用就是严格按照线程启动的顺序来执行的,不允许其他线程插队执行的;而非公平锁是允许插队的。
默认情况下ReentrantLock是通过非公平锁来进行同步的,包括synchronized关键字都是如此,因为这样性能会更好。
因为从线程进入了RUNNABLE状态,可以执行开始,到实际线程执行是要比较久的时间的。
而且,在一个锁释放之后,其他的线程会需要重新来获取锁。其中经历了持有锁的线程释放锁,其他线程从挂起恢复到RUNNABLE状态,其他线程请求锁,获得锁,线程执行,这一系列步骤。如果这个时候,存在一个线程直接请求锁,可能就避开挂起到恢复RUNNABLE状态的这段消耗,所以性能更优化。
 
    /**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
默认状态,使用的ReentrantLock()就是非公平锁。再参考如下代码,我们知道ReentrantLock的获取锁的操作是通过装饰模式代理给sync的。
 
    /**
* 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.
*
* <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.
*/
public void lock() {
sync.lock();
}
下面参考一下FairSync和NonfairSync对lock方法的实现:
 
    /**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
} /**
* Sync object for fair locks
*/
static final class FairSync extends Sync {
final void lock() {
acquire(1);
}
}
当使用非公平锁的时候,会立刻尝试配置状态,成功了就会插队执行,失败了就会和公平锁的机制一样,调用acquire()方法,以排他的方式来获取锁,成功了立刻返回,否则将线程加入队列,知道成功调用为止。
 

总结

上锁的过程本身也是有时间开销的,如果操作资源的时间比上锁的时间还短建议使用非公平锁可以提高系统的吞吐率;否则就老老实实的用公平锁。
 

最后

欢迎大家关注我的公种浩【程序员追风】,2019年多家公司java面试题整理了1000多道400多页pdf文档,文章都会在里面更新,整理的资料也会放在里面。
喜欢文章记得关注我点个赞哟,感谢支持!

 

带你快速了解Java锁中的公平锁与非公平锁的更多相关文章

  1. 使用示例带你提前了解 Java 9 中的新特性

    使用示例带你提前了解 Java 9 中的新特性 转载来源:https://juejin.im/post/58c5e402128fe100603cc194 英文出处:https://www.journa ...

  2. IDEA插件:快速删除Java代码中的注释

    背景   有时,我们需要删除Java源代码中的注释.目前有不少方法,比如: 实现状态机.该方式较为通用,适用于多种语言(取决于状态机支持的注释符号). 正则匹配.该方式容易误判,尤其是容易误删字符串. ...

  3. 一篇博客带你轻松应对java面试中的多线程与高并发

    1. Java线程的创建方式 (1)继承thread类 thread类本质是实现了runnable接口的一个实例,代表线程的一个实例.启动线程的方式start方法.start是一个本地方法,执行后,执 ...

  4. 【视频+图文】带你快速掌握Java中含break语句的双重for循环

    双重for循环掌握后,我们就一起来看看双重for循环的进阶内容一之带break语句的双重for循环. 双重for循环[视频+图文]讲解传输门:点击这里可去小乔的哔哩哔哩观看~ 带continue语句的 ...

  5. Java并发指南8:AQS中的公平锁与非公平锁,Condtion

    一行一行源码分析清楚 AbstractQueuedSynchronizer (二) 转自https://www.javadoop.com/post/AbstractQueuedSynchronizer ...

  6. Java中的线程安全和非线程安全以及锁的几个知识点

    1. 线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用.不会出现数据不一致或者数据污染. 线程不安全就是不提供 ...

  7. 《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁

    第13章 显示锁 终于看到了这本书的最后一本分,呼呼呼,真不容易.其实说实在的,我不喜欢半途而废,有其开始,就一定要有结束,否则的话就感觉哪里乖乖的. java5.0之前,在协调对共享对象的访问时可以 ...

  8. Java多线程中的常用方法

    本文将带你讲诉Java多线程中的常用方法   Java多线程中的常用方法有如下几个 start,run,sleep,wait,notify,notifyAll,join,isAlive,current ...

  9. Java多线程系列--“JUC锁”05之 非公平锁

    概要 前面两章分析了"公平锁的获取和释放机制",这一章开始对“非公平锁”的获取锁/释放锁的过程进行分析.内容包括:参考代码获取非公平锁(基于JDK1.7.0_40)释放非公平锁(基 ...

随机推荐

  1. 领扣(LeetCode)各位相加 个人题解

    给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数. 示例: 输入: 38 输出: 2 解释: 各位相加的过程为:3 + 8 = 11, 1 + 1 = 2. 由于 2 是一位数,所 ...

  2. Django--导出项目依赖库requirements.txt

    虚拟环境下: 1.导出项目依赖库: pip freeze > requirements.txt 2.使用 pip 一次性安装项目的所有依赖项,方法是在命令行中输入:  pip install - ...

  3. JavaScript笔记十二

    1.DOM对CSS的操作 - 读取和修改内联样式 - 使用style属性来操作元素的内联样式 - 读取内联样式: 语法:元素.style.样式名 - 例子: 元素.style.width 元素.sty ...

  4. 从两个List集合里找到相同部分和不同部分

    /** * 获取两个集合里元素不同的部分 */ public List<User> getDifferent(List<User> u1, List<User> u ...

  5. Swift - 给UICollectionview设置组背景和圆角

    钟情圆角怎么办 最近由于我们的UI钟情于圆角搞得我很方,各种圆角渐变,于是就有了下面这篇给UICollection组设置圆角和背景色的诞生,不知道在我们平时有没有遇到这样子的一些需求,就是按照每一组给 ...

  6. php之自动加载(懒加载)

    有A类和B类,如果在A类实例化B类,最简单直接的方法就是在B中使用include require_once A的文件,但是这种方法显然是不友好的,在框架中叶不是这么做的,在框架中使用的是自动加载的机制 ...

  7. day20191010ClassNotes

    笔记: 1.DAO模式组成部分: 程序 ----> 数据库 实体类 数据库中的表 工具类:公共的数据库连接.关闭.公共的增删改.查询 接口 : 程序提倡的是面向接口编程,从而降低程序的耦合性 实 ...

  8. .NET Core应用框架AA介绍(二)

    AA的开源地址 https://github.com/ChengLab/AAFrameWork AA框架是一个基础应用框架,是建立在众多大家熟知的流行工具之上并与之集成.比如:ASP.NET Core ...

  9. Prometheus Label 标签管理

    目录 前言 配置测试 删除metric值 重新加载配置文件后测试 更换 重新加载配置文件后测试 删除 Label 标签 前言 在prometheus监控体系中.标签label是一个极为重要的参数,考虑 ...

  10. 2. Python环境安装

    Centos 下环境安装 我们通过pyenv来管理python环境,更好的帮助开发者避免在环境上出现各种各样的问题 准备工作 安装之前,确保已经安装了git yum install git -y 安装 ...