🌕 1116. 打印零与奇偶数

吞佛童子2022年6月20日
  • algorithm
  • thread
大约 2 分钟

🌕 1116. 打印零与奇偶数

难度: 🌕

问题描述

img.png


解法 1 - ReentrantLock + Condition + flag

class ZeroEvenOdd {
    // 思路:
    // ReentrantLock + Condition + flag
    private int n;
    ReentrantLock lock;
    Condition cA;
    Condition cB;
    Condition cC;
    private boolean flagA;
    private boolean flagB;
    private boolean flagC;
    private boolean flag; // 从 A 开始,派发给 B 还是 C
    
    public ZeroEvenOdd(int n) {
        this.n = n;
        this.lock = new ReentrantLock();
        this.cA = lock.newCondition();
        this.cB = lock.newCondition();
        this.cC = lock.newCondition();
        this.flagA = true;
        this.flagB = false;
        this.flagC = false;
        this.flag = false;
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void zero(IntConsumer printNumber) throws InterruptedException {
        for(int i = 0; i < n; i ++) {
            lock.lock();
            try {
                while(!flagA) {
                    cA.await();
                }
                printNumber.accept(0);
                flagA = false;
                this.flag = !this.flag;
                if(this.flag) {
                    flagB = true;
                    cB.signal();
                } else {
                    flagC = true;
                    cC.signal();
                }
            } finally {
                lock.unlock();
            }
        }
    }

    public void odd(IntConsumer printNumber) throws InterruptedException {
        for(int i = 0; i < (n + 1) / 2; i ++) {
            lock.lock();
            try {
                while(!flagB) {
                    cB.await();
                }
                int cur = 2 * i + 1;
                printNumber.accept(cur);
                flagB = false;
                flagA = true;
                cA.signal();
            } finally {
                lock.unlock();
            }
        }
    }
    
    public void even(IntConsumer printNumber) throws InterruptedException {
        for(int i = 0; i < n / 2; i ++) {
            lock.lock();
            try {
                while(!flagC) {
                    cC.await();
                }
                int cur = 2 * (i + 1);
                printNumber.accept(cur);
                flagC = false;
                flagA = true;
                cA.signal();
            } finally {
                lock.unlock();
            }
        }        

    }

}

解法 2 - CountDownLatch

class ZeroEvenOdd {
    // 思路:
    // CountDownLatch
    private int n;
    CountDownLatch c0;
    CountDownLatch c1;
    CountDownLatch c2;
    private int flag;
    
    public ZeroEvenOdd(int n) {
        this.n = n;
        this.c0 = new CountDownLatch(0); // 一开始就启动 0
        this.c1 = new CountDownLatch(1);
        this.c2 = new CountDownLatch(1);
        this.flag = 1;
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void zero(IntConsumer printNumber) throws InterruptedException {
        for(int i = 0; i < n; i ++) {
            c0.await();
            printNumber.accept(0);
            // System.out.println("zero printed");
            c0 = new CountDownLatch(1); // 重新计时
            if(flag == 1) {
                flag = 2;
                c1.countDown();
            } else {
                flag = 1;
                c2.countDown();
            }
        }
    }
    public void odd(IntConsumer printNumber) throws InterruptedException {
        for(int i = 0; i < (n + 1) / 2; i ++) {
            c1.await();
            printNumber.accept(2 * i + 1);
            // System.out.println("odd printed");
            c1 = new CountDownLatch(1);
            c0.countDown();
        }
    }

    public void even(IntConsumer printNumber) throws InterruptedException {
        for(int i = 0; i < n / 2; i ++) {
            c2.await();
            printNumber.accept(2 * (i + 1));
            // System.out.println("even printed");
            c2 = new CountDownLatch(1);
            c0.countDown();
        }
    }
}

解法 3 - Semaphore

class ZeroEvenOdd {
    // 思路:
    // Semaphore
    private int n;
    Semaphore s0;
    Semaphore s1;
    Semaphore s2;
    private int flag;
    
    public ZeroEvenOdd(int n) {
        this.n = n;
        this.s0 = new Semaphore(1);
        this.s1 = new Semaphore(0);
        this.s2 = new Semaphore(0);
        this.flag = 1;
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void zero(IntConsumer printNumber) throws InterruptedException {
        for(int i = 0; i < n; i ++) {
            s0.acquire();
            printNumber.accept(0);
            // System.out.println("zero printed");
            if(flag == 1) {
                flag = 2;
                s1.release(); // 给 s1 发放一个许可
            } else {
                flag = 1;
                s2.release();
            }
        }
    }
    public void odd(IntConsumer printNumber) throws InterruptedException {
        for(int i = 0; i < (n + 1) / 2; i ++) {
            s1.acquire();
            printNumber.accept(2 * i + 1);
            // System.out.println("odd printed");
            s0.release();
        }
    }

    public void even(IntConsumer printNumber) throws InterruptedException {
        for(int i = 0; i < n / 2; i ++) {
            s2.acquire();
            printNumber.accept(2 * (i + 1));
            // System.out.println("even printed");
            s0.release();
        }
    }
}
上次编辑于: 2022/6/20 下午8:24:47
贡献者: liuxianzhishou