如果讓你用三個線程循環(huán)打印ABC,你有幾種寫法?

題目描述:

三個線程分別打印A,B,C,要求這三個線程一起運(yùn)行,打印n次,輸出形如“ABCABCABC....”的字符串。
在看之前不妨先敲代碼試試,看似很簡單的問題可能代碼寫起來沒那么順利。

使用Semaphore:

public class PrintABC {
    private int times;
    private Semaphore semaphoreA =new Semaphore(1);
    private Semaphore semaphoreB =new Semaphore(0);
    private Semaphore semaphoreC =new Semaphore(0);

    public PrintABC(int times) {
        this.times=times;
    }

    
    public static void main(String[] args) {
        PrintABC PrintABC =new PrintABC(10);
        new Thread(PrintABC::printA).start();
        new Thread(PrintABC::printB).start();
        new Thread(PrintABC::printC).start();
        
        
    }
    public void printA() {
        print("A",semaphoreA,semaphoreB);
    }
    public void printB() {
        print("B",semaphoreB,semaphoreC);
    }
    public void printC() {
        print("C",semaphoreC,semaphoreA);
    }
    
    
        public void print(String name,Semaphore current,Semaphore next) {
            for(int i=0;i<times;i++) {
                try {
                    current.acquire();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(name);
                next.release();
            }
            
        }
}

邏輯描述:

注意哦,semaphoreB和semaphoreC的值都為0,而semaphoreA的值為1。
也就是說semaphoreB.acquire();前沒有使用過semaphoreB.release()的話,調(diào)用的這個線程是會被阻塞的。那么這個時候,只有我們的線程A(假設(shè)調(diào)用printA的線程為線程A)能順利運(yùn)行了(因?yàn)橹挥芯€程A的emaphoreA為1)
線程A啟動,調(diào)用semaphoreA.acquire(),繼續(xù)運(yùn)行,打印A,調(diào)用semaphoreB.release(),此時線程B能動了……
如果A又獲得時間片,進(jìn)入了下一個for循環(huán)了呢?調(diào)用了semaphoreA.acquire();此時也會是阻塞狀態(tài),因?yàn)樯弦淮窝h(huán)acquire()的還沒有被release()掉。
C也是一樣的道理去分析,說多了更容易亂,建議大家在print方法上打個斷點(diǎn)調(diào)試一下就能輕松理解。

使用Lock

public class PrintABC2 {
    private int times;
    private int state;
    private Lock lock = new ReentrantLock();

    public PrintABC2(int times) {
        this.times = times;
    }

    public void printA() {
        print("A", 0);
    }

    public void printB() {
        print("B", 1);
    }

    public void printC() {
        print("C", 2);
    }

    public void print(String name, int stateNow) {
        for (int i = 0; i < times;) {
            lock.lock();
            if (stateNow == state % 3) {
                state++;
                i++;
                System.out.println(name);
            }
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        PrintABC2 printABC2 = new PrintABC2(10);
        new Thread(printABC2::printA).start();
        new Thread(printABC2::printB).start();
        new Thread(printABC2::printC).start();

    }

}

邏輯描述:

在這個代碼中,三個線程會不斷的獲取lock,判斷stateNow == state % 3,而只有A線程進(jìn)入if內(nèi)的代碼段后,B線程才有機(jī)會執(zhí)行,否則只是獲取鎖,判斷為false,把鎖讓出來而已,沒有做實(shí)際的操作。C也是一樣

使用Condition

public class LockCoditionTest {
    final Business business = new Business();

    public static void main(String[] args) {
        new LockCoditionTest().init();
    }

    private void init() {

        new Thread(new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i <= 10; i++) {
                    business.sub2("B");
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 10; i++) {
                    business.sub3("C");
                }
            }
        }).start();

        for (int i = 0; i <= 10; i++) {
            business.main("A");
        }
    }

    class Business {
        private int flag = 1;
        Lock lock = new ReentrantLock();
        Condition condition1 = lock.newCondition();
        Condition condition2 = lock.newCondition();
        Condition condition3 = lock.newCondition();

        public void sub2(String s) {
            lock.lock();
            try {
                if (flag != 2) {
                    condition2.await();
                }

                System.out.println("B線程輸出" + s);

                flag = 3;
                condition3.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        public void sub3(String s) {
            lock.lock();
            try {
                if (flag != 3) {
                    condition3.await();
                }
                System.out.println("C線程輸出" + s);
                flag = 1;
                condition1.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        public void main(String s) {
            lock.lock();
            try {
                if (flag != 1) {
                    condition1.await();
                }
                System.out.println("main線程輸出" + s);
                flag = 2;
                condition2.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}

邏輯描述:

每個線程都調(diào)用了Business類里的方法,別以為我的main()沒有創(chuàng)建線程哦,他可是在主線程下運(yùn)行的,這次我們通過了三個condition和一個flag來實(shí)現(xiàn)線程間的通信。
首先flag為1,如果此時B或者C線程拿到了,就會進(jìn)入if判斷,把自己給await啦,然后咱們的A線程拿到,輸出A,把flag改成2,再把B線程喚醒,這個時候flag已經(jīng)是 2啦,b線程if判斷為false,就不await自個了,輸出B,在把flag改成3,把線程C喚醒。

這個較于上面的lock來說,用了condition來更細(xì)粒度的操作線程,使得沒輪到他們工作的時候就進(jìn)入阻塞狀態(tài),解決了上面lock方法中幾個線程間不必要的上下文切換(沒輪到你就給我乖乖休息)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 線程 操作系統(tǒng)線程理論 線程概念的引入背景 進(jìn)程 之前我們已經(jīng)了解了操作系統(tǒng)中進(jìn)程的概念,程序并不能單獨(dú)運(yùn)行,只有...
    go以恒閱讀 1,796評論 0 6
  • 【threading模塊詳解】 模塊基本方法 該模塊定了的方法如下:threading.active_count(...
    奕劍聽雨閱讀 1,153評論 0 0
  • ReentrantLock 介紹 一個可重入的互斥鎖,它具有與使用{synchronized}方法和語句訪問的隱式...
    tomas家的小撥浪鼓閱讀 4,260評論 1 4
  • 關(guān)于Python多線程的概述 由于GIL的存在,Python的多線程在CPU密集型任務(wù)并沒有多大的優(yōu)勢,任何Pyt...
    千鳥月讀閱讀 597評論 0 0
  • 一、Python簡介和環(huán)境搭建以及pip的安裝 4課時實(shí)驗(yàn)課主要內(nèi)容 【Python簡介】: Python 是一個...
    _小老虎_閱讀 6,338評論 0 10

友情鏈接更多精彩內(nèi)容