RenntrantLock公平锁:
关键字: T1 : 第一个线程 T2 : 第二个线程 T3 : 第三个线程 head: 队头,也就是正在处理的线程 park:睡眠,发生系统调用,膨胀为重量级锁
整体概念: 假如我们来拿锁的线程叫是T1,T1拿锁时由于他是第一个线程,此时连队列都无需初始化,直接拿到锁,性能比较好。 再T1持有锁的过程中,此时又有一个线程T2前来拿锁,此时形成队列并进入队列,进入队列后判断前一个线程是否是head,如果不是,则进入park,如果是,则再一次尝试拿锁,发生自旋,如果拿到,执行同步代码块,如果没拿到,则进入park。 如果这时T3来了,T3跟T2唯一的区别就是T3不会进入自旋,直接park,因为T2不是head。
总结: 1.T1拿到锁时,无需初始化队列,性能较好。 2.如果在T1持有锁时T2拿锁,发生资源竞争,则生成队列,且如果T2的秦前一个线程是head,则T2会发生自旋。 3.如果所有线程都是交替执行,比如T1线程(第一个线程)释放锁后T2线程(第二个线程)才尝试拿锁,那么将永远不会初始化队列。
RenntrantLock非公平锁: 线程T1首次调用lock方法时候直接进行抢锁(公平锁的新线程在调用lock方法的时候不会上来就拿锁),如果加锁失败,则判断为何失败,是否已被人持有,如果没有被持有,则直接加锁,不会判断队列是否有等待线程。如果被持有,则进入队列,进入队列后先判断前面那个线程是否是head,如果是,则再此尝试加锁,成功则执行同步代码,失败则进入park。
1.线程调用lock方法时会直接进行加锁,不会判断队列 2.如果加锁失败会再次直接加锁,也不会判断队列,相当于一次自旋 3.如果加锁再次失败则进入队列,且此时并未park,而是判断前一个线程是否时head,如果是,则发生自旋 4.如果自旋加锁失败,则调用park
疑问: 1.什么叫一朝排队,永远排队? 2.ReentrantLock的park是什么样的? ReentrantLock的park和sunchronized的park都一样,都是调用jvm底层的c++代码写的park,都是调用的操作系统的park方法。但是有一点区别就是在低版本的jdk中,ReentrantLock的park和sunchronized的park调用的不是同一个park,也就是底层有多个park,高版本中貌似是一样的
1.所谓的公平锁和非公平锁在于抢到锁之后会不会先去判断队列。
2.RenntrantLock默认是非公平锁,非公平锁的效率较高。
3.什么场景下使用公平锁?当后一个线程的执行需要依赖前一个线程执行的结果的时候,使用 公平锁。
4.synchronized是一把非公平锁
5.synchronized的同步代码块内部发生异常会释放锁,是在汇编级别进行了处理