爱奇艺笔试题 输出01020304... ...

简介

三个线程一个线程输出0, 一个线程输出奇数, 还有一个线程输出偶数, 下面的代码感觉逻辑挺乱的.

code

import java.util.Scanner;
import java.util.concurrent.Semaphore;
import java.util.function.IntConsumer;

public class Main {
    public static void main(String[] args) {
        final Scanner reader = new Scanner(System.in);
        int n = reader.nextInt();

        ZeroEvenOdd zeroEvenOdd = new ZeroEvenOdd(n);
        new Thread(() -> {
            try {
                zeroEvenOdd.printZero(System.out::print);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(() -> {
            try {
                zeroEvenOdd.printEven(System.out::print);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(() -> {
            try {
                zeroEvenOdd.printOdd(System.out::print);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

class ZeroEvenOdd {
    private int n;

    volatile int t;
    volatile boolean b;
    volatile boolean c;
    public ZeroEvenOdd(int n) {
        this.n = n;
        t = n;
        b = false;
        c = false;
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public  void  printZero(IntConsumer printNumber) throws InterruptedException {
        while(n > 0) {
            synchronized (this) {
                if(b == false) {
                    if(t!=n && t!=(n+1)) // 为什么要这么写呢, 首先比如输入n=5那么, 输出奇数他会首先输出1个0, 所以屏蔽, 然后奇数线程会获得执行然后输出1,然后他又获得执行权输出0
                        System.out.print(0);
                    b = true;
                }
            }

        }
    }

    public  void printEven(IntConsumer printNumber) throws InterruptedException {
        while(n > 0) {
            synchronized (this){
                if(b == true) {
                        if(n %2 ==0) {
                            System.out.print(t-n);
                            n--;
                            b = false;
                        }
                    }
            }
        }
    }

    public  void printOdd(IntConsumer printNumber) throws InterruptedException {
        while(n > 0) {
                synchronized (this) {
                    if(b == true) {
                        if (n % 2 != 0) {
                            System.out.print(t - n); // 这里会输出第一个0
                            n--;
                            b = false;
                        }
                    }
                }
        }


    }


}

TIPS

逻辑上应该使用信号量, 因为信号量的使用场景就是这样子的. 顺序对于资源的把控

class AlternatePrinting {


    public static void main(String[] args) throws InterruptedException {

        Semaphore semaphoreOld = new Semaphore(1);
        Semaphore semaphoreEven = new Semaphore(1);

        semaphoreOld.acquire();//让奇数先启动,所以先减掉偶数的信号量 等奇数线程来释放

        SemaphorePrintEven semaphorePrintEven = new SemaphorePrintEven(semaphoreOld, semaphoreEven);
        Thread t1 = new Thread(semaphorePrintEven);
        t1.start();

        SemaphorePrintOdd semaphorePrintOdd = new SemaphorePrintOdd(semaphoreOld, semaphoreEven);
        Thread t2 = new Thread(semaphorePrintOdd);
        t2.start();

    }

    /**
     * 使用信号量实现
     */
    static class SemaphorePrintOdd implements Runnable {

        int i = 0;
        private Semaphore semaphoreOdd;
        private Semaphore semaphoreEven;


        public SemaphorePrintOdd(Semaphore semaphoreOdd, Semaphore semaphoreEven) {
            this.semaphoreOdd = semaphoreOdd;
            this.semaphoreEven = semaphoreEven;
        }

        @Override
        public void run() {
            try {
                semaphoreOdd.acquire();//获取信号量
                while (true) {
                    i++;
                    if (i % 2 == 0) {
                        System.out.println("偶数线程:" + i);
                        semaphoreEven.release();
                        //再次申请获取偶数信号量,因为之前已经获取过,如果没有奇数线程去释放,那么就会一直阻塞在这,等待奇数线程释放
                        Thread.sleep(300);
                        semaphoreOdd.acquire();
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class SemaphorePrintEven implements Runnable {

        int i = 0;
        private Semaphore semaphoreOdd;
        private Semaphore semaphoreEven;


        public SemaphorePrintEven(Semaphore semaphoreOdd, Semaphore semaphoreEven) {
            this.semaphoreOdd = semaphoreOdd;
            this.semaphoreEven = semaphoreEven;
        }

        @Override
        public void run() {

            try {
                semaphoreEven.acquire();
                while (true) {
                    i++;
                    if (i % 2 == 1) {
                        System.out.println("奇数线程:" + i);
                        semaphoreOdd.release();
                        semaphoreEven.acquire();//再次申请获取奇数信号量,需要等偶数线程执行完然后释放该信号量,不然阻塞
                    }
                }

            } catch (Exception ex) {}


        }
    }
}

Hope is a good thing,maybe the best of things,and no good thing ever dies.----------- Andy Dufresne
原文地址:https://www.cnblogs.com/eat-too-much/p/15173803.html