浅谈synchronized与volatile以及lock的爱恨情仇

多线程里的安全(volatile,synchronized,lock)


主要是为了保证三大特性:可见性,原子性,有序性
想看多线程安不安全,得先知道一个东西:JMM(java内存模型)
浅谈一下就是对于JMM来说,变量一开始存放在一个主内存,当有cpu线程想执行操作时,需要把变量读取到一个自己的工作内存来进行操作,最后全部操作结束在放回主内存供大家后续读取。
这里对于变量一共有八大操作:
lock, unlock, write, read, assign, load, use, store
这些操作都是原子的(存在特殊情况),就像之前谈到,这里主要包含主内存,工作内存,变量,读取出来的变量副本(threadlocal),具体执行的线程几个部分,他们之间操作的关系是:lock和unlock对于主内存中变量的上锁和解锁,read和write对于主内存和工作内存中变量与变量副本之间的转换关系,load和store是把变量副本交给执行的线程以及收到处理结果的操作,use和assign是线程使用变量副本和给变量副本赋值。
*这里还要小小的引申一个概念叫重排序,对于没有依赖关系的执行语句来说,编译器和处理器是可以对其重新排序的,以求得到更好的性能。但这也会引发一些问题,这里不做过多讨论,我们为了避免问题保证有序性,提出了内存屏障。
Volatile修饰的变量就提供了内存屏障,保证了在该变量的操作时拥有一个读屏障和一个写屏障。其实就是不允许对其进行重排序操作。

下面是synchronized和volatile的区别
Volatile只能修饰变量,它同时保证了可见性和有序性,volatile修饰的变量会强制操作完刷回主存,这样其他线程就能永远保证到最新,这样就保证了可见性,在这一点上,性能是高于synchronized的。但它没办法保证原子性,当有多个线程同时操作同一个变量时,写回主内存后就会引起混乱。*但它可以解决long和double的操作原子性,long和double是64位的,对于32位的jdk来说,对于他们的操作都是分两次进行,如果这时分别修改了前半段和后半段就会引起问题。但通过volatile的特性就可以避免。当然如果使用64位的jdk也可以,而且本身也有一定的宽容机制。

Synchronized关键字可以修饰变量和方法,但和volatile本质上是有区别的,volatile是给变量的一种提醒,而synchronized是一种加锁的方式来保证的安全。所以synchronized保证了可见性,原子性,有序性。这样的加锁方式势必会引起性能效率的下降,而且这样也会引起线程的阻塞。

所以总结来看,volatile只能修饰变量,只保证了可见性和有序性。Synchronized可以修饰变量和方法,保证了可见性,有序性和原子性。但因为加锁的原因可能会造成阻塞,且性能不如volatile。

再来看看lock锁,这里还要谈谈reentrantlock
Reentrantlock实现了lock接口,它支持公平锁和非公平锁,java主要默认应用的都是非公锁,就是谁来谁先请求,公平锁则是来了先排着队。Reentrantlock是基于CAS和AQS,那么我们来讲讲它俩是什么意思。
CAS是compare and swap的缩写,比较并替换,这是用来操作状态的。不做重点讨论。
AQS是AbstractQueuedSynchronizer的缩写,抽象排队同步器,叫什么不重要,它是一个构建锁和同步容器的框架,它是链表结构,头部节点也被称为哨兵节点或者哑节点。AQS主要实现的是对同步状态的管理,对阻塞线程进行排队,等待通知等。以上这些抽象概念不好懂,那么reentrantlock到底在哪里使用了呢?
在这里插入图片描述

在尝试修改同步状态后,如果失败,则调用AQS提供的acquire方法。
在这里插入图片描述

tryAcquire再次尝试获取同步状态,如果继续失败,调用addWaiter方法添加到等待队列。
就看到这里不做更深入了,有兴趣自己看看吧。

回到一开始的问题,lock和synchronized的区别都在哪里?
Synchronized是一个关键字,lock是一个接口,reentrantlock是lock的实现。Synchronized的锁是可以自动释放的默认非公锁,lock则是需要unlock方法手动解锁。但lock可以用的操作更多,比如可以让等待锁的线程响应中断trylock(),知道线程有没有获取到锁holdlock()。并且在大量资源竞争的情况下,lock性能也更优。

总结的说说synchronized吧。
它可以修饰在方法和变量,方法也分为普通方法(锁住当前实例对象),静态同步方法(锁住当前类对象),同步方法块(锁住括号内对象)。

总结的说说锁吧
锁分为四种状态,按照升级顺序是无锁,偏向锁,轻量级锁,重量级锁。
对于锁和synchronized的一些原理深入内容之后单独研究一下吧。

最后说一下死锁,定义都不陌生,说说四个条件
互斥:只能我自己用,别人只能等着我用完
请求和保持:我想用别的资源了,我请求发出去然后开始等待,保持我自己的资源不放
不可剥夺:我自己获取的资源只能我自己释放(我不给你,你不能抢)
环路等待:等待形成了一个环,造成了互相等待
死锁的发生必须同时存在上述四个条件。

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值