线程之间等待通知的一种机制。类似于LockSupport,可以使一个线程等待,然后去唤醒另外一个线程。
Condition是一个接口,获取它的方式可以通过lock.newCondition()获取。

  1. public static void main(String[] args){
  2. ReentrantLock lock = new ReentrantLock();
  3. Condition condition = lock.newCondition();
  4. }
  • 线程间的通信
  • 每个锁上可以存在多个condition,这意味着锁的状态条件可以有多个
  • 支持公平和非公平的队列操作
  • 支持可中断的条件等待
  • 支持可定时的等待

    源码分析

    image.png

    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)

    等待直到deadline

    signal()

    唤醒一个等待的线程

    signalAll()

    唤醒所有的等待线程

使用场景

Condition作为等待通知的机制,在JUC包中的很多类中都使用到,比如ArrayBlockingQueue阻塞队列内部就维护了两个Condition(notEmpty,notFull)来实现生产者消费者模式,notEmpty作为取(take),notFull作为存(push)

生产者消费者模式

ArrayBlockingQueue的实现

  1. public static void main(String[] args) throws InterruptedException {
  2. int queueCapacity = 10;
  3. PriorityQueue<Integer> queue = new PriorityQueue(queueCapacity);
  4. ReentrantLock lock = new ReentrantLock();
  5. Condition notEmpty = lock.newCondition();
  6. Condition notFull = lock.newCondition();
  7. Thread consumerThread = new Thread(() -> {
  8. boolean flag = true;
  9. while(flag) {
  10. lock.lock();
  11. try {
  12. while (queue.size() == 0) {
  13. System.out.println("队列为空,等待生产数据。。。");
  14. notEmpty.await();
  15. }
  16. queue.poll();
  17. notFull.signal();
  18. System.out.println("消费者从队列中消费一条数据,队列剩余数据: " +queue.size());
  19. } catch (Exception e) {
  20. flag = false;
  21. } finally {
  22. lock.unlock();
  23. }
  24. }
  25. }, "consumerThread");
  26. Thread producerThread = new Thread(() -> {
  27. boolean flag = true;
  28. while(flag){
  29. lock.lock();
  30. try {
  31. while (queue.size() == queueCapacity) {
  32. System.out.println("队列已满,等待消费。。。");
  33. notFull.await();
  34. }
  35. queue.offer(1);
  36. notEmpty.signal();
  37. System.out.println("生产者向队列中插入一条数据,队列剩余空间:" + (queueCapacity - queue.size()));
  38. } catch (Exception e) {
  39. flag = false;
  40. } finally {
  41. lock.unlock();
  42. }
  43. }
  44. }, "producerThread");
  45. producerThread.start();
  46. consumerThread.start();
  47. Thread.sleep(0);
  48. producerThread.interrupt();
  49. consumerThread.interrupt();
  50. }

循环打印

  1. public static void main(String[] args){
  2. Lock lock = new ReentrantLock();
  3. Condition conditionT1 = lock.newCondition();
  4. Condition conditionT2 = lock.newCondition();
  5. char[] num = "1234567890".toCharArray();
  6. char[] word = "ABCDEFGHIJ".toCharArray();
  7. new Thread(() -> {
  8. lock.lock();
  9. try{
  10. for (char c : num) {
  11. System.out.print(c);
  12. conditionT2.signal();
  13. conditionT1.await();
  14. }
  15. conditionT2.signal();
  16. }catch(Exception e){
  17. }finally {
  18. lock.unlock();
  19. }
  20. },"t1").start();
  21. new Thread(() -> {
  22. lock.lock();
  23. try{
  24. for (char c : word) {
  25. System.out.print(c);
  26. conditionT1.signal();
  27. conditionT2.await();
  28. }
  29. conditionT1.signal();
  30. }catch(Exception e){
  31. }finally {
  32. lock.unlock();
  33. }
  34. },"t2").start();
  35. }