线程之间等待通知的一种机制。类似于LockSupport,可以使一个线程等待,然后去唤醒另外一个线程。
Condition是一个接口,获取它的方式可以通过lock.newCondition()获取。
public static void main(String[] args){
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
}
- 线程间的通信
- 每个锁上可以存在多个condition,这意味着锁的状态条件可以有多个
- 支持公平和非公平的队列操作
- 支持可中断的条件等待
- 支持可定时的等待
源码分析
await()
使当前线程等待或中断,直到有其他线程唤醒。线程调用await方法会处于等待状态,此时调用Thread.interrupt()方法会报IllegalMonitorStateException异常awaitUninterruptibly()
线程调用awaitUninterruptibly方法会处于等待状态,此时调用Thread.interrupt()方法不会报错。awaitNanos(long nanosTimeout)
线程处于等待状态,设置等待时间为nanosTimeout。
返回值:nanosTimeout减去线程等待的时间,大于0表示还有时间,小于或等于0表示没有时间啦。await(long time,TimeUnit unit)
等待time时间或者中断awiatUntil(Date deadline)
等待直到deadlinesignal()
唤醒一个等待的线程signalAll()
唤醒所有的等待线程
使用场景
Condition作为等待通知的机制,在JUC包中的很多类中都使用到,比如ArrayBlockingQueue阻塞队列内部就维护了两个Condition(notEmpty,notFull)来实现生产者消费者模式,notEmpty作为取(take),notFull作为存(push)
生产者消费者模式
ArrayBlockingQueue的实现
public static void main(String[] args) throws InterruptedException {
int queueCapacity = 10;
PriorityQueue<Integer> queue = new PriorityQueue(queueCapacity);
ReentrantLock lock = new ReentrantLock();
Condition notEmpty = lock.newCondition();
Condition notFull = lock.newCondition();
Thread consumerThread = new Thread(() -> {
boolean flag = true;
while(flag) {
lock.lock();
try {
while (queue.size() == 0) {
System.out.println("队列为空,等待生产数据。。。");
notEmpty.await();
}
queue.poll();
notFull.signal();
System.out.println("消费者从队列中消费一条数据,队列剩余数据: " +queue.size());
} catch (Exception e) {
flag = false;
} finally {
lock.unlock();
}
}
}, "consumerThread");
Thread producerThread = new Thread(() -> {
boolean flag = true;
while(flag){
lock.lock();
try {
while (queue.size() == queueCapacity) {
System.out.println("队列已满,等待消费。。。");
notFull.await();
}
queue.offer(1);
notEmpty.signal();
System.out.println("生产者向队列中插入一条数据,队列剩余空间:" + (queueCapacity - queue.size()));
} catch (Exception e) {
flag = false;
} finally {
lock.unlock();
}
}
}, "producerThread");
producerThread.start();
consumerThread.start();
Thread.sleep(0);
producerThread.interrupt();
consumerThread.interrupt();
}
循环打印
public static void main(String[] args){
Lock lock = new ReentrantLock();
Condition conditionT1 = lock.newCondition();
Condition conditionT2 = lock.newCondition();
char[] num = "1234567890".toCharArray();
char[] word = "ABCDEFGHIJ".toCharArray();
new Thread(() -> {
lock.lock();
try{
for (char c : num) {
System.out.print(c);
conditionT2.signal();
conditionT1.await();
}
conditionT2.signal();
}catch(Exception e){
}finally {
lock.unlock();
}
},"t1").start();
new Thread(() -> {
lock.lock();
try{
for (char c : word) {
System.out.print(c);
conditionT1.signal();
conditionT2.await();
}
conditionT1.signal();
}catch(Exception e){
}finally {
lock.unlock();
}
},"t2").start();
}