# java中的锁
参考原文章: [https://www.cnblogs.com/jyroy/p/11365935.html](https://www.cnblogs.com/jyroy/p/11365935.html)
## 乐观锁 VS 悲观锁
概念:
对同一个数据的并发操作, 悲观锁认为自己在使用数据的时候,一定有别的线程来修改数据,因此在获取数据的时候就进行加锁。 乐观锁任务自己在使用数据时不会有别的线程来修改数据, 所以不会添加锁, 只会在更新的时候,判断之前有没有别的线程更新过这个数据。
乐观锁在java中是通过无锁编程来实现的,最常用的是CAS算法。
Java中, synchronized关键字和Lock的实现类都是悲观锁。
适用场景:
乐观锁适合读操作读的场景, 不加锁可以使得读操作的性能大幅提升。
悲观锁适合写操作多的场景, 乐观锁经常会失效, 不如直接加锁保证写入安全。
## 公平锁和非公平锁
公平锁是指多个线程按照申请锁的顺序来获取锁, 非公平锁则表示可能会插队。
对于 ReentrantLock 而言, 非公平锁就是加入队列之前会先尝试一次直接获取锁。
`synchronized`关键字加的是非公平锁。
## 独享锁 VS 共享锁
独享锁是指该锁一次只能被一个线程所持有
共享锁是指该锁可同时被多个线程锁持有
`ReentrantReadWriteLock` 有两个锁: 读锁是共享锁, 写锁是独享锁
读锁的共享锁可保证并发读是非常高效的,读写,写读 ,写写的过程是互斥的(A线程拿到读锁,B线程申请写锁需要等A释放掉读锁,B线程申请读锁则可以立即拿到)。
独享锁与共享锁也是通过AQS来实现的,通过实现不同的方法,来实现独享或者共享。
`ReentrantReadWriteLock`适用于读多写少的场景
`ReentrantLock` 和 `Synchronized` 都是独享锁。
## 分段锁
分段锁是一种锁的设计,并不是具体的一种锁。
典型的例子就是ConcurrentHashMap, 当进行put操作时,不会对整个hashmap进行加锁, 会先计算要加入的key分到哪个segment中, 然后对segment进行加锁。
## 自旋锁
自旋锁是指线程获取锁失败时,不会立即阻塞,而是采用循环的方式再尝试几次, 如果锁占用时间比较短的话, 自旋后可以获得锁。
这样做的好处是减少线程上下文切换的消耗,缺点是循环会消耗CPU。
`适应性自选锁` 是对自选锁的改进(jdk1.6加入), 自旋的次数不再固定,而是根据前一次在同一个锁上的自旋时间以及锁的拥有者的状态来决定。 如果自旋后可以获得锁,那么下次还会自旋,否则自旋可能没效果, 将会取消掉。