join方法應用之—查詢航班資訊

wjf_jone發表於2020-10-08

哈嘍,小夥伴們,大家好。本章節繼續分享join應用,希望大家有所收穫。好了,廢話不多說,進入正題。


需求:

假設一個軟體,需要實現這樣一個功能,主要用於查詢航班資訊,你的軟體沒有這些實時資料的,所以當使用者發起查詢請求時,你需要到各大航空公司的介面獲取資訊,最後統一整理加工返回到客戶端。需求大概如下圖:
在這裡插入圖片描述

分析:

其實功能很簡單,就是我們輸入起始地址,然後去查詢每一家航空公司的航班資訊,返回給我們,我們處理之後,再返回給客戶端。就是先序列然後並行然後序列,即序列任務區域性並行。
第一步:定義一個介面

/**
 * 航班查詢
 */
public interface FlightQuery {

    List<String> get();// 航空公司名稱-查詢時長

}

因為不管是Thread 的 run 方法,還是 Runnable 介面,都是 void 返回型別,如果你想通過某個執行緒的執行得到結果,就需要自己定義一個返回介面。

第二步:定義一個任務實現類,去實現FlightQuery並且繼承Thread類。

public class FlightQueryTask extends Thread implements FlightQuery {

    private final String origin;// 出發地
    private final String destination;// 目的地
    private final List<String> flightList = new ArrayList<>();// 航班資訊集合

    public FlightQueryTask(String airline, String origin, String destination) {
        super("[" + airline + "]");// 使用航空公司名稱為執行緒命名
        this.origin = origin;
        this.destination = destination;
    }

    @Override
    public void run() {
        // 航空公司查詢從出發地到目的地
        System.out.printf("%s-query from %s to %s \n", this.getName(), origin, destination);
        // 隨機生成隨機數模擬查詢時長
        int randomVal = ThreadLocalRandom.current().nextInt(10);
        try {
            TimeUnit.SECONDS.sleep(randomVal);
            // 將航空公司和查詢時長新增至航班資訊集合中
            this.flightList.add(this.getName() + "-" + randomVal);
            System.out.printf("The Flight:%s list query successful\n", this.getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public List<String> get() {
        return this.flightList;// 返回航班查詢資訊
    }

}

在程式碼裡面,很多程式碼你可以不看,主要就是重執行單元run方法,因為邏輯都在run方法裡面。然後run方法重點就是將航空公司和查詢時長新增至航班資訊集合中,最後通過get()方法獲取航班資訊。

第三步:編寫具體實現類。


public class FlightQueryExample {

    // APP 合作的航空公司
    private static List<String> airlineList = Arrays.asList("南方航空", "東方航空", "海南航空");

    public static void main(String[] args) {
        List<String> results = search("SH", "BJ");
        System.out.println("----------result----------");
        results.forEach(System.out::println);
    }

    private static List<String> search(String origin, String destination) {
        final List<String> result = new ArrayList<>();// 聚合所有航空公司查詢結果的集合
        // 建立查詢航班資訊的執行緒列表
        List<FlightQueryTask> tasks = airlineList.stream()
                .map(f -> new FlightQueryTask(f, origin, destination))
                .collect(Collectors.toList());
        // 啟動執行緒
        tasks.forEach(Thread::start);
        // 呼叫每一個執行緒的 join 方法,阻塞當前執行緒
        tasks.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        // 當前執行緒阻塞,獲取每一個查詢執行緒的結果,並且加入 result 中
        tasks.stream().map(FlightQuery::get).forEach(result::addAll);
        return result;
    }
}

程式碼裡面,相關的程式碼我已經註釋,如果還是有不懂,建議去除錯一下,還是不懂,給我留言,我給你講。這個程式簡單來說,就是主執行緒收到了search 請求之後, 交給了若干個査詢執行緒分別進行工作,最後將每一個執行緒獲取的航班資料進行統一的彙總。 由於每個航空公司的查詢時間可能不一樣,所以用了一個隨機值來反應不同的查詢速度,返回給客戶端(列印到控制檯)。

第四步:輸出結果

在這裡插入圖片描述

總結:

如果我們去掉下面這段程式碼:則不能達到我們想要的效果。

// 呼叫每一個執行緒的 join 方法,阻塞當前執行緒
        tasks.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

有興趣的小夥伴可以嘗試以下,好了,本次分享到此結束。下節內容我們將分享執行緒之間的通訊,希望對你有幫助。

相關文章