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);
            }
        }
  • 相关阅读:
    网络编程
    并发编程-线程池
    并发编程-集合
    并发编程-AQS
    并发编程-CAS
    并发编程-volatile和synchronized的区别
    并发编程-synchronized
    并发编程-java内存模型
    JVM-分代垃圾回收器
    性能优化
  • 原文地址:https://www.cnblogs.com/handsomecui/p/13847682.html
Copyright © 2011-2022 走看看