最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁

在Java并发场景中,会涉及到各种各样的锁,比如:高并发编程系列:4种常用Java线程锁的特点,性能比较、使用场景,这些锁有对应的种类:公平锁,乐观锁,悲观锁等等,这篇文章来详细介绍各种锁的分类:

公平锁/非公平锁

可重入锁

独享锁/共享锁

乐观锁/悲观锁

分段锁

自旋锁

最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁

乐观锁 VS 悲观锁

乐观锁与悲观锁是一种广义上的概念,体现了看待线程同步的不同角度,在Java和数据库中都有此概念对应的实际应用。


1.乐观锁

顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。


乐观锁适用于多读的应用类型,乐观锁在Java中是通过使用无锁编程来实现,最常采用的是CAS算法,Java原子类中的递增操作就通过CAS自旋实现的。


CAS全称 Compare And Swap(比较与交换),是一种无锁算法。在不使用锁(没有线程被阻塞)的情况下实现多线程之间的变量同步。java.util.concurrent包中的原子类就是通过CAS来实现了乐观锁。

简单来说,CAS算法有3个三个操作数:

  • 需要读写的内存值 V。
  • 进行比较的值 A。
  • 要写入的新值 B。

当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则返回V。这是一种乐观锁的思路,它相信在它修改之前,没有其它线程去修改它;而Synchronized是一种悲观锁,它认为在它修改之前,一定会有其它线程去修改它,悲观锁效率很低


2.悲观锁

总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。

传统的MySQL关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。详情可以参考:阿里P8架构师谈:MySQL行锁、表锁、悲观锁、乐观锁的特点与应用


再比如上面提到的Java的同步synchronized关键字的实现就是典型的悲观锁。

最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁


3.总之:

  • 悲观锁适合写操作多的场景,先加锁可以保证写操作时数据正确。
  • 乐观锁适合读操作多的场景,不加锁的特点能够使其读操作的性能大幅提升。

公平锁 VS 非公平锁


1.公平锁

就是很公平,在并发环境中,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个,就占有锁,否则就会加入到等待队列中,以后会按照FIFO的规则从队列中取到自己。


公平锁的优点是等待锁的线程不会饿死。缺点是整体吞吐效率相对非公平锁要低,等待队列中除第一个线程以外的所有线程都会阻塞,CPU唤醒阻塞线程的开销比非公平锁大。


2.非公平锁

上来就直接尝试占有锁,如果尝试失败,就再采用类似公平锁那种方式。

非公平锁的优点是可以减少唤起线程的开销,整体的吞吐效率高,因为线程有几率不阻塞直接获得锁,CPU不必唤醒所有线程。缺点是处于等待队列中的线程可能会饿死,或者等很久才会获得锁。

最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁

3.典型应用:

java jdk并发包中的ReentrantLock可以指定构造函数的boolean类型来创建公平锁和非公平锁(默认),比如:公平锁可以使用new ReentrantLock(true)实现。

独享锁 VS 共享锁

1.独享锁

是指该锁一次只能被一个线程所持有。


2.共享锁

是指该锁可被多个线程所持有。


3.比较

对于Java ReentrantLock而言,其是独享锁。但是对于Lock的另一个实现类ReadWriteLock,其读锁是共享锁,其写锁是独享锁。

读锁的共享锁可保证并发读是非常高效的,读写,写读 ,写写的过程是互斥的。

独享锁与共享锁也是通过AQS来实现的,通过实现不同的方法,来实现独享或者共享。


4.AQS

抽象队列同步器(AbstractQueuedSynchronizer,简称AQS)是用来构建锁或者其他同步组件的基础框架,它使用一个整型的volatile变量(命名为state)来维护同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。

最全Java锁详解:独享锁/共享锁+公平锁/非公平锁+乐观锁/悲观锁


concurrent包的实现结构如上图所示,AQS、非阻塞数据结构和原子变量类等基础类都是基于volatile变量的读/写和CAS实现,而像Lock、同步器、阻塞队列、Executor和并发容器等高层类又是基于基础类实现。

分段锁

分段锁其实是一种锁的设计,并不是具体的一种锁,对于ConcurrentHashMap而言,其并发的实现就是通过分段锁的形式来实现高效的并发操作。


我们以ConcurrentHashMap来说一下分段锁的含义以及设计思想,ConcurrentHashMap中的分段锁称为Segment,它即类似于HashMap(JDK7与JDK8中HashMap的实现)的结构,即内部拥有一个Entry数组,数组中的每个元素又是一个链表;同时又是一个ReentrantLock(Segment继承了ReentrantLock)。


当需要put元素的时候,并不是对整个hashmap进行加锁,而是先通过hashcode来知道他要放在那一个分段中,然后对这个分段进行加锁,所以当多线程put的时候,只要不是放在一个分段中,就实现了真正的并行的插入。


但是,在统计size的时候,可就是获取hashmap全局信息的时候,就需要获取所有的分段锁才能统计。


分段锁的设计目的是细化锁的粒度,当操作不需要更新整个数组的时候,就仅仅针对数组中的一项进行加锁操作。


money.jpg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/480125.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

论文浅尝 | Generative QA: Learning to Answer the Whole Question

链接: https://openreview.net/forum?idBkx0RjA9tX传统的机器阅读理解的模型都是给定 context 和 question, 找出最有可能回答该 question 的 answer,用概率表示为 p(a|q,c),这其实是一个判别模型。判别模型在大多数任务上可以取得比生成模型更好的准确…

打破BERT天花板:11种花式炼丹术刷爆NLP分类SOTA!

星标/置顶小屋,带你解锁最萌最前沿的NLP、搜索与推荐技术文 | JayLou娄杰编 | 小轶在2020这个时间节点,对于NLP分类任务,我们的关注重点早已不再是如何构造模型、拘泥于分类模型长什么样子了。如同CV领域当前的重点一样,我们更应该…

论文笔记(A Neural Influence Diffusion Model for Social Recommendation)

神经影响传播模型为了社交推荐 原文链接:A Neural Influence Diffusion Model for Social Recommendation, SIGIR’19 原理:社交网络上应用GNN提取朋友对用户的影响候选项对用户历史交互项的注意力影响用户向量,用户向量和项向量的内积预测评…

玩转算法面试-第三章

数组中常见的问题 排序: 选择排序;插入排序;归并排序;快速排序 查找:二分查找法 数据结构:栈;队列;堆 … 二分查找法: 1964年提出,没有bug的二分查找法是在1…

回溯应用-- 0-1背包问题

文章目录1. 问题描述2. 回溯解决思路1. 问题描述 0-1背包非常经典,很多场景都可以抽象成这个问题。经典解法是动态规划,回溯简单但没有那么高效。 有一个背包,背包总的承载重量是 W kg。现有n个物品,每个物品重量不等&#xff0…

Java多线程系列(五):线程池的实现原理、优点与风险、以及四种线程池实现

为什么需要线程池 我们有两种常见的创建线程的方法,一种是继承Thread类,一种是实现Runnable的接口,Thread类其实也是实现了Runnable接口。但是我们创建这两种线程在运行结束后都会被虚拟机销毁,如果线程数量多的话,频繁…

论文浅尝 | 面向单关系事实问题的中文问答模型

来源:NLPCC 2017论文下载地址:http://tcci.ccf.org.cn/conference/2017/papers/2003.pdf动机开放领域的QA问题是一个被广泛研究的问题,而且目前这个问题并没有被很好地解决。在中文领域,相关的数据集并不多。而NLPCC开放了一个KBQ…

玩转算法值面试-第五章 -在链表中穿针引线

5-123 数组中可以随机访问,相反链表就不行 leetcode:206 反转一个链表,链表如果没有特别声明,则节点的值不发生改变 一共需要三个指针:current指向当前需要处理的指针 next指向当前需要处理的元素的下一个元素的指针…

论文笔记(SocialGCN: An Efficient Graph Convolutional Network based Model for Social Recommendation)

一个有效的基于图卷积神经网络的社交推荐模型 原文链接:SocialGCN: An Efficient Graph Convolutional Network based Model for Social Recommendation, arxiv 原理:在用户-项交互图上应用GNN来学习用户向量的表示,用户向量和项向量内积预测…

POJ 1753 Flip Game(回溯)

文章目录1. 题目1.1 题目链接1.2 题目大意1.3 解题思路2. 代码2.1 Wrong Answer代码2.2 Accepted代码1. 题目 1.1 题目链接 http://poj.org/problem?id1753 1.2 题目大意 一个黑白棋子的棋盘,一个反过来周围四个也跟着反过来(如果存在的话),颜色取反…

他读书时挣了五十万,找工作时收获阿里腾讯快手等ssp offer

今天介绍一位dalao,他之前在中科院获取了计算机硕士学位,现在是一名大厂的算法工程师。大多数人的学生生活,是在枯燥的课程和任务中度过的,但他却有所不同,乐于折腾,收获了不一样的精彩。他喜欢去公司实习&…

Java多线程系列(三):Java线程池的使用方式,及核心运行原理

之前谈过多线程相关的4种常用Java线程锁的特点,性能比较、使用场景,今天主要分享线程池相关的内容,这些都是属于Java面试的必考点。 为什么需要线程池 java中为了提高并发度,可以使用多线程共同执行,但是如果有大量线程短时间之内…

论文浅尝 | 图神经网络综述:方法及应用

论文链接:https://arxiv.org/pdf/1812.08434.pdfGNN相关论文列表链接:https://github.com/thunlp/GNNPapers近日,清华刘知远老师组在arXiv上发表了一篇关于图神经网络的综述,本次论文浅尝在分享这篇论文的基础上,对图神…

论文笔记(Social Attentional Memory Network:Modeling Aspect- and Friend-level Differences in Recom-)

社交注意记忆网络:模拟面级别和朋友级别的区别 原文链接:Social Attentional Memory Network: Modeling Aspect- and Friend-Level Differences in Recommendation, WSDM’19 1. 摘要 社会中的连接有助于提升推荐系统的性能,但是&#xff…

玩转算法之面试-第六章(栈和队列)

leetcode 20 此时栈顶的左括号和当前遍历的右括号匹配,故将左括号从栈顶pop出。 leetcode 150: leetcode 71 栈和递归的关系 递归算法:二叉树中的算法 、二叉树的前序遍历,中序遍历,后序遍历 前序遍历代码&am…

POJ 1321 棋盘问题(回溯)

文章目录1. 题目1.1 题目链接1.2 题目大意1.3 解题思路2. 代码2.1 Accepted 代码1. 题目 1.1 题目链接 http://poj.org/problem?id1321 1.2 题目大意 在一个给定形状的棋盘(只能在#号的位置摆放)上面摆放棋子,棋子没有区别。要求摆放时任…

Java多线程系列(二):线程的五大状态,以及线程之间的通信与协作

在Java面试的时候,经常会问到Java并发编程相关的多线程、线程池、线程锁、线程通信等面试必考点,比如: Java并发编程系列:Java线程池的使用方式,核心运行原理、以及注意事项 Java并发编程系列:4种常用Jav…

负样本为王:评Facebook的向量召回算法

星标/置顶小屋,带你解锁最萌最前沿的NLP、搜索与推荐技术有人的地方就会有江湖,就会有鄙视链存在,推荐系统中也不例外。排序、召回,尽管只是革命分工不同,但是我感觉待遇还是相差蛮大的排序排序,特别是精排…

论文浅尝 | TEQUILA: 一种面向时间信息的知识问答方法

来源:CIKM’18链接:http://delivery.acm.org/10.1145/3270000/3269247/p1807-jia.pdf?ip223.3.116.39&id3269247&accACTIVE%20SERVICE&keyBF85BBA5741FDC6E%2EEEBE655830483280%2E4D4702B0C3E38B35%2E4D4702B0C3E38B35&__acm__15478819…

京东2020算法工程师0824笔试题整理

代码题: 1:开心消消乐: #include #include #include #include #include #include #include #define ll long long #define inf 0x3f3f3f3f #define Max 1001 using namespace std; int dir[4][2]{{-1,0},{1,0},{0,-1},{0,1}}; string …