面了個 5 年 Java,兩個線程進行數據交換都不會,我真是醉了。。

来源:https://www.cnblogs.com/javastack/archive/2022/06/10/16363358.html
-Advertisement-
Play Games

面試總結 最近棧長面試了一個 5 年經驗的 Java 程式員,簡歷和個人介紹都提到了精通 Java 多線程,於是我就問了幾個多線程方面的問題: 1、實現多線程有哪幾種方式,如何返回結果? 2、多個線程如何實現順序訪問? 3、兩個線程如何進行數據交換? 4、如何統計 5 個線程的運行總耗時? 5、如何 ...


面試總結

最近棧長面試了一個 5 年經驗的 Java 程式員,簡歷和個人介紹都提到了精通 Java 多線程,於是我就問了幾個多線程方面的問題:

1、實現多線程有哪幾種方式,如何返回結果?

2、多個線程如何實現順序訪問?

3、兩個線程如何進行數據交換?

4、如何統計 5 個線程的運行總耗時?

5、如何將一個任務拆分成多個子任務執行,最後合併結果?

大概問了他這幾個問題,答的並不是太好,3、4、5 題都沒有真正答上來,其實這幾個問題在 JDK 包中都有答案,但他給的是他個人臨時思考的方案,而且我個人覺得可能行不通。

工作 5 年了,這幾個題都答不好,有點說不過去,我真是醉了。。

其中,1、2、4、5 題我都在公眾號Java技術棧分享過相關的教程,也都在Java面試庫小程式上整理好了,最近面試的看看,今天就分享一下第 3 題的參考答案。

第 3 題也是通過 JDK 中的 java.util.concurrent.Exchanger 類來實現的,並不需要我們重覆造輪子,這個工具類在 JDK 1.5 中就已經引入了,並不是什麼 "新特性"。

Exchanger 簡介

Exchanger 就是線程之間的數據交換器,只能用於兩個線程之間的數據交換。

Exchanger 提供了兩個公開方法:

1、只帶泛型 V(交換的數據對象)的方法,線程一直阻塞,直到其他任意線程和它交換數據,或者被線程中斷;線程中斷也是一門學問,棧長在公眾號Java技術棧已經分享過,可在公眾號搜索閱讀;

2、另外一個帶時間的方法,如果超過設置時間還沒有線程和它交換數據,就會拋出 TimeoutException 異常;

Exchanger 實戰

簡單數據交換

來一個兩個線程正常數據交換的簡單示例:

private static void test1() {
    Exchanger exchanger = new Exchanger();

    new Thread(() -> {
        try {
            Object data = "-公眾號Java技術棧AAA";
            System.out.println(Thread.currentThread().getName() + data);

            // 開始交換數據
            data = exchanger.exchange(data);
            System.out.println(Thread.currentThread().getName() + data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();

    new Thread(() -> {
        try {
            Object data = "-公眾號Java技術棧BBB";
            System.out.println(Thread.currentThread().getName() + data);

            // 開始交換數據
            data = exchanger.exchange(data);
            System.out.println(Thread.currentThread().getName() + data);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();
}

這段代碼的邏輯:

1、創建並啟動兩個線程;

2、進行數據交換前先列印出自己線程的數據;

3、進行數據交換;

4、列印數據交換之後的數據;

輸出結果:

從結果可以看出,線程 0、1 分別先列印出 A、B,數據交換之後,列印出了 B、A,數據交換正常!

超時數據交換

上面演示了兩個線程的正常交換,下麵再來一個帶超時的示例:

private static void test2() {
    Exchanger exchanger = new Exchanger();

    new Thread(() -> {
        try {
            Object data = "-公眾號Java技術棧AAA";
            System.out.println(Thread.currentThread().getName() + data);

            // 開始交換數據
            data = exchanger.exchange(data, 3000L, TimeUnit.MILLISECONDS);
            System.out.println(Thread.currentThread().getName() + data);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }).start();
}

現在只啟動了一個線程,並且設置了超時時間 3 秒。

輸出結果:

首先線程輸出了自己的數據,然後 3 秒後,並沒有其他線程和它交換數據,所以拋出了超時異常,最後線程結束運行。

本文所有案例源代碼已經上傳:https://github.com/javastacks/javastack

中斷數據交換

線程開始交換數據後,會一直阻塞直到其他任意線程和它交換數據,或者被中斷、超時,上面演示了超時,下麵這個示例演示一下中斷。

private static void test3() {
    Exchanger exchanger = new Exchanger();

    new Thread(() -> {
        try {
            Object data = "-公眾號Java技術棧AAA";
            System.out.println(Thread.currentThread().getName() + data);

            // 開始交換數據
            data = exchanger.exchange(data);
            System.out.println(Thread.currentThread().getName() + data);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }).start();
}

結果輸出:

預設情況下不帶超時設置會一直阻塞運行中……

現在我再加入一段中斷的邏輯:

private static void test3() throws InterruptedException {
    Exchanger exchanger = new Exchanger();

    Thread thread = new Thread(() -> {
        try {
            Object data = "-公眾號Java技術棧AAA";
            System.out.println(Thread.currentThread().getName() + data);

            // 開始交換數據
            data = exchanger.exchange(data);
            System.out.println(Thread.currentThread().getName() + data);
        } catch (Exception e) {
            e.printStackTrace();
        }
    });

    thread.start();

    // 線程中斷
    Thread.sleep(3000L);
    thread.interrupt();
}

主線程休眠 3 秒後,中斷該線程。

輸出結果:

輸出結果 3 秒後,線程被中斷了,拋出了中斷異常,線程也停止阻塞,最後線程結束運行。

兩兩數據交換

另外需要知道是,Exchanger 只能用於兩個線程之間的數據交換,一個線程開啟數據交換之後,會阻塞直到其他任意線程同樣開啟數據交換達到交換點。

最後來個示例,開啟 10 個線程,看它們是怎麼兩兩交換的:

private static void test4() {
    Exchanger exchanger = new Exchanger();

    for (int i = 1; i <= 10; i++) {
        Integer data = i;
        new Thread(() -> {
            try {
                Object exchange = exchanger.exchange(data);
                System.out.println(Thread.currentThread().getName() + "-" + exchange);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "Java技術棧" + i).start();
    }
}

輸出結果:

可以看到,10 個線程,都兩兩交換彼此的數據了。

總結

本文介紹了線程之間的數據交換器 Exchanger 類的使用,只能用於多個線程中的兩個線程兩兩交換數據,如果沒有對應的線程交換就會一直阻塞,可設置超時,可以中斷。

你都掌握了嗎?面試如果問到,你需要掌握這個類的用法,當然也有其他的方案,但如果不是必須就沒有必要重覆造輪子,重覆造輪子需要考慮的面更多。

本文所有案例源代碼已經上傳:

https://github.com/javastacks/javastack

歡迎 Star 學習,後面 Java 示例都會在這上面提供!

好了,今天的分享就到這裡了,後面棧長會分享更多好玩的 Java 技術和最新的技術資訊,關註公眾號Java技術棧第一時間推送,我也將主流 Java 面試題和參考答案都整理好了,在公眾號後臺回覆關鍵字 "面試" 進行刷題。

最後,覺得我的文章對你用收穫的話,動動小手,給個在看、轉發,原創不易,棧長需要你的鼓勵。

版權聲明: 本文系公眾號 "Java技術棧" 原創,轉載、引用本文內容請註明出處,抄襲、洗稿一律投訴侵權,後果自負,並保留追究其法律責任的權利。

近期熱文推薦:

1.1,000+ 道 Java面試題及答案整理(2022最新版)

2.勁爆!Java 協程要來了。。。

3.Spring Boot 2.x 教程,太全了!

4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優雅的方式!!

5.《Java開發手冊(嵩山版)》最新發佈,速速下載!

覺得不錯,別忘了隨手點贊+轉發哦!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文代碼: https://gitee.com/felord/spring-security-oauth2-tutorial/tree/wwopen/ 現在很多企業都接入了企業微信,作為私域社群工具,企業微信開放了很多API,可以打通很多自有的應用。既然是應用,那肯定需要做登錄。正好企業微信提供了企 ...
  • 變數(variable)可以理解成一塊記憶體區域,通過變數名,可以引用這塊記憶體區域,獲取裡面存儲的值。 變數名 標識符(identifier)命名有嚴格的規範。 只能由字母、數字和下劃線(_)組成。 不能以數字開頭。 長度不能超過63個字元。 不能使用關鍵字和保留字。 auto, break, cas ...
  • 1、從規範角度分析,一般是禁止使用C++的異常機制的。 2、要求所有的錯誤都應該通過錯誤值在函數間傳遞病做相應的判斷,而不應該通過異常機制進行錯誤處理。 3、編碼人員必須完全掌控自己的整個編碼過程,要有攻擊者思維,主動把握有可能出錯的環節,儘可能的分析出程式的所有異常,增強安全編碼意識。 4、使用c ...
  • ​ 1,建一個表 create table 表名( 屬性a 類型 限制, 屬性b 類型 限制 ) ​編輯 2,向表裡添加數據 insert into Tset(屬性a,屬性b) values(a的數據,b的數據) 給屬性a,屬性b添加數據 insert into Tset values(a的數據,b ...
  • 排序演算法總結 1.十大經典演算法及性能 2.具體排序演算法 1.冒泡排序 迴圈過程中比較相鄰兩個數大小,通過交換正確排位,迴圈整個數組即可完成排序 圖片演示 代碼實現Java //冒泡排序 public static Integer[] Bubble(Integer[] array){ boolean ...
  • 前言 不知道有沒有小伙伴跟我一樣,每次刷抖音都不想動手,好希望能夠有什麼東西代替我的手指,我給它一個命令,它就明白我要什麼。於 是,我利用空閑時間操作了一下,終於用Python把自動刷抖音給搞出來了,這下真的是解決了我長久以來的困擾… 工具準備 1.Python3.7.7 2.adb(Android ...
  • 我們知道 Python 有很多運算符可以進行數學運算,如果是簡單的問題還好說,但是要處理一些相對複雜的問題也要我們自己一行一行手動的來編寫嗎?答案當然不是,Python 提供了 math 模塊對一些數學運算提供了支持。 1.簡介 math 模塊提供了對 C 標准定義的數學函數的訪問,但該模塊並不支持 ...
  • Skywalking介紹 Skywalking是一個國產的開源框架,2015年有吳晟個人開源,2017年加入Apache孵化器,國人開源的產品,主要開發人員來自於華為,2019年4月17日Apache董事會批准SkyWalking成為頂級項目,支持Java、.Net、NodeJs等探針,數據存儲支持 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...