前言
在阅读本文之前, 需要对CAS 和 synchronized关键字有一定的了解,可以读一下这篇关于CAS的文章和这篇关于synchronized的文章
ReentrantLock
,就是java中基于CAS的新的同步机制之一。
顾名思义,ReentrantLock
,又叫可重入锁。 而synchronized
也是一个可重入锁,我们可以说,ReentrantLock就是synchronized的替代品。
本文将从ReentrantLock的常用API入手,然后比较一下ReentrantLock与synchronized。
常用API
lock()与unlock()
lock()
与unlock()
,顾名思义,就是加锁和解锁的操作。对应于synchronized中的加锁和解锁。
下面两段代码的效果应该是相同的。
// 使用ReentrantLock的代码
ReentrantLock lock = new ReentrantLock();
public void method() {
try {
lock.lock();
// code logic
} finally {
lock.unlock();
}
}
// 使用synchronized的代码
public void method() {
synchronized(this) {
// code logic
}
}
但是需要注意,lock.unlock()
方法是必须放在finally代码块中的,确保这个方法一定要执行。
boolean tryLock(timeout, unit)
这个方法就是ReentrantLock与synchronized不同之处之一了。
这个方法的作用是,尝试在指定的时间内不断的去获取锁,如果获取成功,返回true
,如果没有拿到锁就返回false
。
下面这段测试代码:
static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
// thread1 拿到锁后睡眠5秒
(new Thread(new Runnable() {
@Override
public void run() {
try{
lock.lock();
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
})).start();
// thread2 用tryLock尝试拿锁
(new Thread(new Runnable() {
@Override
public void run() {
try {
boolean res = lock.tryLock(10, TimeUnit.SECONDS); // res 为false
// boolean res = lock.tryLock(3, TimeUnit.SECONDS); // res 为true
System.out.println(res);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
})).start();
}
首先有thread1
先拿到ReentrantLock, 然后睡眠5
秒。
然后有thread2
分别尝试在3
秒内拿锁或者10
秒内拿锁。
根据不同的命令,会在3秒尝试拿锁中返回false,而在10秒尝试拿锁时返回true。
lockInterruptibly()
这个方法也是ReentrantLock有别于synchronized的地方。
这个方法是说,当一个线程阻塞等待锁的过程是可以被打断的,调用interupt()
方法会抛出异常。但是在synchronized中,等待锁的线程是不能被打断的。
看看下面这段测试代码:
static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
// thread1 拿到锁后无限运行
(new Thread(new Runnable() {
@Override
public void run() {
try{
lock.lock();
while(true) {
}
} finally {
lock.unlock();
}
}
})).start();
// thread2 用lockInterruptibly加锁。
Thread thread2 = (new Thread(new Runnable() {
@Override
public void run() {
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}));
thread2.start();
thread2.interrupt();
}
总结
本文讲了一个Java中基于CAS的新的同步机制——ReentrantLock,通过介绍它的API,来对比它与synchronized的异同之处。