学习目标
-
锁的类别有哪些
-
reentrantlock与synchronized的区别
-
设计一把锁要考虑啥
-
如何使用reentrantlock
-
reentrantlock的lock流程
-
reentrantlock的unlock流程
-
AQS的理解
第1章 锁分类
1、乐观锁和悲观锁
-
乐观锁:采用乐观的思想处理数据,在每次读取数据时都认为别人不会修改该数据,所以不会上锁,但在更新时会判断在此期间别人有没有更新该数据,通常采用在写时先读出当前版本号然后加锁的方法。具体过程为:比较当前版本号与上一次的版本号,如果版本号一致,则更新,如果版本号不一致,则重复进行读、比较、写操作。(CAS)
-
悲观锁:采用悲观思想处理数据,在每次读取数据时都认为别人会修改数据,所以每次在读写数据时都会上锁,这样别人想读写这个数据时就会阻塞、等待直到拿到锁。(Synchronized)
2、公平锁和非公平锁
-
公平锁:指在分配锁前检查是否有线程在排队等待获取该锁,优先将锁分配给排队时间最长的线程。
-
非公平锁:指在分配锁时不考虑线程排队等待的情况,直接尝试获取锁,在获取不到锁时再排到队尾等待。
3、共享锁和独占锁
-
独占锁:也叫互斥锁,每次只允许一个线程持有该锁,ReentrantLock为独占锁的实现。
-
共享锁:允许多个线程同时获取该锁,并发访问共享资源。ReentrantReadWriteLock中的读锁为共享锁的实现。
4、重量级锁和轻量级锁
5、可重入锁和不可重入锁
-
可重入锁:也叫作递归锁,指在同一线程中,在外层函数获取到该锁之后,内层的递归函数仍然可以继续获取该锁。在Java环境下,ReentrantLock和synchronized都是可重入锁。
-
不可重入锁:每次都要重新抢占锁资源。StampedLock是jdk1.8新增的重入锁
6、自旋锁:说白了就是一个循环
7、分段锁:说白了就是对每个区间进行上锁
8、如何进行锁优化
-
减少锁持有的时间 减少锁持有的时间指只在有线程安全要求的程序上加锁来尽量减少同步代码块对锁的持有时间。
-
减小锁粒度 减小锁粒度指将单个耗时较多的锁操作拆分为多个耗时较少的锁操作来增加锁的并行度,减少同一个锁上的竞争。在减少锁的竞争后,偏向锁、轻量级锁的使用率才会提高。减小锁粒度最典型的案例就是ConcurrentHashMap中的分段锁。
-
锁分离 锁分离指根据不同的应用场景将锁的功能进行分离,以应对不同的变化,最常见的锁分离思想就是读写锁(ReadWriteLock),它根据锁的功能将锁分离成读锁和写锁,这样读读不互斥,读写互斥,写写互斥,既保证了线程的安全性,又提高了性能。 操作分离思想可以进一步延伸为只要操作互不影响,就可以进一步拆分,比如LinkedBlockingQueue从头部取出数据,并从尾部加入数据。
-
锁粗化 锁粗化指为了保障性能,会要求尽可能将锁的操作细化以减少线程持有锁的时间,但是如果锁分得太细,将会导致系统频繁获取锁和释放锁,反而影响性能的提升。在这种情况下,建议将关联性强的锁操作集中起来处理,以提高系统整体的效率。
-
锁消除 在开发中经常会出现在不需要使用锁的情况下误用了锁操作而引起性能下降,这多数是因为程序编码不规范引起的。这时,我们需要检查并消除这些不必要的锁来提高系统的性能。
第2章 reentrantlock与synchronized的区别
1、底层实现层面
synchronized 是JVM层面的锁,是Java关键字
reentrantlock是JUC下面的一个类,是java实现的
2、是否可手动释放
synchronized不需要手动释放,reentrantlock需要手动释放
3、是否可以中断
synchronized不可中断,reentrantlock可以
4、效率层面
reentrantlock效率比synchronized要高
5、锁的层面
reentrantlock的对象就是锁本身,synchronized锁的是别的对象;
reentrantlock可以
6、公平和非公平层面
reentrantlock可以是公平也可以是非公平,通过构造函数指定,synchronized是非公平
第3章 如何设计一把锁
先来看看我这代码里面实现了一把锁
public class RepeatLock {
boolean isLocked = false;
Thread lockedBy = null;
int lockedCount = 0;
public synchronized void lock()
throws InterruptedException{
Thread thread = Thread.currentThread();
while(isLocked && lockedBy != thread){
wait();
}
isLocked = true;
lockedCount++;
lockedBy = thread;
}
public synchronized void unlock(){
if(Thread.currentThread() == this.lockedBy){
lockedCount--;
if(lockedCount == 0){
isLocked = false;
notify();
}
}
}
}
public class Count {
// 不可重入锁
UnRepeatLock lock = new UnRepeatLock();
public void print() {
System.out.println("获取lock");
lock.lock();
System.out.println("调用doAdd之前");
doAdd();
System.out.println("调用doAdd之后");
lock.unlock();
System.out.println("释放lock");
}
public void doAdd() {
System.out.println("再次获取lock");
lock.lock();
//do something
lock.unlock();
System.out.println("再次释放lock");
}
publ