鹿鼎記 · 韋小寶,麗春院、天地會、入皇宮等五個場景的惡搞版多執行緒鎖學習!

小傅哥發表於2020-11-23


作者:小傅哥
部落格:https://bugstack.cn
Github:https://github.com/fuzhengwei/CodeGuide/wiki

沉澱、分享、成長,讓自己和他人都能有所收穫!?

一、前言

學習路徑決定學習效果!

有時候很多看似複雜的知識,其實並沒有多複雜,只不過你找到的那份資料把知識講複雜了。為什麼這麼說呢??

學習知識可以想象成是一個從開頭接觸結尾把知識吸納的過程,在這個過程中會有一些知識路徑行走經歷。那麼不同的資料就是帶著你在走這條知識路徑,只不過有些資料容易繞路或者難走(路也跟車有關係,有些路適合客車?、有些路適合轎車?)。而當你找到一份非常不錯並且適合自己的資料時,就會有一種酣暢、通透的感覺,不會感覺學起來多複雜,同時不僅學會了也理解了核心本質。這份資料在你手裡就是,車速有點快、繫好安全帶

所以,能找到最好的資料也是學習過程中,非常重要的一個點。你的檢索能力越強,你就會越容易找到最合適你的資料。

接下來小傅哥就帶你進入鹿鼎記 · 韋小寶多執行緒和鎖的故事路線,感受逗B的學習路線!

二、韋小寶與多執行緒

圖 12-1 鹿鼎記·韋小寶,多執行緒惡搞例子

小傅哥選取了五個鹿鼎記場景,融入進去不同的多執行緒使用,包括:麗春院,說書天地會,香主招收雜役,入宮皇上、建寧,比武七個老婆,隱居,這樣五個場景。相信你看完後,一定會記住每個執行緒的使用!

1. 麗春院,說書

圖 12-2 麗春院,說書

public class SynchronizedTest {

    private static ExecutorService 麗春院 = Executors.newFixedThreadPool(10);

    private static volatile boolean 老鴇 = false;

    public static class 客官 implements Runnable {

        private String 姓名;

        public 客官(String 姓名) {
            this.姓名 = 姓名;
        }

        @Override
        public void run() {
            try {
                清倌(姓名);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public static synchronized void 清倌(String 姓名) throws InterruptedException {
        while (true){
            System.out.println("韋春花與" + 姓名 + "喝茶、吟詩、做對、聊風月!");
            if (老鴇){
                System.out.println("老鴇敲門:時間到啦!\r\n");
                老鴇 = false;
                break;
            }
            Thread.sleep(1000);
        }

    }

    private static List<String> list = Arrays.asList("鰲大人", "陳近南", "海大富");

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 3; i++) {
            麗春院.execute(new 客官(list.get(i)));
            Thread.sleep(3000);
            老鴇 = true;
        }
    }

}
  • 場景:韋小寶在麗春院打雜說書時,常有一些大佬(鰲大人陳近南海大富)前來與清倌吟詩、做對、聊風月。但由於大家都欣賞其中一個叫韋春花的清倌,所以需要排隊。
  • 知識:使用 synchronized 鎖,和 volatile 可見性,不斷的例項化客官加入執行緒池,等待與清倌聊天。還可以使用wait()、notify()來實現這一效果過程
  • 測試結果
韋春花與鰲大人喝茶、吟詩、做對、聊風月!
韋春花與鰲大人喝茶、吟詩、做對、聊風月!
韋春花與鰲大人喝茶、吟詩、做對、聊風月!
韋春花與鰲大人喝茶、吟詩、做對、聊風月!
老鴇敲門:時間到啦!

韋春花與陳近南喝茶、吟詩、做對、聊風月!
韋春花與陳近南喝茶、吟詩、做對、聊風月!
韋春花與陳近南喝茶、吟詩、做對、聊風月!
韋春花與陳近南喝茶、吟詩、做對、聊風月!
老鴇敲門:時間到啦!

韋春花與海大富喝茶、吟詩、做對、聊風月!
韋春花與海大富喝茶、吟詩、做對、聊風月!
韋春花與海大富喝茶、吟詩、做對、聊風月!
韋春花與海大富喝茶、吟詩、做對、聊風月!
老鴇敲門:時間到啦!

2. 天地會,香主

圖 12-3 天地會,香主

public class CountDownLatchTest {

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

        List<String> list = Arrays.asList("總舵主,陳近南", "蓮花堂香主,蔡德忠",
                "洪順堂香主,方大洪",
                "家後堂香主,馬超興",
                "參太堂香主,胡德帝",
                "巨集化堂香主,李式開",
                "青木堂香主,韋小寶",
                "赤火堂香主,古至中",
                "玄水堂香主,林永超",
                "黃土堂香主,姚必達");

        CountDownLatch latch = new CountDownLatch(10);
        ExecutorService exec = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            int idx = i;
            exec.execute(() -> {
                try {
                    System.out.println("天地會核心十堂核心成員,高層會議,成員:" + list.get(idx) + " 入場");
                    Thread.sleep(3000);
                } catch (Exception ignore) {
                } finally {
                    latch.countDown();
                }
            });
        }
        latch.await();
        System.out.println("天地會,核心成員到齊。開會討論誰入宮,偷取四十二章經!「內定韋香主」");
        exec.shutdown();
    }

}
  • 場景:韋小寶在麗春院營救陳近南後,加入了天地會還當上了青木堂韋香主,與其他九位香主齊名:洪順堂、家後堂、參太堂、巨集化堂、赤火堂、玄水堂、黃土堂。這也是天地會的核心成員,他們經常定期開會。這不,就開會討論由誰入宮偷取四十二章經,其實已經內定了韋香主·韋小寶。
  • 知識CountDownLatch 門栓效果,滿足一定人數就開船、搖擺錘、雲霄飛車?。那麼開會的效果也是使用這個鎖來實現,滿足10個人以後,關門開始。
  • 測試結果
天地會核心十堂核心成員,高層會議,成員:總舵主,陳近南 入場
天地會核心十堂核心成員,高層會議,成員:蓮花堂香主,蔡德忠 入場
天地會核心十堂核心成員,高層會議,成員:洪順堂香主,方大洪 入場
天地會核心十堂核心成員,高層會議,成員:家後堂香主,馬超興 入場
天地會核心十堂核心成員,高層會議,成員:參太堂香主,胡德帝 入場
天地會核心十堂核心成員,高層會議,成員:巨集化堂香主,李式開 入場
天地會核心十堂核心成員,高層會議,成員:青木堂香主,韋小寶 入場
天地會核心十堂核心成員,高層會議,成員:赤火堂香主,古至中 入場
天地會核心十堂核心成員,高層會議,成員:玄水堂香主,林永超 入場
天地會核心十堂核心成員,高層會議,成員:黃土堂香主,姚必達 入場
天地會,核心成員到齊。開會討論誰入宮,偷取四十二章經!「內定韋香主」

3. 招收雜役,入宮

圖 12-4 招收雜役,入宮

public class ReentrantLockTest {

    private static ReentrantLock lock = new ReentrantLock(true);

    private static List<String> list = Arrays.asList("路人甲", "路人乙", "路人丙", "路人丁", "路人戊", "路人己", "路人庚", "路人壬", "路人癸", "韋小寶");

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            int idx = i;

            new Thread(() -> {
                try {
                    招收雜役(list.get(idx));
                } catch (InterruptedException ignore) {
                }
            }).start();

            if (idx == 9) {
                new Thread(() -> {
                    招收太監(list.get(idx));
                }).start();
            }
        }
    }

    public static void 招收雜役(String name) throws InterruptedException {
        lock.lock();
        try {
            while (true) {
                System.out.println(name + ",排隊等待進宮當雜役...");
                Thread.sleep(1000);
            }
        } finally {
            lock.unlock();
        }
    }

    public static void 招收太監(String name) {
        System.out.println(name + ",進宮當太監,不用排隊!");
    }

}
  • 場景:在被坑作為入宮人選好後,小寶來到了招募雜役的地方,一看排隊好長。靈機一動跑到了旁邊,這邊沒有人排隊呀!就立馬衝了進去。我們在案例中採用公平鎖排隊的方式來體現這一場景。
  • 知識ReentrantLock,公平鎖排隊,在程式碼中需要顯示的開啟鎖和關閉鎖。
  • 測試結果
路人甲,排隊等待進宮當雜役...
韋小寶,進宮當太監,不用排隊!
路人甲,排隊等待進宮當雜役...
路人甲,排隊等待進宮當雜役...
路人甲,排隊等待進宮當雜役...
路人甲,排隊等待進宮當雜役...
路人甲,排隊等待進宮當雜役...

4. 皇上、建寧,比武

圖 12-5 皇上、建寧,比武

public class ReentrantReadWriteLockTest {

    private static final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    private static final Lock readLock = readWriteLock.readLock();
    private static final Lock writeLock = readWriteLock.writeLock();

    private static Deque<String> deque = new ArrayDeque<>();

    public static String get() {
        readLock.lock();
        try {
            return deque.poll();
        } finally {
            readLock.unlock();
        }
    }

    public static void put(String value) {
        writeLock.lock();
        try {
            deque.add(value);
        } finally {
            writeLock.unlock();
        }
    }

    public static void main(String[] args) {
        new Thread(() -> {
            while (true) {
                put("小擒拿");
                put("抓乃龍抓手");
                put("下腳絆");
                put("大別子");
                put("鎖喉");
                put("釦眼珠子");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException ignore) {
                }
            }
        }).start();

        new Thread(() -> {
            while (true) {
                System.out.println("韋小寶與皇上比武出招:" + get());
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ignore) {
                }
            }
        }).start();
    }

}

  • 場景:在海大富的幫助下矇混進宮偷四十二章經時,不小心被建寧公主發現,為此引來這樣一段打鬥比武的場景。小寶不會武功,每天學會點再比試點,因此我們這裡使用讀寫鎖來模擬。寫鎖相當於傳授知識、讀鎖相當於使用知識
  • 知識ReentrantReadWriteLock 關於讀寫鎖的使用。
  • 測試結果
韋小寶與皇上比武出招:小擒拿
韋小寶與皇上比武出招:抓乃龍抓手
韋小寶與皇上比武出招:下腳絆
韋小寶與皇上比武出招:大別子
韋小寶與皇上比武出招:鎖喉
韋小寶與皇上比武出招:釦眼珠子
韋小寶與皇上比武出招:小擒拿
韋小寶與皇上比武出招:抓乃龍抓手
韋小寶與皇上比武出招:下腳絆
韋小寶與皇上比武出招:大別子
韋小寶與皇上比武出招:鎖喉
韋小寶與皇上比武出招:釦眼珠子
韋小寶與皇上比武出招:小擒拿
韋小寶與皇上比武出招:抓乃龍抓手
韋小寶與皇上比武出招:下腳絆
韋小寶與皇上比武出招:大別子
韋小寶與皇上比武出招:鎖喉

5. 七個老婆,隱居

圖 12-6 七個老婆,隱居

public class SemaphoreTest {

    public static void main(String[] args) {

        List<String> list = new ArrayList<>();
        list.add("韋小寶");
        list.add("阿珂");
        list.add("雙兒");
        list.add("曾柔");
        list.add("建寧公主");
        list.add("沐建屏");
        list.add("方怡");
        list.add("蘇荃");

        Semaphore semaphore = new Semaphore(4, true);
        for (int i = 0; i < 8; i++) {
            new Thread(() -> {
                try {
                    semaphore.acquire();
                    String user = list.remove(new Random().nextInt(list.size()));
                    System.out.println("韋小寶帶著七個老婆,過著桃園生活。每天打打麻將、練練武術。麻將四人桌:" + user);
                    Thread.sleep(3000L);
                } catch (InterruptedException ignore) {
                } finally {
                    semaphore.release();
                }
            }).start();
        }

    }

}
  • 場景:經歷了風風雨雨的小寶,最後決定和老婆們過起快樂的隱居生活。我們這裡模擬隱居桃園後,每天打打麻將、練練武術,湊夠一桌四人。這裡我們使用訊號量鎖 Semaphore,一次湊夠四個人就夠一桌麻將的人。隨機抽取四個人
  • 知識Semaphore 訊號量鎖的使用
  • 測試結果
韋小寶帶著七個老婆,過著桃園生活。每天打打麻將、練練武術。麻將四人桌:曾柔
韋小寶帶著七個老婆,過著桃園生活。每天打打麻將、練練武術。麻將四人桌:蘇荃
韋小寶帶著七個老婆,過著桃園生活。每天打打麻將、練練武術。麻將四人桌:雙兒
韋小寶帶著七個老婆,過著桃園生活。每天打打麻將、練練武術。麻將四人桌:阿珂

韋小寶帶著七個老婆,過著桃園生活。每天打打麻將、練練武術。麻將四人桌:方怡
韋小寶帶著七個老婆,過著桃園生活。每天打打麻將、練練武術。麻將四人桌:韋小寶
韋小寶帶著七個老婆,過著桃園生活。每天打打麻將、練練武術。麻將四人桌:建寧公主
韋小寶帶著七個老婆,過著桃園生活。每天打打麻將、練練武術。麻將四人桌:沐建屏

三、總結

  • 在鹿鼎記的場景中我們串進去了各個多執行緒的使用案例,分別包括不同鎖:SynchronizedCountDownLatchReentrantLockReentrantReadWriteLockSemaphore
  • 很多時候如果在學習的過程中,如果能找到一些非常適合的例子,那麼對於知識點的學習是非常快的也能有深刻的印象。
  • 好嘞,這個案例就寫完了,感謝支援。同時,這裡面的各個場景中的多執行緒和鎖也可以有不同的方式的使用來實現每個場景的效果,可以自行嘗試。

四、系列推薦

相關文章