Java中的各种锁,容易理解_锁的理解,用到哪些锁-程序员宅基地

技术标签: Java中的各种锁  java  乐观锁和悲观锁  

转载自WX公众号:https://mp.weixin.qq.com/s/WSZV5l5dlieJ8YxSit6Qug

作者:乱敲代码

说到了锁我们经常会联想到生活中的锁,在我们日常中我们经常会接触到锁。比如我们的手机锁,电脑锁,再比如我们生活中的门锁,这些都是锁。

锁有什么作用呢?

说了这么多还是不清楚锁到底有什么用处?这一点就要深思我们为什么要使用锁,我们用手机锁是为了保障我们的隐私安全,使用门锁是为了保障我们的财产安全,准确的来说我们使用锁就是为了安全。那么在生活中我们可以加锁来保障自己的隐私和财产安全,那Java中的锁有什么用处呢?

Java中的锁

Java中的锁准确的来说也是为了保证安全,不过不同的是Java中的锁是为了保证并发所需要的。所以在Java中加锁准确的来说是为了保证并发安全,同时也是为了解决内存中的一致性,原子性,有序性三种问题。在Java中提供了各式各样的锁,每种锁都有其自身的特点和适用范围。所以我们都要熟悉锁的区别和原理才能正确的使用。

乐观锁和悲观锁

悲观锁

乐观锁和悲观锁的话在之前我刚刚开始写的时候就写过相关的文章,在这里就重新介绍一下吧。悲观锁如其名它是悲观的,它觉得每次访问数据都可能被其他人(线程)修改,所以在访问资源的时候就会对资源进行加锁,用这种方式来保证资源在访问的时候不会被其他线程修改。这样的话其他线程想要获取资源的话就只能阻塞,等到当前线程释放锁后在获取。在Java中悲观锁的实现有synchronized关键字Lock的实现类都是悲观锁。我们来看一下悲观锁到底是怎么执行的。

线程A抢占到资源后线程B就陷入了阻塞中,然后就等待线程A释放资源。

 

当线程A释放完资源后线程B就去获取锁开始操作资源˛悲观锁保证了资源同时只能一个线程进行操作。

乐观锁

与悲观锁相反,乐观锁并不会觉得访问数据的时候会有人修改(所以它是乐观的),所以在访问资源的时候并不会上锁,但是在提交的时候回去判断一下是否有人修改了当前数据,在数据库中我们可以使用version版本号去实现。在Java中我们是使用CSA来实现。我们看一下乐观锁的执行过程

CAS

CAS(Compare And Swap)算法是一种无锁算法,是Java提供的非阻塞原子性操作。在不使用锁的情况下实现多线程下的同步。在并发包中(java.util.concurrent)原子性类都是使用CAS来实现乐观锁的。CAS通过硬件保证了比较更新的原子性,在JDK中Unsafe提供了一系列的compareAndSwap*方法,这里就不深究Unsafe这个类了。CAS操作过程就是将内存中的将要被修改的数据与预期的值进行比较,如果这两个值相等就修改值为新值,否则就不做操作也就是说CAS需要三个操作值:

  • 预期值的 A

  • 内存中的V

  • 将要修改的B

简单的来说CAS就是一个死循环,在循环中判断预期的值和内存中的值是否相等,如果相等的话就执行修改,如果如果不相等的话就继续循环,直到执行成功后退出。

CAS的问题

CAS虽然很牛逼但是它也存在一些问题比如ABA问题,举个例子,现在有内存中有一个共享变量X的值为A,这个时候出现一个变量想要去修改变量X的值,首先会获取X的值这个时候获取的是A,然后使用CAS操作把X变量修改成B。这样看起来是没有问题,那如果在线程1获取变量X之后,执行CAS之前出现一个线程2把X的值修改成B然后CAS操作执行又修改成了了A,虽然最后执行的结果共享变量的值为A但是此A已经不是线程1获取的A了。这就是经典的ABA问题。产生ABA问题是因为变量的状态值发生了环形转换,A可以到B,B可以到A,如果A到B,B到C就不会发生这种问题。

解决办法:在JDK1.5后加入了AtomicStampedReference方法给每个变量加入了一个时间戳来避免ABA问题。

同时CAS还有循环开销大的问题,因为会一直循环直到预期和内存相等修改成功。同时还有只能保证一个共享变量的原子性的问题不过在JDK1.5之后加入了AtomicReference类来保证引用对象之间的原子性。

使用悲观锁和乐观锁

 

可以使用synchronized关键字来实现悲观锁,乐观锁可以使用并法包下提供的原子类。

公平锁和非公平锁

上面说了悲观锁和乐观锁,现在来看公平锁和非公平锁。在锁中也是有公平和不公平滴,公平锁如其名讲究的是一个公平,所以多个线程同时申请申请锁的话,线程会放入一个队列中,在队列中第一个进入队列的线程才能获取锁资源,讲究的是先到先得。就比如我们在学校食堂打饭的时候,那个时候记得我同学一放学就赶快去食堂排队这样的话才能尽快的打上饭,而且在排队的过程中并不会有人吃不到饭,这个时候食堂阿姨是公平的每个人排队的话都能吃到饭,线程也是如此。非公平锁可以这样理解,我那个同学去食堂排队打饭了但是有人却插队,食堂阿姨却不公平直接给插队的人打饭却不给他打,你说气不气是不是很不公平,划重点非公平锁先到不一定先得。不过公平锁也是有缺点的,当一个线程获取资源后在队列中的其他的线程就只能在阻塞,CPU的所以公平锁比非公平锁的效率要低很多。因为CPU唤醒阻塞线程的开销比非公平锁大。我们来看一个一个例子:

在Java中ReentrantLock提供了公平锁和非公平锁的实现。看一下ReentrantLock怎么实现公平锁和非公平锁

 

使用公平锁和非公平锁

ReentrantLock默认就是非公平的锁,我们来看一下公平锁的例子:

看一下输出结果:

我们可以看到公平锁的输出结果是按照顺序来的,先到先得。在看一下非公平锁的例子:

输出结果:

我们可以看到如果使用非公平锁的话最后输出的结果是完全没有顺序的,先到不一定先得。所以在使用公平锁的时候线程1获取到锁之后线程2在请求锁的话就会挂起等待线程1释放锁,然后线程2才能获取锁。如果再有一个线程3想要请求锁的话,这时候如果使用的是非公平锁,那么线程2和线程3中两个有一个会获取到锁,公平锁的情况下线程3只能先挂起,等待线程2获取锁资源释放后在获取。

什么时候使用公平锁和非公平锁

在需要公平资源的场景下使用公平锁,如果不需要特殊的公平对待的话尽量使用非公平锁,因为公平锁会带来性能的开销。

独占锁和共享锁

看到独占和共享会联想到什么,对的独占锁就是每次只有一个线程能霸占这个锁资源,而其他线程就只能等待当前获取锁资源的线程释放锁才能再次获取锁,刚刚上面的ReentrantLock就是独占锁,那这样看来独占锁不也就是悲观锁吗?因为悲观锁抢占资源后就只能等待释放其他线程才能再次获取到锁资源。其实准确的说独占锁也是悲观锁。在谈共享锁,共享锁其实也是乐观锁它放宽了锁的策略允许多个线程同时获取锁。在并发包中ReadWriteLock就是一个典型的共享锁。它允许一个资源可以被多个读操作访问,或者被一个 写操作访问,但两者不能同时进行。

自旋锁

什么是自旋锁,自旋锁其实就是当一个线程获取锁的时候,这个锁已经被其他人获取到了那么这个线程不会立马挂起,反而在不放弃CPU使用权的情况下会尝试再次获取锁资源,默认次数是10次,可以使用-XX: PreBlockSpinsh来设置次数。如果自旋锁获取锁的时间太长,会造成后面的线程CPU资源耗尽释放。并且自旋锁是不公平的。

优点

自旋锁不会使线程状态发生切换,一直处于用户态,即线程一直都是active的;不会使线程进入阻塞状态,减少了不必要的上下文切换,执行速度快。

 

关注我的公众号:程序员小栈
一起来交流学习吧

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Dream_xun/article/details/102472010

智能推荐

15、Nuxt.js代理转发解决跨域问题_nuxtjs 跨域-程序员宅基地

文章浏览阅读340次。【代码】15、Nuxt.js代理转发解决跨域问题。_nuxtjs 跨域

如何在CKEditor5富文本编辑器中获取工具栏可用项目_ckeditor5获取默认工具栏-程序员宅基地

文章浏览阅读654次。CKEditor5富文本编辑器官方地址Vue 的一个更简单的解决方案 - 只需@ready="onReady"在ckeditor组件和onReady方法中监听:onReady(event) { console.log(Array.from(event.ui.componentFactory.names()));},在vue.js中简单通过下面的示例即可实现;import ClassicEditorfrom '@ckeditor/ckeditor5-build-classic';expor_ckeditor5获取默认工具栏

《一个小时,学会黑客技能》——以前BiliBili上面的那个视频中的那个网站,我终于又找到了_黑客教学视频在哪里可以找到?-程序员宅基地

文章浏览阅读1.8k次,点赞4次,收藏11次。可能是最好用的网上教程。_黑客教学视频在哪里可以找到?

探秘GA-BP:一款强大的遗传算法与反向传播神经网络集成工具-程序员宅基地

文章浏览阅读411次,点赞4次,收藏7次。探秘GA-BP:一款强大的遗传算法与反向传播神经网络集成工具项目地址:https://gitcode.com/Grootzz/GA-BP项目简介GA-BP 是一个开源项目,它结合了遗传算法(Genetic Algorithm, GA)和反向传播(Backpropagation, BP)神经网络,旨在为机器学习和优化问题提供一种创新的解决方案。由开发者Grootzz维护,该项目提供了Pytho..._ga bpnn csdn

8个Python必备的PyCharm插件_pycharm常见插件-程序员宅基地

文章浏览阅读2k次,点赞28次,收藏35次。大家好,在PyCharm中浏览插件列表并尝试很多人推荐的插件后,总结了几个瑰宝插件,它们各自以独特的方式帮助开发者快速、简便、愉悦地开发,接下来将逐个介绍它们。_pycharm常见插件

java面试题之volatile和synchronized的使用方法和区别_javasynchronized和volatile面试题-程序员宅基地

文章浏览阅读8.3k次,点赞11次,收藏36次。我们先来看一下Java 内存模型中的可见性、原子性和有序性。可见性:可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。原子性:原子是世界上的最小单位,具有不可分割性。synchronized块之间的操作就具备原子性。volatile关键字定义的变量就可以做到这一点,Java还有两个关键字能实现可见性,即synchronized和final。有序性..._javasynchronized和volatile面试题

随便推点

蚂蚁二面遭JVM调优灵魂拷问,逼得我啃透500页JVM实战笔记,成功上岸京东-程序员宅基地

文章浏览阅读505次,点赞5次,收藏12次。就写到这了,也算是给这段时间的面试做一个总结,查漏补缺,祝自己好运吧,也希望正在求职或者打算跳槽的 程序员看到这个文章能有一点点帮助或收获,我就心满意足了。多思考,多问为什么。希望小伙伴们早点收到满意的offer!越努力越幸运!金九银十已经过了,就目前国内的面试模式来讲,在面试前积极的准备面试,复习整个 Java 知识体系将变得非常重要,可以很负责任的说一句,复习准备的是否充分,将直接影响你入职的成功率。

序列号 java_JAVA序列号的serialVersionUID-程序员宅基地

文章浏览阅读411次。serialVersionUID 的规范 Serializable 和 ExternalizableJava类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法进行序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。如果读者看过Serializable的源码,就会发现,他只是一个空的接口,里面什么东西都没有。Serializable接口没有方..._serialversionuid 序列号

推出 TensorFlow 图神经网络 (GNNs)-程序员宅基地

文章浏览阅读1.1k次。发布人:Sibon Li、Jan Pfeifer、Bryan Perozzi 和 Douglas Yarrington日前,我们很高兴发布了 TensorFlow 图神经网络 (Graph..._图神经网络是用thesfolw吗

产生死锁的必要条件_不是产生线程死锁的必要条件是 一个进程因请求资源而阻塞时,对已获得的资源保特不-程序员宅基地

文章浏览阅读1k次,点赞2次,收藏2次。产生死锁的原因主要是:(1) 因为系统资源不足。(2) 进程运行推进的顺序不合适。(3) 资源分配不当等。如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。其次,进程运行推进顺序与速度不同,也可能产生死锁。产生死锁的四个必要条件:(1)互斥条件:一个资源每次只能被一个进程使用。(2)请求与保持条件(占有等待):..._不是产生线程死锁的必要条件是 一个进程因请求资源而阻塞时,对已获得的资源保特不

android软件安装到平板,新人看过来 安卓平板装机必备软件推荐-程序员宅基地

文章浏览阅读1.6k次。1平板与PC的桥梁:豌豆荚、91【PConline 应用】前几天我们为大家简单对比介绍了一下不同第三方安卓电子市场之间的差异。如今,安卓平板已经到手,也知道哪些电子市场好了,开始疯狂装软件呗。停!急切体验各种应用、游戏的心情可以理解,但不假思索的看见叫QQ的就下载,它真的适合你手中的平板吗?辛苦下载了20款软件,结果试用一圈后发现18个都不给力,这岂不是既浪费时间又影响心情。说的可能有点夸张,但如..._平板电脑装什么小程序可以用安卓手机

Spring-aop的四种增强方式_spring aop增强方法-程序员宅基地

文章浏览阅读144次。java_spring aop增强方法

推荐文章

热门文章

相关标签