JUC練習代碼-力扣多線程1116題目:打印零與奇偶數,解題詳解

題目描述

假設有這麼一個類:

class ZeroEvenOdd {
public ZeroEvenOdd(int n) { … } // 構造函數
public void zero(printNumber) { … } // 僅打印出 0
public void even(printNumber) { … } // 僅打印出 偶數
public void odd(printNumber) { … } // 僅打印出 奇數
}
相同的一個 ZeroEvenOdd 類實例將會傳遞給三個不同的線程:

線程 A 將調用 zero(),它只輸出 0 。
線程 B 將調用 even(),它只輸出偶數。
線程 C 將調用 odd(),它只輸出奇數。
每個線程都有一個 printNumber 方法來輸出一個整數。請修改給出的代碼以輸出整數序列 010203040506… ,其中序列的長度必須爲 2n。

示例 1:

輸入:n = 2
輸出:“0102”
說明:三條線程異步執行,其中一個調用 zero(),另一個線程調用 even(),最後一個線程調用odd()。正確的輸出爲 “0102”。
示例 2:

輸入:n = 5
輸出:“0102030405”

解題過程

這道題花的時間長了一些。首先最先想到的是嘗試用Condtion來解決,但是實際在處理過程中,發現必須要將特殊情況的場景全部判斷清楚,包括每個線程起始,和退出。這樣思路下寫出來的代碼,容易導致某些場景下最後線程阻塞,提交超時。

另外多線程環境,本地測試情況經常會覺得自己答案正確,實際確不是,這個時候不要懷疑係統驗證有問題,需要細心檢查自己的邏輯。

後面決定改變思路,第一點,每個線程只負責做自己的事情,比如第一個線程負責打印n個0,奇數線程負責打印n+1/2個奇數,偶數線程負責打印n/2個偶數,每個線程自己有個局部變量i進行循環打印。通過信號量控制每個線程按順序循環打印即可。

class ZeroEvenOdd {
    private int n;

    public ZeroEvenOdd(int n) {
        this.n = n;
    }

    Semaphore zeros=new Semaphore(1);
    Semaphore odds=new Semaphore(0);
    Semaphore evens=new Semaphore(0);

    //線程 A 將調用 zero(),它只輸出 0 。
    //線程 B 將調用 even(),它只輸出偶數。
    //線程 C 將調用 odd(),它只輸出奇數。
    // printNumber.accept(x) outputs "x", where x is an integer.
    public void zero(IntConsumer printNumber) throws InterruptedException {
        int i=0;
        while(i<n){
            zeros.acquire();
            printNumber.accept(0);

            if((i+2)%2==0){
                odds.release();
            }else{
                evens.release();
            }
            i++;
        }
    }
    //打印偶數
    public void even(IntConsumer printNumber) throws InterruptedException {
        int i=0;
        while(i<n/2){
            evens.acquire();
            printNumber.accept(i*2+2);
            i++;
            zeros.release();
        }
    }
    //打印奇數
    public void odd(IntConsumer printNumber) throws InterruptedException {
        int i=0;
        while(i<(n+1)/2){
            odds.acquire();
            printNumber.accept(i*2+1);
            i++;
            zeros.release();
        }
    }

    public static void main(String[] args) {
        ZeroEvenOdd zeroEvenOdd = new ZeroEvenOdd(5);
        new Thread(()->{
            try {
                zeroEvenOdd.zero(value -> {
                    System.out.print(value);
                });
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(()->{
            try {
                zeroEvenOdd.even(value -> {
                    System.out.print(value);
                });
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(()->{
            try {
                zeroEvenOdd.odd(value -> {
                    System.out.print(value);
                });
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章