LeetCode 1116 Print Zero Even Odd (并发 多线程 CountDownLatch Lock Condition)

17 篇文章 0 订阅
4 篇文章 0 订阅

You have a function printNumber that can be called with an integer parameter and prints it to the console.

  • For example, calling printNumber(7) prints 7 to the console.

You are given an instance of the class ZeroEvenOdd that has three functions: zeroeven, and odd. The same instance of ZeroEvenOdd will be passed to three different threads:

  • Thread A: calls zero() that should only output 0's.
  • Thread B: calls even() that should only output even numbers.
  • Thread C: calls odd() that should only output odd numbers.

Modify the given class to output the series "010203040506..." where the length of the series must be 2n.

Implement the ZeroEvenOdd class:

  • ZeroEvenOdd(int n) Initializes the object with the number n that represents the numbers that should be printed.
  • void zero(printNumber) Calls printNumber to output one zero.
  • void even(printNumber) Calls printNumber to output one even number.
  • void odd(printNumber) Calls printNumber to output one odd number.

Example 1:

Input: n = 2
Output: "0102"
Explanation: There are three threads being fired asynchronously.
One of them calls zero(), the other calls even(), and the last one calls odd().
"0102" is the correct output.

Example 2:

Input: n = 5
Output: "0102030405"

Constraints:

  • 1 <= n <= 1000

题目链接:https://leetcode.com/problems/print-zero-even-odd/

题目大意:初始化一个ZeroEvenOdd实例,三个线程分别持有并分别调用其zero,odd,even方法,要求zero只输出0,odd只输出奇数,even只输出偶数,最终输出"010203040506..."这样的序列

题目分析:实现方法比较多,本文采用CountDownLatch + Lock + Condition的方式,CountDownLatch用于保证进入循环时0在先,奇数在前偶数在后,之后通过condition的await和signal交替操作,错误点看注释

8ms,时间击败70.7%

public class ZeroEvenOdd {
    ReentrantLock lock;
    Condition cZero, cEven, cOdd;
    // Used to ensure non-zero numbers start after zero
    CountDownLatch zeroForOdd, zeroForEven;
    int n;

    public ZeroEvenOdd(int n) {
        this.n = n;
        lock = new ReentrantLock();
        cZero = lock.newCondition();
        cEven = lock.newCondition();
        cOdd = lock.newCondition();

        zeroForOdd = new CountDownLatch(1);
        zeroForEven = new CountDownLatch(1);
    }

    public void zero(IntConsumer printNumber) throws InterruptedException {
        lock.lock();
        try {
            for (int i = 1; i <= n; i ++) {
                printNumber.accept(0);
                if (i % 2 == 1) {
                    cOdd.signal();
                } else {
                    cEven.signal();
                }
                if (i == 1) {
                    zeroForOdd.countDown();
                }
                // latch should be released to ensure even thread can end normally if n == 1
                if (n == 1 || i == 2) {
                    zeroForEven.countDown();
                }
                cZero.await();
            }
            // **these "signal"s are important**
            // when the last non-zero number accepted, corresponding thread will be in blocking state, which should be woken up to ensure it end normally.
            cOdd.signal();
            cEven.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void odd(IntConsumer printNumber) throws InterruptedException {
        try {
            zeroForOdd.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        lock.lock();
        try {
            for (int i = 1; i <= n; i += 2) {
                printNumber.accept(i);
                cZero.signal();
                cOdd.await();
            }
            cZero.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void even(IntConsumer printNumber) throws InterruptedException {
        try {
            zeroForEven.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        lock.lock();
        try {
            for (int i = 2; i <= n; i += 2) {
                printNumber.accept(i);
                cZero.signal();
                cEven.await();
            }
            // **this judgement is important**
            // if lack of this judgement, odd can be blocked forever when n == 1:
            // 1. [zero] get lock -> release two latches -> release lock -> blocked
            // 2. [even] get lock -> release lock -> signal zero -> exit
            // 3. [zero] get lock -> signal even and odd -> exit
            // 4. [odd] get lock -> release lock -> blocked
            if (n > 1) {
                cZero.signal();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值