Java高级工程师蜕变·多线程·join方法结合实战【接上篇Thread API】

一、先看应用场景:

        假设有一个APP服务主要用于查询航班信息,你的APP是没有这些实时数据的,当用户发起查询请求时,你需要到各大航空公司的接口获取信息,最后统一整理加工返回到APP客户端。

       该例子是典型的串行任务局部并行化处理,用户在APP客户端输入出发地"上海"和目的地"北京",服务器接收到这个请求后,先来验证用户的信息,然后到各大航空公司的接口查询信息,最后经过加工返回给客户端,每一个航空公司的接口不一样,返回的数据格式也不同,查询速度也存在差异,如果串行化处理,很明显客户需要等待很长时间,我们将每一个航空公司的查询都交给一个线程去工作,然后在他们结束工作之后统一对数据进行处理,可以极大的节约时间。

二、实现:

1.不管是Thread的run方法,还是Runnable接口,都是void返回类型,如果想要得到运行结果,需要自己定义一个返回的接口。因此设计一个接口,用于获取当前线程的数据。如下所示:

package com.jseeker.api;

import java.util.List;

public interface FightQuery {
    List<String> get();
}

2.查询航班的任务,其实就是一个线程的子类,主要用于到各大航空公司获取数据。由于每个航空公司的查询时间不太一样,示例代码中用一个随机数来模拟不同的查询速度。线程定义如下所示:

package com.jseeker.api;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

public class FightQueryTask extends Thread implements FightQuery {

    private final String origin;

    private final String destination;

    private final List<String> flightList = new ArrayList<>();

    public FightQueryTask(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", getName(), origin, destination);
        int randomVal = ThreadLocalRandom.current().nextInt(10);
        try {
            TimeUnit.SECONDS.sleep(randomVal);
            this.flightList.add(getName() + "-" + randomVal);
            System.out.printf("The Fight:%s list query successful\n", getName());
        } catch (InterruptedException e) {

        }
    }

    @Override
    public List<String> get() {
        return this.flightList;
    }
}

3.接口和线程都定义好了,这一步就要写实现从上海到北京的航班查询了。示例代码如下:

package com.jseeker.api;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static java.util.stream.Collectors.toList;

public class FightQueryMain {
    //航空公司
    private static List<String> fightCompany = Arrays.asList("CSA", "CEA", "HNA");

    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 original, String dest) {
        final List<String> result = new ArrayList<>();

        //创建查询航班信息的线程列表
        List<FightQueryTask> tasks = fightCompany.stream()
                .map(f -> createSearchTask(f, original, dest))
                .collect(toList());

        //分别启动这几个线程
        tasks.forEach(Thread::start);

        //分别调用每一个线程的join方法,阻塞当前线程
        tasks.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {

            }
        });

        //在此之前,当前线程会阻塞住,获取每一个查询线程的结果,并且加入到result中
        tasks.stream().map(FightQueryTask::get).forEach(result::addAll);

        return result;
    }

    private static FightQueryTask createSearchTask(String fight, String original, String dest) {
        return new FightQueryTask(fight, original, dest);
    }
}

程序最终输出如下:

[CSA]-query from SH to BJ
[HNA]-query from SH to BJ
[CEA]-query from SH to BJ
The Fight:[CSA] list query successful
The Fight:[HNA] list query successful
The Fight:[CEA] list query successful
===============result===============
[CSA]-2
[CEA]-8
[HNA]-3

------------------------------------------------这是分割线------------------------------------------------

        由于随机数的关系,每台电脑执行的效果可能不太一样,主要是用来模拟。利用学习到join知识解决实际问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值