ReentrantLock和synchronized的相同点
1.ReentrantLock和synchronized都是独占锁,只允许线程互斥的访问临界区。但是实现上两者不同:synchronized加锁解锁的过程是隐式的,用户不用手动操作,优点是操作简单,但显得不够灵活。一般并发场景使用synchronized的就够了;ReentrantLock需要手动加锁和解锁,且解锁的操作尽量要放在finally代码块中,保证线程正确释放锁。ReentrantLock操作较为复杂,但是因为可以手动控制加锁和解锁过程,在复杂的并发场景中能派上用场。
2.ReentrantLock和synchronized都是可重入的。synchronized因为可重入因此可以放在被递归执行的方法上,且不用担心线程最后能否正确释放锁;而ReentrantLock在重入时要却确保重复获取锁的次数必须和重复释放锁的次数一样,否则可能导致其他线程无法获得该锁。
ReentrantLock公平锁
公平锁是指当锁可用时,在锁上等待时间最长的线程将获得锁的使用权。而非公平锁则随机分配这种使用权。和synchronized一样,默认的ReentrantLock实现是非公平锁,因为相比公平锁,非公平锁性能更好。当然公平锁能防止饥饿,某些情况下也很有用。在创建ReentrantLock的时候通过传进参数true创建公平锁,如果传入的是false或没传参数则创建的是非公平锁
例子
public class Java_ReentrantLock {
public void test() throws InterruptedException {
// ReentrantLock是独占锁且可重入的
ReentrantLock lock = new ReentrantLock();
for (int i = 1; i <= 3; i++) {
lock.lock();
}
for (int i = 1; i <= 3; i++) {
try {
} finally {
lock.unlock();
}
}
}
public void test1() {
// 场景 1:如果发现该操作已经在执行中则不再执行(有状态执行)
ReentrantLock lock = new ReentrantLock();
if (lock.tryLock()) { // 如果已经被 lock,则立即返回 false 不会等待,达到忽略操作的效果。
try {
// 操作
} finally {
lock.unlock();
}
}
}
public void test2() {
// 场景 2:如果发现该操作已经在执行,等待一个一个执行(同步执行,类似 synchronized)
// 公平情况下,操作会排一个队按顺序执行,来保证执行顺序。(会消耗更多的时间来排队)
// 不公平情况下,是无序状态允许插队,JVM 会自动计算如何处理更快速来调度插队。(如果不关心顺序,这个速度会更快)
ReentrantLock lock = new ReentrantLock(); // 参数默认false,不公平锁
// ReentrantLock lock = new ReentrantLock(true); //公平锁
try {
lock.lock(); // 如果被其它资源锁定,会在此等待锁释放,达到暂停的效果
// 操作
} finally {
lock.unlock();
}
}
public void test3() {
// 场景 3:如果发现该操作已经在执行,则尝试等待一段时间,等待超时则不执行(尝试等待执行)
ReentrantLock lock = new ReentrantLock();
try {
if (lock.tryLock(5, TimeUnit.SECONDS)) { // 如果已经被 lock,尝试等待
// 5s,看是否可以获得锁,如果 5s
// 后仍然无法获得锁则返回 false
// 继续执行
try {
// 操作
} finally {
lock.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace(); // 当前线程被中断时(interrupt),会抛 InterruptedException
}
}
public void test4() {
// 场景 5:条件判断。
// 每一个 lock 可以有任意数据的 Condition 对象
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lock.lock();
try {
boolean cnd = false;
while (cnd) {
condition.wait();
}
// 处理逻辑
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
Comments