重入锁(ReentrantLock)
内置锁是jvm内部支持的,使用时不需要显示的加锁和释放锁,因此内置锁也被称为隐式锁。而重入锁使用时需要显式的加锁和释放锁,因此属于显式锁。
一、重入锁概述
重入锁是JDK1.5引入的,作为一种线程同步机制,其作用与内置锁相同,但并不是用来替代内置锁的。但它提供了一些内置锁不具备的特性。在java中使用Lock接口来表示对显式锁的抽象,而ReentrantLock是Lock接口的默认实现类。
Lock lock = new ReentrantLock();//创建锁实例 lock.lock();//申请锁 try { //访问共享数据 …… } finally { lock.unlock();//手动释放锁,防止锁泄露 }
为了避免发生异常而导致锁泄露,即锁不被释放,建议把unlock操作放在finally中。可见,显示锁不像内置锁那样可以由jvm代为规避锁泄露问题。
二、重入锁的公平性
公平锁指线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先获得。非公平锁是基于抢占式的获取锁,先来不一定先获得锁,这样就会造成有些线程一直拿不到锁,所以就不公平了。
重入锁支持公平锁和非公平锁,默认为非公平锁。如果为了确保公平,即让线程都有机会获取锁,必然会让线程进行竞争锁,这必然会导致过多的线程上下文切换,这也就是重入锁默认使用非公平策略的原因。公平锁适合于被持有的时间相对长或者线程申请锁的平均时间间隔相对长的情形。总的来说使用公平锁的开销比非公平锁的开销要大。
三、重入锁的实现原理
四、内置锁和显式锁的比较
内置锁和显式锁各有所长,并不能相互替代。
1.易用性
内置锁简单易用,且不会导致锁泄露。而显式锁容易因错用而导致锁泄露,必须要牢记住要在finally中释放掉锁。
2.灵活性
显式锁比内置锁更加灵活。内置锁的申请和释放只能在一个方法内进行(因为代码块无法跨方法),而显式锁可以在一个方法内申请锁,在另一个方法里释放锁。
3.显式锁多出的特性
①等待时间
线程因竞争不到内置锁而可能等待较长时间,但显式锁支持获取超时,通过tryLock方法可以指定一个时间。
②锁调度方面
内置锁仅支持非公平锁,而显式锁既支持非公平锁,也支持公平锁
③问题定位方面
在定位生产环境问题的时候,线程转储(Thread dump)可以告诉我们JVM中关于线程的详细信息。线程转储会包含内部锁的相关信息,包括一个线程等待哪些锁以及这些锁的当前(获取相应线程转储那一刻)持有线程。而JDK1.5下,线程转储中并不包含显式锁相关信息。不过JDK6提供了jstack工具,用它产生的线程转储中可以包含显式锁的信息。
另外,显式锁提供了一些方法可以用来对锁的相关信息进行监控,而内置锁不支持这种特性。ReentrantLock中定义的isLocked()可用来检测锁是否被某个线程持有,getQueueLength()方法可以用于检查所的等待线程数量。
4.性能差异
5.锁的选择
总结
1.重入锁的公平性?两者的区别?适用场景?
重入锁分为公平锁和非公平锁,默认为非公平锁。
公平锁:如果为了确保公平,即让线程都有机会获取锁,必然会让线程进行竞争锁,这必然会导致过多的线程上下文切换。
非公平锁:
2.重入锁与内置锁的区别?如何选择?
3.重入锁为何可防止死锁?
锁申请等待可中断(lockInterruptibly)
锁申请等待可限时(tryLock)
4.重入锁的实现原理?