使用
ReentrantLock
比直接使用
synchronized
更安全,可以替代
synchronized
进行线程同步。
但是,
synchronized
可以配合
wait
和
notify
实现线程在条件不满足时等待,条件满足时唤醒,用
ReentrantLock
我们怎么编写
wait
和
notify
的功能呢?
答案是使用
Condition
对象来实现
wait
和
notify
的功能。
我们仍然以
TaskQueue
为例,把前面用
synchronized
实现的功能通过
ReentrantLock
和
Condition
来实现:
class TaskQueue {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private Queue<String> queue = new LinkedList<>();
public void addTask(String s) {
lock.lock();
try {
queue.add(s);
condition.signalAll();
} finally {
lock.unlock();
}
}
public String getTask() {
lock.lock();
try {
while (queue.isEmpty()) {
condition.await();
}
return queue.remove();
} finally {
lock.unlock();
}
}
}
可见,使用
Condition
时,引用的
Condition
对象必须从
Lock
实例的
newCondition()
返回,这样才能获得一个绑定了
Lock
实例的
Condition
实例。
Condition
提供的
await()
、
signal()
、
signalAll()
原理和
synchronized
锁对象的
wait()
、
notify()
、
notifyAll()
是一致的,并且其行为也是一样的:
-
会释放当前锁,进入等待状态;await()
-
会唤醒某个等待线程;signal()
-
会唤醒所有等待线程;signalAll()
- 唤醒线程从
返回后需要重新获得锁。await()
此外,和
tryLock()
类似,
await()
可以在等待指定时间后,如果还没有被其他线程通过
signal()
或
signalAll()
唤醒,可以自己醒来:
if (condition.await(1, TimeUnit.SECOND)) {
// 被其他线程唤醒
} else {
// 指定时间内没有被其他线程唤醒
}
可见,使用
Condition
配合
Lock
,我们可以实现更灵活的线程同步。