Java并发编程锁之独占公平锁与非公平锁比较

公平锁和非公平锁理解:

在上一篇文章中,我们知道了非公平锁。其实Java中还存在着公平锁呢。公平二字怎么理解呢?和我们现实理解是一样的。大家去排队本着先来先得到的原则,在排队中,无论身份贵贱,一律平等对待。这是就是我们现实生活中的公平。大家都喜欢公平的。但是在Java中默认是非公平的,为什么呢?

本文主要内容:公平锁的现实生活理解;公平锁演示;为什么Java中默认是非公平锁(公平锁的非公平锁的比较)

本篇是《凯哥(凯哥Java:kagejava)并发编程学习》系列之《Lock系列》教程的第四篇:《Java并发包下锁学习第五篇:公平锁理解及与非公平锁的比较》。

生活中的例子:

同样还是去ATM机取钱的例子。假设现在有3个人使用ATM取钱。路人甲不会用ATM,自己摸索耗时5min,然后终于学会怎么使用了,但是密码又忘掉了。打电话给家里人咨询耗时1min.当路人甲操作完成之后,后面两个人排队接着依次操作,这种方式是谁先到谁先操作,操作完成之后下一个人才可以操作的,不管贫富贵贱,不管你是取100还是取1W,取1W的人在取100的人后面,就要排着队等着,这种看上去很公平的,无论贵贱,大家依次操作,这种操作模式站在多线程并发角度来看的话,就是公平锁操作。

在路人甲总耗时6min之后,路人乙和路人丁两个人操作耗时3min。也就是三个人总耗时9min.为什么会产生这种情况呢?因为路人甲堵着了。一直占着锁的资源。在路人甲操作的过程中,其他人只能排队等待。如果路人甲不会操作,排在他后面的路人丙插队询问路人甲,自己可以先插队操作ATM,同时教会路人甲。如果甲同意,则丙可以操作完成后,甲可以学着别人操作,有可能路人甲2min也能操作完成。这个时候,三个人总耗时就是5min了;如果甲不同意丙插队操作,那么丙只能回到原来位置上,进行排队等待。这种操作模式站在多线程并发角度来考虑的话,路人甲在模式及和家人通话耗时看着是CPU切换上下文的耗时。路人丙插队后获取ATM资源,这个操作可以看着是非公平的,因为丙的进入时间比路人乙晚,但是丙先操作了。但是从最后三人总耗时来看,路人丙插队,是的效率提高了。这种操作在Java并发中,称之为非公平锁。

需要说明的是,无论是显式锁还是隐式锁默认都是非公平的。因为非公平能够提升系统的吞吐量。

非公平锁的定义:

线程先尝试着获取同步状态操作(丙先尝试着插队),如果获取到,就对共享变量操作(甲同意丙的插队,丙就操作ATM机),如果获取不到,就接着排队。

使用方法二:独占公平演示

需求:控制台打印的结果和线程顺序一致。代码如下:

此时代码和上一次代码唯一区别如上图:在实例化lock的是有个参数,设置了true.

运行结果:

从运行结果中,我们发现控制台打印出的获取锁的顺序和调用锁的时候顺序是一样的, 已经达到我们预期结果了。但是,还是每次只有一个线程操作,等这个线程操作完成释放锁后,其他线程才可以接着获取锁。

公平锁与非公平锁的比较

问题:

为什么并发大师Doug Lea把ReentrantLock设计默认模式是非公平的?

其实要回答这个问题,就需要从公平锁与非公平锁的不同来进行比较了。我们先来看看ATM机操作在公平锁和非公平锁的场景下,如下图:

公平锁:大家都排队,如果一个线程堵着了(路人甲),其他线程只能等待这个。最终,三个线程操作完成,总耗时9min.

非公平锁情况下:多个线程操作的共享资源的时候,发现共享资源还没有被锁定(路人甲还在摸索过程),就尝试插队(路人丙尝试和甲沟通,先插队操作并教会甲),如果插队成功(甲同意了),就操作共享资源(丙先操作ATM机);如果插队失败(甲不同意),接着排队(丙回到队伍中排队)。如果插队成功,最终耗时:5min.

从中我们可以看出公平锁和非公平锁的优缺点了。

优缺点比较:

非公平锁:

优点:效率高;缺点:容易导致线程“饥饿”。当多个线程使用非公平的话,有可能有一个线程一直就获取不到竞争权,导致这个线程会“饥饿而死”。

适用场景:

如果在不考虑TPS(单位时间内成功完成的次数)作为唯一考量指标的场景下,可以使用非公平锁来操作,因为非公平锁能提高系统的吞吐量;

公平锁:

优点:避免了线程的“饥饿”;缺点:性能相对于公平锁会差很多。

​    ​    ​    ​    ​    ​    ​    ​    ​    ​    ​    ​    ​    ​        ​    ​                  ​​欢迎来聊

Java并发编程锁之独占公平锁与非公平锁比较的更多相关文章

  1. Java并发编程:用AQS写一把可重入锁

    Java并发编程:自己动手写一把可重入锁详述了如何用synchronized同步的方式来实现一把可重入锁,今天我们来效仿ReentrantLock类用AQS来改写一下这把锁.要想使用AQS为我们服务, ...

  2. 【Java并发编程实战】-----“J.U.C”:CLH队列锁

    在前面介绍的几篇博客中总是提到CLH队列,在AQS中CLH队列是维护一组线程的严格按照FIFO的队列.他能够确保无饥饿,严格的先来先服务的公平性.下图是CLH队列节点的示意图: 在CLH队列的节点QN ...

  3. Java并发编程:自己动手写一把可重入锁

    关于线程安全的例子,我前面的文章Java并发编程:线程安全和ThreadLocal里面提到了,简而言之就是多个线程在同时访问或修改公共资源的时候,由于不同线程抢占公共资源而导致的结果不确定性,就是在并 ...

  4. 【Java并发编程实战】-----“J.U.C”:CLH队列锁

    在前面介绍的几篇博客中总是提到CLH队列,在AQS中CLH队列是维护一组线程的严格依照FIFO的队列.他可以确保无饥饿,严格的先来先服务的公平性.下图是CLH队列节点的示意图: 在CLH队列的节点QN ...

  5. java并发编程的艺术——第五章总结(Lock锁与队列同步器)

    Lock锁 锁是用来控制多个线程访问共享资源的方式. 一般来说一个锁可以防止多个线程同时访问共享资源(但有些锁可以允许多个线程访问共享资源,如读写锁). 在Lock接口出现前,java使用synchr ...

  6. 【漫画】JAVA并发编程 J.U.C Lock包之ReentrantLock互斥锁

    在如何解决原子性问题的最后,我们卖了个关子,互斥锁不仅仅只有synchronized关键字,还可以用什么来实现呢? J.U.C包中还提供了一个叫做Locks的包,我好歹英语过了四级,听名字我就能马上大 ...

  7. 转:【Java并发编程】之一:可重入内置锁

    每个Java对象都可以用做一个实现同步的锁,这些锁被称为内置锁或监视器锁.线程在进入同步代码块之前会自动获取锁,并且在退出同步代码块时会自动释放锁.获得内置锁的唯一途径就是进入由这个锁保护的同步代码块 ...

  8. 【Java并发编程】之一:可重入内置锁

    每个Java对象都可以用做一个实现同步的锁,这些锁被称为内置锁或监视器锁.线程在进入同步代码块之前会自动获取锁,并且在退出同步代码块时会自动释放锁.获得内置锁的唯一途径就是进入由这个锁保护的同步代码块 ...

  9. java并发编程(一)可重入内置锁

    每个Java对象都可以用做一个实现同步的锁,这些锁被称为内置锁或监视器锁.线程在进入同步代码块之前会自动获取锁,并且在退出同步代码块时会自动释放锁.获得内置锁的唯一途径就是进入由这个锁保护的同步代码块 ...

  10. java并发编程(8)原子变量和非阻塞的同步机制

    原子变量和非阻塞的同步机制 一.锁的劣势 1.在多线程下:锁的挂起和恢复等过程存在着很大的开销(及时现代的jvm会判断何时使用挂起,何时自旋等待) 2.volatile:轻量级别的同步机制,但是不能用 ...

随机推荐

  1. Vue-API之全局配置

    API 全局配置 Vue.config 是一个对象,包含 Vue 的全局配置. 源码位置:util/config.js 搜索config 可以找到其源码地址,其中声明了config的类型和默认参数 下 ...

  2. java基础进阶篇(四)_HashMap------【java源码栈】

    目录 一.前言 二.特点和常见问题 二.接口定义 三.初始化构造函数 四.HashMap内部结构 五.HashMap的存储分析 六.HashMap的读取分析 七.常用方法 八.HashMap 的jav ...

  3. iOS下的 Fixed BUG

    input 光标位置乱窜 固定式浮层内的输入框光标会发生偏移.即 fixed 定位的容器中输入框光标的位置显示不正确,没有正常地显示在输入框中,而是偏移到了输入框外面 可触发条件 页面body出现滚动 ...

  4. ASP.NET Core 中间件自定义全局异常处理

    目录 背景 ASP.NET Core过滤器(Filter) ASP.NET Core 中间件(Middleware) 自定义全局异常处理 .Net Core中使用ExceptionFilter .Ne ...

  5. elasticsearch-head 安装

    一.安装phantomjs(由于入坑多写一步,此步骤可省掉) 1.下载phantomjs 安装npm的时候会依赖phantomjs 所以我们先安装phantomjs phantomjs 下载地址:ht ...

  6. vue iview modal弹出框 form表单验证

    一.ref="addApply" :model="addApply" :rules="ruleValidate"   不要忘记prop 二. ...

  7. 浅谈CSRF(跨站请求伪造)攻击方式

    一.CSRF是什么? CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSR ...

  8. BUAAOO——UNIT2 SUMMARY

    本单元的题目为设计电梯,通过这单元的学习,我初步了解了关于java多线程编程及线程之间并发安全性设计等方面的内容.以下为对这三次作业的分析与总结. 作业分析 序号 楼层 电梯数量 可停靠楼层 调度策略 ...

  9. 12.unittest的学习

    unittest学习后的总结,记录各个主要内容

  10. Dubbo 扩展点加载机制:从 Java SPI 到 Dubbo SPI

    SPI 全称为 Service Provider Interface,是一种服务发现机制.当程序运行调用接口时,会根据配置文件或默认规则信息加载对应的实现类.所以在程序中并没有直接指定使用接口的哪个实 ...