题解 | 条件变量实现数字的交替输出

今天摸鱼逛博客园,看到一个并发题目,考察条件变量的使用:

题目:使用条件变量(AQS.Condition),实现两个线程交替输出从0到100,规定线程A先输出,线程B后输出,前者输出偶数,后者输出奇数

我的实现方法如下:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Solution {
    private final static ReentrantLock lock = new ReentrantLock();
    private static int value = 0;

    public static void main(String[] args) {

        Condition l0 = lock.newCondition();		// 等待偶数的条件
        Condition l1 = lock.newCondition();		// 等待奇数的条件

        System.out.println("Tread A first print!");

        Thread threadA = new Thread(() -> {
            while (true) {
                if (value >= 100) {
                    break;
                }
                try {
                    lock.lock();
                    while(value % 2 != 0) {		// while防止虚假唤醒
                        l0.await();
                    }
                    System.out.println("Thread A start to print —— " + value++);
                    l1.signalAll();		// 也可以signal
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        });

        Thread threadB = new Thread(() -> {
            while (true) {
                if (value >= 100) {
                    break;
                }
                try {
                    lock.lock();
                    while(value % 2 == 0) {
                        l1.await();
                    }
                    System.out.println("Thread B start to print —— " + value++);
                    l0.signalAll();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    lock.unlock();
                }
            }
        });

        threadA.start();
        threadB.start();
    }
}

之前虽然把AQSReentrantLock的源码都看了好几遍,但是真正自己动手写多线程代码,还是有些生疏-_-||

值得注意的有三点:

  • 使用条件变量之前,必须先获取锁。如果是ReentrantLock创建出来的条件变量,必须将条件变量的awaitsignal方法包裹在lockunlock中使用。await方法会释放获取到的锁,当等待的条件满足时,会重新获取锁,这点不用担心
  • 如果要同步两个线程,需要两个条件变量,另外还需要外界的一个条件来帮助判断,光靠两个条件变量的awaitsignal会发生死锁。这里使用的条件是value是否为偶数。如果是生产者-消费者模型中,条件就应该是队列是否为空。这些条件都应该放在while循环而不是if条件中,这是为了防止虚假唤醒
  • 以后要多练练使用Idea调试多线程代码,不容易但也没有想象中那么难
posted @ 2021-12-03 20:32  酒冽  阅读(160)  评论(0编辑  收藏  举报