Java多线程六脉神剑-关冲剑-Condition

226 阅读2分钟

前言

关冲剑:关冲剑拙滞古朴,Condition 常用于线程间的条件等待,以相对基础和传统的方式实现线程间的协调。

使用synchronized和Object的wait()和notify()可以实现等待/通知模型,然而使用这种方式,JVM会随机唤醒一个等待的线程。而使用Condition,可以将线程进行更精细的分组管理。通过创建多个Condition对象,可以将不同需求的线程等待在不同的Condition上。在唤醒时,可以精确地选择唤醒特定Condition上等待的线程,而不是像notify()那样随机唤醒或者notifyAll那样全部唤醒。

因而使用Condition的前提必须是获取到Lock锁,就像使用Object.wait()时必须需要先获取到Synchronized一样。

image.png

Condition方法详解

  • await():线程等待,直到被唤醒或中断,等待的过程中会释放Lock锁,类似于Object.wait()
  • await(long time, TimeUnit unit):线程等待指定的时间,或被唤醒或被中断,类似于Object.wait(long timeoutMillis)
  • awaitNanos(long nanosTimeout):线程等待指定纳秒的时间,或被唤醒或被中断,类似于Object.wait(long timeoutMillis, int nanos)
  • awaitUntil(Date deadline):线程等待直到指定的截止日期,或被唤醒,或被中断。
  • awaitUninterruptibly():线程等待直到被唤醒,即使在等待时被中断也不会返回。
  • signal():唤醒同Condition下一个等待的线程。类似于 Object.notify()
  • signalAll():唤醒同Condition下所有等待的线程。类似于 Object.notifyAll()
1ms【毫秒】 = 1000μs【微秒】    1μs【微秒】 = 1000ns【纳秒】

举个栗子🌰

今典的生产者消费者问题,消费者在消费之前必须要等待生产者生产,在业务中生产消费可能还会有一些前提,比如要某某数据拿到了才能生产,这里我们用两个Ready方法模拟生产条件是否满足。其次,如果消费者先拿到锁,然而生产者还没生产数据,消费者将会阻塞等待。

代码如下:

public class ConditionCase {

    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    private Object object = null;
    private boolean produced = false; //是否已经生产
    private boolean consumed = false; //是否已经消费

    public void producer() {
        lock.lock();
        try {
            // 假设生产条件未满足 或 还未进行消费,等待
            while (!isProductionReady() || consumed) {
                condition.await();
            }
            // 进行生产操作
            object = new Object();
            produced = true;
            System.out.println("生产完成,可以消费");
            // 通知消费者可以消费
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void consumer() {
        lock.lock();
        try {
            // 假设消费条件未满足,等待
            while (!isConsumptionReady() ||!produced) {
                condition.await();
            }
            // 进行消费操作
            object = null;
            consumed = true;
            System.out.println("消费完成");
            // 通知生产者可以生产
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    private boolean isProductionReady() {
        // 这里可以根据实际情况判断生产条件是否满足
        return true;
    }

    private boolean isConsumptionReady() {
        // 这里可以根据实际情况判断消费条件是否满足
        return true;
    }

    public static void main(String[] args) {
        ConditionCase conditionCase = new ConditionCase();

        new Thread(() -> conditionCase.consumer()).start();
        new Thread(() -> conditionCase.producer()).start();
    }
}

执行结果:

生产完成,可以消费
消费完成