Java中的分很多种类,按照场景的不同、特性的不同等分为了很多类,下面就来讲讲Java中锁的概念:
synchronized
是非公平锁)。悲观锁
在获取资源的时候,认为会有其它线程也要来修改资源(假定会有冲突),于是在获取资源的时候,会将线程先加锁,避免数据被其他线程修改。
乐观锁
在获取资源的时候,认为不会有其它线程来资源资源(假定没有冲突),所以在获取资源的时候,不会加锁。其他线程来获取资源的时候,会根据实现场景的不同而采取不同的方式(重试或报错)。
在Java语言中,对于悲观锁和乐观锁有不同的实现。
synchronized
关键字和Lock
相关实现类都是悲观锁。J.U.C
包下面的相关原子类实现了乐观锁,比如说AtmoicInteger
类synchronized
实现悲观锁,是通过在对象头中添加一个锁的状态。我们知道synchronized
是锁住的对象,明确了这一点,我们再来理解synchronized锁就很简单了。只要一个线程获取到了对象的锁,会修改对象头中的Mark Word状态,同时线程中也会保存对应的状态。
而Java中的乐观锁最常采用的是CAS
算法。
阻塞或唤醒一个Java线程需要操作系统切换CPU状态来完成,这种状态转换需要耗费处理器时间。如果同步代码块中的内容过于简单,状态转换消耗的时间有可能比用户代码执行的时间还要长。
在很多场景下,同步代码块的执行时间很短,有时候线程挂起和恢复线程的时间花费可能就要比线程切换的时间还要长,这样子做事得不偿失的。所以在这种这种场景下就可以使用自旋锁,比如说CAS。
场景描述: 在两个线程(线程A、线程B)访问同步资源的时候,线程A先获取同步资源并加锁,线程B这时再来获取同步资源。
自旋锁:线程B发现不能获得锁(获取锁失败),线程B不会放弃CPU时间片,而是不断自旋获取锁,直到获取锁成功。这就是CAS算法
的做法,当然了也会CAS算法
的缺点,比如说:一直占用线程,造成CPU使用率过高。所以,自旋等待的时间必须要有一定的限度,如果自旋超过了限定次数(默认是10次,可以使用-XX:PreBlockSpin
来更改)没有成功获得锁,就应当挂起线程。
自旋锁在JDK1.4.2中引入,使用-XX:+UseSpinning
来开启。JDK 6中变为默认开启,并且引入了自适应的自旋锁(适应性自旋锁)。
自适应意味着自旋的时间(次数)不再固定,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。如果在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也是很有可能再次成功,进而它将允许自旋等待持续相对更长的时间。如果对于某个锁,自旋很少成功获得过,那在以后尝试获取这个锁时将可能省略掉自旋过程,直接阻塞线程,避免浪费处理器资源。
在自旋锁中 另有三种常见的锁形式:TicketLock
、CLHlock
和MCSlock
,感兴趣的同学可以自行查阅相关资料。
这四种锁是针对synchronized
关键字提出的,在说这四种锁之前先来简单介绍一个重要的知识点:Mark Word
Mark Word
是保存在Java
对象头中的数据,在HotSpot虚拟机
的Java对象头中,有两部分的数据Mark Word(标记字段)、Klass Pointer(类型指针)。Klass Point是是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例,Mark Word用于存储对象自身的运行时数据,它是实现轻量级锁和偏向锁的关键,今天要介绍的也是Mark Word
。
Mark Word用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等,今天我们着重关注锁标志位。
Mark Word一共有五个锁标志位:
锁状态 | 锁标志位 | 是否偏向锁 |
---|---|---|
无锁态 | 01 | hashCode、分代年龄,是否是偏向锁(0) |
偏向锁 | 01 | 偏向线程ID、偏向时间戳、对象分代年龄、是否是偏向锁(1) |
轻量级锁 | 00 | 指向栈中锁记录的指针 |
重量级锁 | 10 | 指向互斥量(重量级锁)的指针 |
Mark Word保存的不同锁标志对应了不同的锁状态 ,这些状态也都是针对synchronized关键提出,锁之间转换是通过加锁
、解锁
、锁升级
来实现的。
无锁的状态就是不会对同步资源加锁,所有线程都能访问并修改同一资源,但只能有一个线程修改成功。
无锁的特点就是修改操作在循环内进行,线程会不断的尝试修改共享资源。如果没有冲突就修改成功并退出,否则就会继续循环尝试。如果有多个线程修改同一个值,必定会有一个线程能修改成功,而其他修改失败的线程会不断重试直到修改成功。上面我们介绍的CAS原理及应用即是无锁的实现。无锁无法全面代替有锁,但无锁在某些场合下的性能是非常高的。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。