zoukankan      html  css  js  c++  java
  • 打印零与奇偶数

    一、题目描述:https://leetcode-cn.com/problems/print-zero-even-odd

    相同的一个 ZeroEvenOdd 类实例将会传递给三个不同的线程:

    线程 A 将调用 zero(),它只输出 0 。
    线程 B 将调用 even(),它只输出偶数。
    线程 C 将调用 odd(),它只输出奇数。
    每个线程都有一个 printNumber 方法来输出一个整数。
    请修改给出的代码以输出整数序列 010203040506... ,
    其中序列的长度必须为 2n。

    输入:n = 2
    输出:"0102"
    说明:三条线程异步执行,其中一个调用 zero(),另一个线程调用 even(),
    最后一个线程调用odd()。正确的输出为 "0102"。

    题解:3个线程,打印0的分别与奇偶线程互斥,奇偶线程互斥,多种解法。

    解法一:不使用锁,使用两个全局标记线程输出状态,当不满足线程输出时让出时间片。
    import java.util.function.IntConsumer;
    
    /**
     打印零与奇偶数
    
     相同的一个 ZeroEvenOdd 类实例将会传递给三个不同的线程:
    
     线程 A 将调用 zero(),它只输出 0 。
     线程 B 将调用 even(),它只输出偶数。
     线程 C 将调用 odd(),它只输出奇数。
     每个线程都有一个 printNumber 方法来输出一个整数。
     请修改给出的代码以输出整数序列 010203040506... ,
     其中序列的长度必须为 2n。
    
     输入:n = 2
     输出:"0102"
     说明:三条线程异步执行,其中一个调用 zero(),另一个线程调用 even(),
     最后一个线程调用odd()。正确的输出为 "0102"。
    
     https://leetcode-cn.com/problems/print-zero-even-odd
    
     * @author jy.cui
     * @version 1.0
     * @date 2020/10/15 16:27
     */
    class ZeroEvenOdd {
        private int n;
        private volatile boolean flag1 = true;
        private volatile boolean flag2 = false;
    
        public ZeroEvenOdd(int n) {
            this.n = n;
        }
    
        // printNumber.accept(x) outputs "x", where x is an integer.
        public void zero(IntConsumer printNumber) throws InterruptedException {
            for(int i = 1; i <= n; i++){
                while (!flag1){
                    Thread.yield();
                }
                printNumber.accept(0);
                flag1 = false;
            }
        }
    
        public void even(IntConsumer printNumber) throws InterruptedException {
            for(int i = 1; i <= n; i++){
                if((i & 1) == 0){
                    while (!flag2 || flag1){
                        Thread.yield();
                    }
                    printNumber.accept(i);
                    flag2 = false;
                    flag1 = true;
                }
            }
        }
    
        public void odd(IntConsumer printNumber) throws InterruptedException {
            for(int i = 1; i <= n; i++){
                if((i & 1) == 1){
                    while (flag2 || flag1){
                        Thread.yield();
                    }
                    printNumber.accept(i);
                    flag2 = true;
                    flag1 = true;
                }
            }
        }
    }

     解法二:信号量Semaphore,思路,三个信号量,分别阻塞,等待其他线程的唤醒,奇偶线程输出完毕唤醒zero线程,zero根据输出的次数,判断唤醒奇偶线程。

     Semaphore用法:

      void acquire():从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。

      void release():释放一个许可,将其返回给信号量。

      int availablePermits():返回此信号量中当前可用的许可数。

      boolean hasQueuedThreads():查询是否有线程正在等待获取。

    class ZeroEvenOdd {
        private int n;
        private Semaphore zero = new Semaphore(0);
        private Semaphore odd = new Semaphore(0);
        private Semaphore even = new Semaphore(0);
    
        public ZeroEvenOdd(int n) {
            this.n = n;
        }
    
        // printNumber.accept(x) outputs "x", where x is an integer.
        public void zero(IntConsumer printNumber) throws InterruptedException {
            for(int i = 1; i <= n; i++){
                if (i != 1){
                    zero.acquire();
                }
                printNumber.accept(0);
                if((i & 1) == 0){
                    even.release();
                }else {
                    odd.release();
                }
            }
        }
    
        public void even(IntConsumer printNumber) throws InterruptedException {
            for(int i = 1; i <= n; i++){
                if((i & 1) == 0){
                    even.acquire();
                    printNumber.accept(i);
                    zero.release();
                }
            }
        }
    
        public void odd(IntConsumer printNumber) throws InterruptedException {
            for(int i = 1; i <= n; i++){
                if((i & 1) == 1){
                    odd.acquire();
                    printNumber.accept(i);
                    zero.release();
                }
            }
        }
    }

    测试线程:

    public static void main(String[] args) throws InterruptedException {
            ZeroEvenOdd foo = new ZeroEvenOdd(5);
    
            new Thread(()->{
                try {
                    foo.zero(new A());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
            new Thread(()->{
                try {
                    foo.odd(new A());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
            Thread threadC = new Thread(() -> {
                try {
                    foo.even(new A());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            threadC.start();
            threadC.join();
        }
        static class A implements IntConsumer {
    
            @Override
            public void accept(int value) {
                System.out.println(value);
            }
        }
  • 相关阅读:
    UVA 254 Towers of Hanoi
    UVA 701 The Archeologists' Dilemma
    UVA 185 Roman Numerals
    UVA 10994 Simple Addition
    UVA 10570 Meeting with Aliens
    UVA 306 Cipher
    UVA 10160 Servicing Stations
    UVA 317 Hexagon
    UVA 10123 No Tipping
    UVA 696 How Many Knights
  • 原文地址:https://www.cnblogs.com/handsomecui/p/13847682.html
Copyright © 2011-2022 走看看