JAVA锁机制
1.1 悲观锁
- 悲观锁:顾名思义,在每次拿数据的时候都认为会造成数据的丢失,特别悲观,会直接上锁(如
select * from user for update)- 缺点是只能保持一个链接进行操作,查询量少可使用悲观锁

1.2 乐观锁
乐观锁:顾名思义,很乐观,认为每次查询都不会数据丢失。
- 原理:利用版本号(数据库字段)+影响行数判断是否为零
1.3 重入锁
重入锁:也叫递归锁,外层函数还是获取该锁之后,内层函数还有获取该锁代码的权限。
常见重入锁:在Java环境下ReentrantLock和synchronized都是可重入锁
Lock lock = new ReentrantLock();1.3.1 锁的获取和释放过程如下:
1、线程再次获取锁。锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是则再次获取成功。
2、锁的最终释放。线程重复n次获取了锁,随后在第n次释放该锁后,其他线程能够获取到该锁。锁的最终释放要求锁对获取进行计数自增,计数表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数器等于0时表示锁已经成功释放了。- 分为公平锁和非公平锁:
- 公平锁:
对先发起请求的线程即等待最久的线程优先满足,获取锁是顺序的,符合FIFO原则,不会产生线程饥饿;获取锁调用tryAcquire方法,与非公平锁不一样的地方在于判断条件多了hasQueuedPredecessors()方法,这个方法判断队列中是否有其他节点,如果队列中还有其他节点,但是head后面还没关联节点 / 或者队列中head节点的后继节点关联的线程不是当前线程,如果是返回true,则表示有线程比当前线程更早地请求获取锁,因为要等待前驱节点获取并释放锁后才嫩继续获取到锁。
- 非公平锁(默认的):
获取是使用nonfairTryAcquire方法,只要CAS设置同步状态成功,则当前线程获取了锁。
非公平锁比公平锁效率更高,因为公平锁为了保证公平性会去切换线程导致上下文切换,存在额外的开销,所以非公平锁性能更好(所以作为默认的实现方式),保证了更大的吞吐量,但是可能会产生线程饥饿。1.3.2 重入锁的底层实现:
锁底层大多方法是使用AQS来实现的。
下面我们看下ReentrantLock的构造函数public ReentrantLock() { //默认实现是以非公平锁实现的 sync = new NonfairSync(); }从上面这个代码可以看出,我们要分析两个东西:一个是sync,一个是NofairSync(非公平锁):
1
2
3
4
5public class ReentrantLock implements Lock, java.io.Serializable {
//我们刚刚要找的sync字段
private final Sync sync;
//Sync继承了AbstractQueuedSynchronizer
abstract static class Sync extends AbstractQueuedSynchronizer {- sync分析:从上面源码可以看出sync是ReentrantLock内的属性,而且Sync是ReentrantLock的内部类,并且继承了AbstractQueuedSynchronizer,这个就是我们常常说的AQS,再进入AQS类看下:
abstract class AbstractQueuedSynchronizer 1
2extends AbstractOwnableSynchronizer
implements java.io.Serializable {从上面源码可以看出AbstractQueuedSynchronizer继承AbstractOwnableSynchronizer,也就是AQS继承AOS(后面都用AQS代表AbstractQueuedSynchronizer,AOS代表AbstractOwnableSynchronizer),我们再看看还没分析的NofairSync;
class ReentrantLock implements Lock, java.io.Serializable { 1
2//NonfairSync继承Sync
static final class NonfairSync extends Sync {- NofairSync分析:NonfairSync也是ReentrantLock的内部类,并且继承Sync,难怪刚刚new NonfairSync()可以直接赋值给sync我们再看下ReentrantLock类的结构:
到这里我们可以总结下:
1.ReentrantLock下面有三个内部类:Sync,NonfairSync,FairSync
2.AQS继承AOS
2.Sync继承AQS
3.NonfairSync(非公平锁)、FairSync(公平锁)分别继承Sync那我们可以得出UML图

- 分为公平锁和非公平锁:
1.4 读写锁
读写锁:顾名思义是一把锁分为两部分:读锁和写锁,其中读锁允许多个线程同时获得,因为读操作本身是线程安全的,而写锁则是互斥锁,不允许多个线程同时获得写锁,并且写操作和读操作也是互斥的。ReentrantLockReadWriterLock里的readLock和writeLock。
- 特点:读读不互斥、读写互斥、写写互斥
1.5 CAS无锁机制
原子类底层实现保证线程安全,通过CAS无锁机制(天生免疫死锁),效率比有锁机制高。
- CAS:CAS体系中有三个参数(V,E,N),V表示需要更新的变量,E表示期望值,N表示新值,仅当V=E时,才会将V设置为N,否则什么都不做,最后后返回V的真实值。
1.6 自旋锁
采用让当前线程不停的在循环体内执行实现,当循环的条件被其他线程改变时,才能进入临界区。