一、Condition接口
Condition可以通俗的理解为条件队列;
当一个线程在调用await方法以后,直到线程等待的某个条件为真的时候,待会被唤醒;
这种线程为简单的等待/通知模式;
Condition必须和Lock配合使用,因为共享状态变量的访问发生在多线程环境下;
final Lock lock = new ReentrantLock();
final Condition ThreeConditon = lock.newCondition();
final Condition SixConditon = lock.newCondition();
二、Condition接口中的方法
//当前线程在接到信号或者被中断之前一直处在等待状态
void await() throws InterruptedException;
//当前线程在接到信号之前一直处于等待状态
void awaitUninterruptibly();
//当前线程在接到信号、中断或者在制定的时间之前一直在等待状态。
//返回值long表示的剩余时间。
//如果在nanosTimeout之前被唤醒,那么返回值=nanosTimeout-消耗时间
//如果返回值小于0,可以认为它超时了
long awaitNanos(long nanosTimeout) throws InterruptedException;
//当前线程在接到信号、中断或者在制定的时间之前一直在等待状态。
boolean await(long time, TimeUnit unit) throws InterruptedException;
//当前线程在接到信号、中断或者在制定的时间之前一直在等待状态。
//如果没有到指定时间,则返回true,否则返回false
boolean awaitUntil(Date deadline) throws InterruptedException;
//唤醒等待线程。
//该线程的从等待方法返回前必须获得与Condition相关的lock
void signal();
//换新所有的等待线程
void signalAll();
三、总结
调用await方法后,将当前线程加入到Condition等待队列中;
当前队列释放lock,否则别的线程无法得到锁,而造成死锁;
自旋 while 挂起,不断的检查节点是否同步在队列中;
如果是,则获取lock;
否则挂起;
当线程被signal方法唤醒;
被唤醒的线程将从await方法中的while循环中退出来;
然后调用acquireQueue方法中竞争同步状态;
四、栗子:两个计数线程,同时启动,线程A执行123,线程B执行456,然后线程A执行789,结束。
public class ConcurrentTest {
static class NumberWrapper{
public int value = 1;
}
public static void main(String... args) {
//初始化可重入锁
//await和signal的Lock是同一个Lock
final Lock lock = new ReentrantLock();
//当屏幕上输出3时,lock.newCondition()
final Condition reachThreeConditon = lock.newCondition();
//当屏幕上输出6时,lock.newCondition()
final Condition reachSixConditon = lock.newCondition();
//NumberWrapper只是为了封装一个数字,一边可以数字对象共享,并可以设置为final
//注意这里不要用Integer,因为Integer是不可比变对象
final NumberWrapper num = new NumberWrapper();
Thread threadA = new Thread(() -> {
//需要先获得锁
lock.lock();
System.out.println("ThreadA获得Lock");
try{
System.out.println("ThreadA start write");
while (num.value <= 3) {
System.out.println(num.value);
num.value++;
}
//输出到3的时候告诉B线程可以开始了
reachThreeConditon.signal();
} finally {
lock.unlock();
System.out.println("ThreadA 释放锁");
}
lock.lock();
System.out.println("ThreadA获得Lock");
try{
//等待6输出的条件
reachSixConditon.await();
System.out.println("ThreadA start write");
while (num.value <= 9) {
System.out.println(num.value);
num.value++;
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println("ThreadA 释放锁");
}
});
Thread threadB = new Thread(() -> {
try {
lock.lock();
System.out.println("ThreadB获得lock");
Thread.sleep(5000);
while (num.value <=3) {
//等待A线程输出3完毕的信号
reachThreeConditon.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("ThreadB释放lock");
lock.unlock();
}
try {
lock.lock();
System.out.println("ThreadB获得lock");
System.out.println("ThreadB start write");
while (num.value <= 6) {
System.out.println(num.value);
num.value++;
}
reachSixConditon.signal();
} finally {
System.out.println("ThreadB释放lock");
lock.unlock();
}
});
threadB.start();
threadA.start();
}
}
运行结果:
ThreadB获得lock
ThreadA获得Lock
ThreadA start write
1
2
3
ThreadA 释放锁
ThreadA获得Lock
ThreadB释放lock
ThreadB获得lock
ThreadB start write
4
5
6
ThreadB释放lock
ThreadA start write
7
8
9
ThreadA 释放锁