JAVA多线程获取目标服务器数据

JAVA多线程获取服务器数据实战

java线程池的几种创建方式

Java通过Executors提供四种线程池,分别为:

  1. newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  2. newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  3. newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
  4. newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行

这里以newFixedThreadPool为例,结合网上资料实现过程如下:

定义实体类

用来初始化线程返回相关数据

@Slf4j
@Data
public class ThreadCallService implements Callable<Object> {

    // 查询参数
    private Map<String, Object> param;

    private String key;

    // 调用的service地址
    private String serviceAddress;

    public static int count = 0;

    private long consumeTime;

    // 返回的结果
    private Object resultData;

    public ThreadCallService (String serviceAddress, Map<String, Object> paramMap) {
        // 初始化参数
        this.param = paramMap;
        this.serviceAddress = serviceAddress;
    }

    @Override
    public Object call(){
        count ++;
        // 调用service获取相关数据
        log.info("开始线程 " + count);
        // 这里是调用服务器对外开放的API获取数据(具体形式具体对待)
        resultData = ServiceUtil.connectService(serviceAddress, "apiUrl", param);
        // 返回数据给Future
        return resultData;
    }
}

主方法

初始化所有线程–> 启动线程 --> 获取结果

private List<Map> multiThreadHandleData(List<Map<String, Object>> paramMapList, String key)
            throws Exception {
        List data = new ArrayList<>();
        // 多线程查询方式
        long start = System.currentTimeMillis();
        List<Callable<Object>> threadList = new ArrayList<>();
        Callable<Object> callable = null;
        for (Map<String, Object> paramMap : paramMapList) {

            // 初始化线程
            callable = new ThreadCallService (webServiceAddress, paramMap);
            threadList.add(callable);
        }
        // 初始化线程数量,防止卡死
        ExecutorService executorService = Executors.newFixedThreadPool(paramMapList.size());
        //Future用于获取结果
        List<Future<Object>> futures = executorService.invokeAll(threadList);

        //处理子线程返回结果
        if (CollectionUtils.isNotEmpty(futures)) {
	        for (Future<Object> future : futures) {
	        	// 具体数据结构具体处理
	            data.add(future.get());
	        }
            log.info("此次相关 " + key + " 的" + paramMapList.size() + " 个线程都跑完了,继续主线程的工作");

            // 关闭线程池
            executorService.shutdown();
            while (true) {
                // 判断线程池中任务是否全部执行完毕  若执行完毕 再返回 list
                if (executorService.isTerminated()) {
                    break;
                }
            }
            long end = System.currentTimeMillis();
            log.info("线程查询 " + key + " 数据用时: " + (end - start) + "ms");
            log.info("下个数据类型的线程,起点编号为 : " + (ThreadCallWebservice.count + 1));
        }
        return data;
    }

注意 : 这里的paramMapList的大小直接决定的线程池的大小,实际可以通过评估服务器当前用户的最大线程数压力来指定大小

总结

  1. 线程池的初始化方式需要从硬件设施/业务场景综合考虑
  2. 单个线程要做的事情为单元来封装实体类可以使程序变得更灵活通用
  3. 用简洁的日志来直观的显示线程的执行过程
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值