Java 初识Condition条件操作,用ReentrantLock实现线程轮流打印(JDk11)

64 阅读1分钟

下面是一段用synchronized同步关键字实现的线程轮流对count+1的代码

两个线程轮流打印

// 两个线程轮流给cont加1,直到count=10
    public static void synchronizedPrint(Object lock) {
        Runnable runnable = () -> {
            synchronized (lock) {
                while (count <= 10) {
                    System.out.println(Thread.currentThread().getName() + " count = " + count++);
                    try {
                        lock.notify();
                        lock.wait();
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
                //这里是保证当count==10的时候,处于wait的线程可以被释放掉
                lock.notify();
            }
        };
        new Thread(runnable).start();
        new Thread(runnable).start();
    }

这段代码如果让你用ReentrantLock来实现,你会怎么做?如果你只用lock()和unlock()方法,是不是很头疼?我们先看实现。

public static void lockPrint() {
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        Runnable runnable = () -> {
            lock.lock();
            try {
                while (count <= 10) {
                    System.out.println(Thread.currentThread().getName() + " count = " + count++);
                    condition.signal();
                    condition.await();
                }
                condition.signal();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        };
        new Thread(runnable).start();
        new Thread(runnable).start();
    }

我们可以看到,其实代码主流程没有变,只是引入了Condition去做原本objecet中wait()和notify()的操作。下面介绍一下Condition的方法

ConditionObject

ConditionObject 是ReentrantLock内部对Condition接口的实现

  • await():使当前线程等待,直到被通知或中断。调用此方法后,当前线程会被阻塞,并释放锁。
  • awaitUninterruptibly():使当前线程等待,直到被通知,但不响应中断。
  • awaitNanos(long nanosTimeout):使当前线程等待指定的时间,直到被通知、中断或超时。
  • awaitUntil(Date deadline):使当前线程等待,直到被通知、中断或到达指定的截止时间。
  • signal():唤醒一个等待的线程。如果有多个线程在等待,则随机选择一个线程唤醒。
  • signalAll():唤醒所有等待的线程。

可以看到,如果ReentrantLock只有lock()和unlock(),是很难做到线程间的通信的,引入了ConditionObject以后,我们就可以更加灵活的操作线程