学了几天python,辣条君始终不忘本人其实是个Javaer。来,跟着辣条君一起看看Java锁是如何分类的吧。
Java锁是为了保障并发过程中,数据保护的准确性。
乐观锁与乐观锁
乐观锁
:认为以后读取数据的时候,不会有线程去批改数据,所以不须要加锁。当更新数据的时候,首先查看数据和本人已经记录的数据是否统一,如果统一,则更新之;如果不统一,采取一些伎俩,比方报错或者自旋(自旋前面会讲)。
举个例子,一个线程A读取账户余额时,不会加锁,读到20元,线程A账户记录更新为20元。而后线程A为账户余额减少5元,当初想把账户余额更新为25元,先去查看账户当初的数值为20元,和账户记录统一,就将账户余额间接更新为25元,同时将本人的账户记录更新为25元。过了一会儿,线程A又想给账户余额减少5元,于是拿着30元去更新账户余额。此时,发现账户余额为100元,和本人的账户记录(25元)不统一了,就报错(或者自旋),此次更新失败。
CAS
(比拟替换)就是一种常见的乐观锁实现计划,java.util.concurrent.atomic
中的那些原子类就是通过CAS
算法实现的。为了保障更新的原子性,原子类最终本质上是通过JNL调用了CPU的原子操作。CAS
先天有两点有余:1、ABA
问题。2、长时间的自旋
会耗费过多的资源。
所以乐观锁多用于读数据多的场景,效率较高。
乐观锁
:认为无论本人进行什么操作,那一瞬间都会有其余线程来净化数据,所以肯定要加锁。
乐观锁很好了解,不须要加什么例子了,synchronized
和Lock
都属于乐观锁。对于这两个类的应用,我想另写一篇博客,毕竟日常应用比拟多嘛。乐观锁多用于写数据多的场景
自旋锁
上一节重复提到自旋,自旋到底是个什么东东呢?
首先咱们要晓得,一个Java线程被阻塞,会放弃CPU使用权;被唤醒,会从新取得CPU使用权。这两个切换上下文的过程,是极其耗费资源的。如果,一个同步操作(线程占用锁)的工夫极短,那须要用锁的线程能够先等一会儿,待会不必进行上下文切换,拿到锁间接执行,那岂不是极好的。这个期待操作就叫做自旋。
自旋操作个别会规定自旋次数,如果肯定次数还是没有失去锁,那就放弃自旋,进行阻塞。为了更加晋升效率,自适应自旋锁呈现了,它不拘泥于固定的次数,而是依据以往教训,如果以前自旋一段时间能够失去锁,那么超过最大自旋数的时候,容许多自旋几次;如果以往教训总是失败,那么不肯定非得达到最大自旋数,就间接进入自旋状态。
无锁、偏差锁、轻量级锁、重量级锁
依据切换资源耗费老本,能够将锁分为无锁、偏差锁、轻量级锁、重量级锁。
无锁
:就是不对资源加锁,例如下面讲到的CAS算法,只是在更新的时候进行一下比拟判断就好。
偏差锁
:有一种现实的状态,一段时间内只有一个线程拜访同步代码块,这样是不是连更新时比拟的步骤都能够省略了。这种状况下能够挂上偏差锁,这样该线程在拜访同步代码块的时候就不须要CAS
操作了。当,有其余线程来访问共享资源的时候,偏差锁主动降级为轻量级锁。如果没有线程来打搅,只有当虚拟机运行到全局平安点的时候能力撤销偏差锁。
轻量级锁
:当一个线程领有轻量级锁,另一个线程想领有这把锁,不会进入阻塞状态,而是先自旋,期待取得锁的机会。然而,当多个线程(至多两个)来获取这把锁时,这把锁会间接降级为重量级锁。
重量级锁
:当一个线程领有重量级锁时,其余线程想要获取该锁,都会间接进入阻塞状态。在JDK1.6之前synchronized
机制应用的时重量级锁,1.6版本之后开始应用轻量级锁和偏差锁
偏心锁和非偏心锁
偏心锁
:当多个线程申请获取锁时,依据申请的先后顺序放到一个队列里,而后按程序获取锁。此时,线程从阻塞到唤醒是须要上下文切换的。保障公平性,然而效率可能较低。
非偏心锁
:非偏心锁,尝试被线程获取的时候,不肯定从线程队列中获取,先看看此时有没有新的线程来获取本锁,如果有,间接把锁给该线程,不须要进行上下文切换。失去公平性,然而可能会提高效率。
可重入锁
可重入锁
是指同一个线程能够屡次加同一把锁。ReentrantLock
和synchronized
都属于可重入锁。
public class MyTest { // 办法嵌套 public synchronized void outThing() { // do someting innerThing(); } public synchronized void innerThing() { // do something }}
看下面这种状况,办法嵌套通过synchronized
机制2次获取了对象的锁(Monitor)。如果是非可重入锁,肯定会产生死锁。
共享锁和独享锁
共享锁
:一个线程给共享资源加上共享锁后,其余线程还能够给这个共享资源加上其余的共享锁。比方常见的读锁。
独享锁
:一个资源被加上独享锁后,就不能增加其余锁了。比方常见的写锁。
共享锁和独享锁在mysql层面也是通用概念。
小结
有了这些Java锁的概念,再去看代码就不便多了。接下来会好好钻研下synchronized
和ReentrantLock
。