Java 中获取互斥锁的传统方式是使用 synchronized 关键字, 但是 Java5 添加了新的锁实现, 比如 ReentrantLock 和 ReentrantReadWriteLock, 它们提供了锁的扩展操作功能.
ReentrantLock Vs Synchronized
-
它们都是同步锁, 也就是说当如果一个线程获得了对象锁,进入了同步块,其他访问该同步块的线程都必须阻塞在同步块外面等待.
ReentrantLock 用 lock() 和 unlock() 在函数中开启锁和关闭锁.
-
synchronized 的使用更加严格. 所有锁的获取和释放都应该以块结构的方式进行. 当获取多个锁时,它们必须以相反的顺序释放,否则可能导致死锁. synchronized 同一时间只有一个线程正在执行 lock 后面的任务(完全互斥排他的效果), 效率低下.
-
ReentrantLock 相比 synchronized 的明显区别是性能优势(伴随jvm的优化这个差距在减小). 同时Lock有更灵活的锁定方式.
-
ReentrantLock 使用 lock() 和 unlock() 来加锁和解锁, 它提供了灵活性, 使用户有责任遵循以下约定, 如下使用 ReentrantLock:
Lock lock = new ReentrantLock();
lock.lock();
try {
// 访问此锁保护的资源
} finally {
lock.unlock();
}
在进入 try 代码块前应该获取锁, 在 finally 中释放锁. 而使用 synchronized 为了保护关键部分,没有这样的约定,即隐式完成获取和释放锁.
- ReentrantLock 通过使用同步方法和语句提供了更多功能
-
提供使用 tryLock() 方法的非阻塞尝试来获取锁,该方法仅在调用时另一个线程未持有该锁时才获取该锁.
-
提供一种获取锁的功能,可以使用 lockInterruptibly() 方法获取锁,除非当前线程被中断,否则该方法将获取锁.
-
提供一种功能,用于获取 tryLock(long timeout, TimeUnit unit)方法超时的锁,该方法如果在给定等待时间内未由另一个线程持有,并且当前线程未中断,则获取该锁.
-
ReentrantLock 还提供了是否是公平锁的选择, 该选项与同步方法和语句不一起存在. 如果使用 synchronized 关键字, 任何等待线程都可以获取锁, 这可能会导致 thread starvation.
ReentrantLock类具有一个构造函数,该构造函数将布尔值作为参数.
/** * Creates an instance of {@code ReentrantLock} with the * given fairness policy. * * @param fair {@code true} if this lock should use a fair ordering policy */ public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
当布尔值作为 true 传递时,此锁应使用公平的排序策略. 请注意,公平锁偏向等待时间最长的线程.