学了几天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、长时间的自旋会耗费过多的资源。

所以乐观锁多用于读数据多的场景,效率较高。

乐观锁:认为无论本人进行什么操作,那一瞬间都会有其余线程来净化数据,所以肯定要加锁。

乐观锁很好了解,不须要加什么例子了,synchronizedLock都属于乐观锁。对于这两个类的应用,我想另写一篇博客,毕竟日常应用比拟多嘛。乐观锁多用于写数据多的场景

自旋锁

上一节重复提到自旋,自旋到底是个什么东东呢?

首先咱们要晓得,一个Java线程被阻塞,会放弃CPU使用权;被唤醒,会从新取得CPU使用权。这两个切换上下文的过程,是极其耗费资源的。如果,一个同步操作(线程占用锁)的工夫极短,那须要用锁的线程能够先等一会儿,待会不必进行上下文切换,拿到锁间接执行,那岂不是极好的。这个期待操作就叫做自旋。

自旋操作个别会规定自旋次数,如果肯定次数还是没有失去锁,那就放弃自旋,进行阻塞。为了更加晋升效率,自适应自旋锁呈现了,它不拘泥于固定的次数,而是依据以往教训,如果以前自旋一段时间能够失去锁,那么超过最大自旋数的时候,容许多自旋几次;如果以往教训总是失败,那么不肯定非得达到最大自旋数,就间接进入自旋状态。

无锁、偏差锁、轻量级锁、重量级锁

依据切换资源耗费老本,能够将锁分为无锁、偏差锁、轻量级锁、重量级锁。

无锁:就是不对资源加锁,例如下面讲到的CAS算法,只是在更新的时候进行一下比拟判断就好。

偏差锁:有一种现实的状态,一段时间内只有一个线程拜访同步代码块,这样是不是连更新时比拟的步骤都能够省略了。这种状况下能够挂上偏差锁,这样该线程在拜访同步代码块的时候就不须要CAS操作了。当,有其余线程来访问共享资源的时候,偏差锁主动降级为轻量级锁。如果没有线程来打搅,只有当虚拟机运行到全局平安点的时候能力撤销偏差锁。

轻量级锁:当一个线程领有轻量级锁,另一个线程想领有这把锁,不会进入阻塞状态,而是先自旋,期待取得锁的机会。然而,当多个线程(至多两个)来获取这把锁时,这把锁会间接降级为重量级锁

重量级锁:当一个线程领有重量级锁时,其余线程想要获取该锁,都会间接进入阻塞状态。在JDK1.6之前synchronized机制应用的时重量级锁,1.6版本之后开始应用轻量级锁偏差锁

偏心锁和非偏心锁

偏心锁:当多个线程申请获取锁时,依据申请的先后顺序放到一个队列里,而后按程序获取锁。此时,线程从阻塞到唤醒是须要上下文切换的。保障公平性,然而效率可能较低。

非偏心锁:非偏心锁,尝试被线程获取的时候,不肯定从线程队列中获取,先看看此时有没有新的线程来获取本锁,如果有,间接把锁给该线程,不须要进行上下文切换。失去公平性,然而可能会提高效率。

可重入锁

可重入锁是指同一个线程能够屡次加同一把锁。ReentrantLocksynchronized都属于可重入锁

public class MyTest {    // 办法嵌套    public synchronized void outThing() {        // do someting        innerThing();    }    public synchronized void innerThing() {        // do something    }}

看下面这种状况,办法嵌套通过synchronized机制2次获取了对象的锁(Monitor)。如果是非可重入锁,肯定会产生死锁。

共享锁和独享锁

共享锁:一个线程给共享资源加上共享锁后,其余线程还能够给这个共享资源加上其余的共享锁。比方常见的读锁。

独享锁:一个资源被加上独享锁后,就不能增加其余锁了。比方常见的写锁。

共享锁和独享锁在mysql层面也是通用概念。

小结

有了这些Java锁的概念,再去看代码就不便多了。接下来会好好钻研下synchronizedReentrantLock