Java多线程系列(四):4种常用Java线程锁的特点,性能比较、使用场景

Java多线程系列(四):4种常用Java线程锁的特点,性能比较、使用场景

多线程的缘由

在出现了进程之后,操作系统的性能得到了大大的提升。虽然进程的出现解决了操作系统的并发问题,但是人们仍然不满足,人们逐渐对实时性有了要求。

使用多线程的理由之一是和进程相比,它是一种非常花销小,切换快,更”节俭”的多任务操作方式。


在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种”昂贵”的多任务工作方式。而在进程中的同时运行多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。

多线程并发面临的问题

Java多线程系列(四):4种常用Java线程锁的特点,性能比较、使用场景

由于多个线程是共同占有所属进程的资源和地址空间的,那么就会存在一个问题:

如果多个线程要同时访问某个资源,怎么处理?

在Java并发编程中,经常遇到多个线程访问同一个 共享资源 ,这时候作为开发者必须考虑如何维护数据一致性,这就是Java锁机制(同步问题)的来源。


Java提供了多种多线程锁机制的实现方式,常见的有:

  1. synchronized
  2. ReentrantLock
  3. Semaphore
  4. AtomicInteger等

每种机制都有优缺点与各自的适用场景,必须熟练掌握他们的特点才能在Java多线程应用开发时得心应手。

4种Java线程锁(线程同步)

Java多线程系列(四):4种常用Java线程锁的特点,性能比较、使用场景


1.synchronized


在Java中synchronized关键字被常用于维护数据一致性。


synchronized机制是给共享资源上锁,只有拿到锁的线程才可以访问共享资源,这样就可以强制使得对共享资源的访问都是顺序的。

Java开发人员都认识synchronized,使用它来实现多线程的同步操作是非常简单的,只要在需要同步的对方的方法、类或代码块中加入该关键字,它能够保证在同一个时刻最多只有一个线程执行同一个对象的同步代码,可保证修饰的代码在执行过程中不会被其他线程干扰。使用synchronized修饰的代码具有原子性和可见性,在需要进程同步的程序中使用的频率非常高,可以满足一般的进程同步要求。

synchronized (obj) {

//方法

…….

}

synchronized实现的机理依赖于软件层面上的JVM,因此其性能会随着Java版本的不断升级而提高。

到了Java1.6,synchronized进行了很多的优化,有适应自旋、锁消除、锁粗化、轻量级锁及偏向锁等,效率有了本质上的提高。在之后推出的Java1.7与1.8中,均对该关键字的实现机理做了优化。


需要说明的是,当线程通过synchronized等待锁时是不能被Thread.interrupt()中断的,因此程序设计时必须检查确保合理,否则可能会造成线程死锁的尴尬境地。


最后,尽管Java实现的锁机制有很多种,并且有些锁机制性能也比synchronized高,但还是强烈推荐在多线程应用程序中使用该关键字,因为实现方便,后续工作由JVM来完成,可靠性高。只有在确定锁机制是当前多线程程序的性能瓶颈时,才考虑使用其他机制,如ReentrantLock等。


2.ReentrantLock

可重入锁,顾名思义,这个锁可以被线程多次重复进入进行获取操作。

ReentantLock继承接口Lock并实现了接口中定义的方法,除了能完成synchronized所能完成的所有工作外,还提供了诸如可响应中断锁、可轮询锁请求、定时锁等避免多线程死锁的方法。


Lock实现的机理依赖于特殊的CPU指定,可以认为不受JVM的约束,并可以通过其他语言平台来完成底层的实现。在并发量较小的多线程应用程序中,ReentrantLock与synchronized性能相差无几,但在高并发量的条件下,synchronized性能会迅速下降几十倍,而ReentrantLock的性能却能依然维持一个水准。

因此我们建议在高并发量情况下使用ReentrantLock。


ReentrantLock引入两个概念:公平锁与非公平锁


公平锁指的是锁的分配机制是公平的,通常先对锁提出获取请求的线程会先被分配到锁。反之,JVM按随机、就近原则分配锁的机制则称为不公平锁。

ReentrantLock在构造函数中提供了是否公平锁的初始化方式,默认为非公平锁。这是因为,非公平锁实际执行的效率要远远超出公平锁,除非程序有特殊需要,否则最常用非公平锁的分配机制。

ReentrantLock通过方法lock()与unlock()来进行加锁与解锁操作,与synchronized会被JVM自动解锁机制不同,ReentrantLock加锁后需要手动进行解锁。为了避免程序出现异常而无法正常解锁的情况,使用ReentrantLock必须在finally控制块中进行解锁操作。通常使用方式如下所示:

Lock lock = new ReentrantLock();

try {

lock.lock();

//…进行任务操作5 }

finally {

lock.unlock();

}


3.Semaphore

上述两种锁机制类型都是“互斥锁”,学过操作系统的都知道,互斥是进程同步关系的一种特殊情况,相当于只存在一个临界资源,因此同时最多只能给一个线程提供服务。但是,在实际复杂的多线程应用程序中,可能存在多个临界资源,这时候我们可以借助Semaphore信号量来完成多个临界资源的访问。

Semaphore基本能完成ReentrantLock的所有工作,使用方法也与之类似,通过acquire()与release()方法来获得和释放临界资源。

经实测,Semaphone.acquire()方法默认为可响应中断锁,与ReentrantLock.lockInterruptibly()作用效果一致,也就是说在等待临界资源的过程中可以被Thread.interrupt()方法中断。

此外,Semaphore也实现了可轮询的锁请求与定时锁的功能,除了方法名tryAcquire与tryLock不同,其使用方法与ReentrantLock几乎一致。Semaphore也提供了公平与非公平锁的机制,也可在构造函数中进行设定。

Semaphore的锁释放操作也由手动进行,因此与ReentrantLock一样,为避免线程因抛出异常而无法正常释放锁的情况发生,释放锁的操作也必须在finally代码块中完成

4.AtomicInteger

首先说明,此处AtomicInteger是一系列相同类的代表之一,常见的还有AtomicLong、AtomicLong等,他们的实现原理相同,区别在与运算对象类型的不同。

我们知道,在多线程程序中,诸如++i

i++等运算不具有原子性,是不安全的线程操作之一。通常我们会使用synchronized将该操作变成一个原子操作,但JVM为此类操作特意提供了一些同步类,使得使用更方便,且使程序运行效率变得更高。通过相关资料显示,通常AtomicInteger的性能是ReentantLock的好几倍。

Java线程锁总结

1.synchronized:

在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize,另外可读性非常好。


2.ReentrantLock:

在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍,而ReentrantLock确还能维持常态。

高并发量情况下使用ReentrantLock。


3.Atomic:

和上面的类似,不激烈情况下,性能比synchronized略逊,而激烈的时候,也能维持常态。激烈的时候,Atomic的性能会优于ReentrantLock一倍左右。但是其有一个缺点,就是只能同步一个值,一段代码中只能出现一个Atomic的变量,多于一个同步无效。因为他不能在多个Atomic之间同步。

所以,我们写同步的时候,优先考虑synchronized,如果有特殊需要,再进一步优化。ReentrantLock和Atomic如果用的不好,不仅不能提高性能,还可能带来灾难。

以上就是Java线程锁的详解,除了从编程的角度应对高并发,更多还需要从架构设计的层面来应对高并发场景,例如:Redis缓存、CDN、异步消息等,详细的内容如下。

更多高并发架构设计|以及最全架构师130题|以及优知学院最全架构师技能高清图

Java多线程系列(四):4种常用Java线程锁的特点,性能比较、使用场景

所有以上资料获取方式

关注优知学院微信公众号,回复关键词 【架构师】即可获取以上所有架构师资料。


money.jpg

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

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

相关文章

论文浅尝 | Global Relation Embedding for Relation Extraction

链接:https://arxiv.org/abs/1704.05958Introduction在关系抽取任务中,通常采用远程监督的方式自动生成数据集。由于实体对间可能存在多关系,生成的数据集往往存在大量噪音。本文对文本中的关系表述(textual relation)…

tensorflow--模型的保存和提取

参考: TensorFlow:保存和提取模型 最全Tensorflow模型保存和提取的方法——附实例 模型的保存会覆盖,后一次保存的模型会覆盖上一次保存的模型。最多保存近5次结果。应当保存效果最优时候的模型,而不是训练最后一次的模型。所以…

推荐模型是怎样由窄变宽、越变越深的?

星标/置顶小屋,带你解锁最萌最前沿的NLP、搜索与推荐技术文 | 邢智皓编 | 兔子酱当前,深度学习推荐模型已经成功应用于推荐、广告、搜索等领域,但在了解它之前,简单回顾传统推荐模型仍是有必要的,原因如下:…

动态规划应用--找零钱

文章目录1. 问题描述2. 问题分析2.1 回溯法求解2.2 DP状态转移方程法2.3 DP状态转移表法1. 问题描述 找零问题,在贪心算法讲过。但是贪心不一定能得出最优解。假设有几种不同币值的硬币v1,v2,.……vn(单位是元)。如果…

玩转算法之面试第九章-动态规划

动态规划: 9-12 斐波那契数列 对重复计算,进行优化,进行记忆化搜索 假设基本的问题已经被解决,依次内推。 动态规划:将原问题拆解成若干个子问题,同时保存子问题的答案,使得每个子问题只求…

领域应用 | 从本体论开始说起——运营商关系图谱的构建及应用

本文转载自公众号:中国联通大数据。联通大数据技术专家闫龙将从“本体论”说起,为大家介绍联通大数据关系图谱的构建与应用。一.本体论万维网之父Tim Berners-Lee教授在1998年将语义网络(Semantic web)带入人类的视线。…

史上最强多线程面试44题和答案:线程锁+线程池+线程同步等

最全BAT必考题答案系列 最全MySQL面试60题和答案 史上最全Spring面试71题与答案 史上最全Redis面试49题(含答案):哨兵复制事务集群持久化等 分布式缓存RedisMemcached经典面试题和答案 最全Java锁详解:独享锁/共享锁公平锁/非公平锁乐观锁…

部门直推!百度大搜索招聘NLP、搜索方向算法工程师!

星标/置顶小屋,带你解锁最萌最前沿的NLP、搜索与推荐技术工作职责负责百度搜索排序相关性(Relevance)策略。 职位要求-了解主流机器学习算法。 -优秀的分析问题和解决问题的能力,对解决具有挑战性问题充满激情。 -C/C语言编程&…

POJ 1276 ATM凑钱(动态规划)(未解答)

文章目录1. 题目1.1 题目链接1.2 题目大意1.3 解题思路2. 代码2.1 Accepted代码1. 题目 1.1 题目链接 http://poj.org/problem?id1276 1.2 题目大意 需要凑的钱最多100000,面额最多10种,每种张数最多1000,面额最大不超过1000 1.3 解题思…

论文浅尝 | 为基于知识库的问答构建形式查询生成

论文笔记整理:刘晓臻,东南大学计算机科学与工程学院本科生。Citation: H.Zafar, G. Napolitano, and J. Lehmann. Formal query generation for questionanswering overknowledge bases. ESWC, 2018.https://link.springer.com/content/pdf/10.1007%2F97…

Java多线程系列(十一):ReentrantReadWriteLock的实现原理与锁获取详解

我们继续Java多线程与并发系列之旅,之前我们分享了Synchronized 和 ReentrantLock 都是独占锁,即在同一时刻只有一个线程获取到锁。 然而在有些业务场景中,我们大多在读取数据,很少写入数据,这种情况下,如…

这篇顶会paper,讲述了疫情期间憋疯的你和我

星标/置顶小屋,带你解锁最萌最前沿的NLP、搜索与推荐技术编 | 小轶2020年净忙着见证历史了。年初疫情爆发后,大家的生活模式也因为疫情发生了巨变。经历了史上最长假期,躺尸太久,到后来满脑子只想开学/复工。今年KDD会议上有一篇很…

论文浅尝 | Knowledge Vault: 全网规模的知识概率融合方法

论文笔记整理:吴桐桐,东南大学博士生,研究方向为自然语言处理。链接:https://www.cs.ubc.ca/~murphyk/Papers/kv-kdd14.pdf基于机器学习,Knowledge Vault不仅能够从多个来源(文本,表格数据&…

java程序员的必用的9款开发工具

今天推荐java程序员开发利器,包含如如下: 开发环境: Eclipse IntelliJ IDEA IntelliJ在业界被公认为最好的java开发工具之一,尤其在智能代码助手、代码自动提示、重构、J2EE支持、各类版本工具(git、svn等&#xff…

动态规划应用--搜索引擎拼写纠错

文章目录1. 字符串相似度1.1 莱文斯坦距离1.2 最长公共子串长度2. 计算编辑距离2.1 莱文斯坦距离2.2 最长公共子串长度3. 搜索引擎拼写纠错4. 练习题在 Trie树那节讲过,利用Trie可以进行关键词提示,节省输入时间。在搜索框中你不小心打错了字&#xff0c…

玩转算法之面试第十章-贪心算法

leetcode 455 分配饼干 尝试将最大的饼干给最贪心的朋友 如果满足&#xff0c;则1 如果不满足&#xff0c;则将最大的饼干给次贪心的朋友&#xff0c;一次类推 试图让最多的小朋友开心 在这里插入代码片 #include<iostream> #include<vector>using namespace …

论文浅尝 | 基于知识库的自然语言理解 04#

本文转载自公众号&#xff1a;知识工场。罗康琦&#xff0c;上海交通大学计算机系2019届博士&#xff0c;研究方向为自然语义理解和知识图谱。2012年获得华中科技大学软件工程学士学位&#xff0c;现就职于京东数据科学实验室&#xff08;Data Science Lab&#xff09;。他曾在…

BERT跨模态之后:占领了视觉常识推理任务榜单TOP 2!

星标/置顶小屋&#xff0c;带你解锁最萌最前沿的NLP、搜索与推荐技术文 | 小鹿鹿lulu编 | YY前言由于 BERT-like 模型在 NLP 领域上的成功&#xff0c;研究者们开始尝试将其应用到更为复杂的 多模态 任务上。要求模型除文本数据以外&#xff0c;还要接收其他模态的数据&#xf…

常见的算法面试问题以及代码实现

1 时间复杂度分析 一个简单的时间测试代码如下&#xff1a; #include<iostream> #include<cmath> #include<ctime>using namespace std;int main(){for(int x1;x<9;x){int npow(10,x);clock_t startTimeclock();int sum0;for(int i0;i<n;i)sumi;clock…

阿里P8架构师谈:高并发与多线程的关系、区别、高并发的技术方案

什么是高并发&#xff1f; 高并发&#xff08;High Concurrency&#xff09;是一种系统运行过程中遇到的一种“短时间内遇到大量操作请求”的情况&#xff0c;主要发生在web系统集中大量访问收到大量请求&#xff08;例如&#xff1a;12306的抢票情况&#xff1b;天猫双十一活动…