condition可以通俗的理解为条件队列。当一个线程在调用了await方法以后,直到线程等待的某个条件为真的时候才会被唤醒。这种方式为线程提供了更加简单的等待/通知模式。Condition必须要配合锁一起使用,因为对共享状态变量的访问发生在多线程环境下。一个Condition的实例必须与一个Lock绑定,因此Condition一般都是作为Lock的内部实现。
这里我们以简单的支付作为一个案例,现在我们要支付两块钱,冲钱的时候每次充值一块钱。
这里使用条件队列的原因是:我们支付和充值都涉及到账户金额的变化,所以我们就需要对充值流程和支付流程加同一把锁,这里就存在一种情况,就是我支付流程一直霸占的锁,导致无法充值。所以我们这里需要引入条件队列
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionAndLock {
private final ReentrantLock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private int amount = 0;
public void method1(String name){
System.out.println(name + "付钱线程-启动");
lock.lock();
try {
System.out.println(name + "付钱线程-获取锁");
Thread.sleep(3000);
while (amount <= 1){
System.out.println(name + "付钱线程-释放锁,阻塞进入等待前的金额" + amount);
condition.await();//线程会释放当前占用的锁,并进入等待
System.out.println(name + "付钱线程-被唤醒后的金额" + amount);
}
amount -= 2;
System.out.println(name + "付钱线程-支付两块钱");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + "离开-付钱线程,并解锁");
lock.unlock();
}
public void method2(String name){
System.out.println(name + "充钱线程-启动");
lock.lock();
try {
System.out.println(name + "充钱线程-获取锁");
Thread.sleep(500);
amount += 1;
System.out.println(name + "充钱线程-充一块钱" + amount);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + "充钱线程-随机唤醒等待队列中的一个-付钱线程");
condition.signal();//随机唤醒等待队列中的一个线程
System.out.println(name + "离开充钱线程,并解锁");
lock.unlock();
}
public static void main(String[] args) {
ConditionAndLock c = new ConditionAndLock();
Thread t =new Thread(new Runnable() {
@Override
public void run() {
c.method1("付钱测试1-");
}
});
Thread t2 =new Thread(new Runnable() {
@Override
public void run() {
c.method1("付钱测试2-");
}
});
Thread t3 =new Thread(new Runnable() {
@Override
public void run() {
c.method2("充值测试3-");
}
});
Thread t4 =new Thread(new Runnable() {
@Override
public void run() {
c.method2("充值测试4-");
}
});
t.start();
t2.start();
t3.start();
t4.start();
}
}
测试结果:从运行结果可以看出来。我们要支付的时候发现金额不够,就释放锁,线程进入条件队列。之后进入每次充值之后都会唤醒在条件队列中的付钱线程,唤醒之后重新判断是否满足付钱条件,只有线程才会往下执行,不满足就重新进入条件队列。
付钱测试2-付钱线程-启动
充值测试3-充钱线程-启动
充值测试4-充钱线程-启动
付钱测试1-付钱线程-启动
付钱测试2-付钱线程-获取锁
付钱测试2-付钱线程-释放锁,阻塞进入等待前的金额0
充值测试3-充钱线程-获取锁
充值测试3-充钱线程-充一块钱1
充值测试3-充钱线程-随机唤醒等待队列中的一个-付钱线程
充值测试3-离开充钱线程,并解锁
充值测试4-充钱线程-获取锁
充值测试4-充钱线程-充一块钱2
充值测试4-充钱线程-随机唤醒等待队列中的一个-付钱线程
充值测试4-离开充钱线程,并解锁
付钱测试1-付钱线程-获取锁
付钱测试1-付钱线程-支付两块钱
付钱测试1-离开-付钱线程,并解锁
付钱测试2-付钱线程-被唤醒后的金额0
付钱测试2-付钱线程-释放锁,阻塞进入等待前的金额0