关于Java串行、并行执行——使用Callable多线程

需求:

做一个报表功能:

在一个方法中查询多个数据库表的结果,然后汇总返回;
由于单独查询一个数据库表速度较慢(大字段查询),此时如果串行查询多个表的话效率会非常低,
所以需要多线程同时查询数据库,等全部查询完毕后再汇总!

DAO层:

package com.moerlong.yj.mapper;

import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;

@Repository
public interface BaseMapper {

    @Select("select hf_industry_record from msd_hf_industry_person_srcdata where card_id = #{cardId}")
    public String selectIndustryData(String cardId);

    @Select("select hf_judicial_record from msd_hf_judicial_person_srcdata where card_id = #{cardId}")
    public String selectJudicialData(String cardId);

    @Select("select td_record from msd_td_preloan_srcdata where card_id = #{cardId}")
    public String selectTdData(String cardId);
}

  

Service层:

串行执行:

package com.moerlong.yj.Service;

import com.moerlong.yj.mapper.BaseMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


@Service
public class TestNoCallable {

    @Autowired
    private BaseMapper baseMapper;

    public String test1(String cardId) throws Exception{
        long start = System.currentTimeMillis();

        //三个串行查询
        String industryData = baseMapper.selectIndustryData(cardId);
        String judicialData = baseMapper.selectJudicialData(cardId);
        String tdData = baseMapper.selectTdData(cardId);

        Thread.sleep(3000);     //此处模拟每个查询添加1s耗时

        String result = industryData + judicialData + tdData;

        long end = System.currentTimeMillis();
        System.out.println("串行执行:" + (end-start));

        return result;
    }
}

并行执行:

package com.moerlong.yj.Service;

import com.moerlong.yj.mapper.BaseMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Method;
import java.util.concurrent.*;


@Service
public class TestCallable {
    @Autowired
    private BaseMapper baseMapper;

    public String test2(String cardId) throws Exception{
        // 三个线程的线程池,核心线程=最大线程,没有临时线程,阻塞队列无界
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        long start = System.currentTimeMillis();

        // 开启线程执行
        // 注意,此处Future对象接收线程执行结果不会阻塞,只有future.get()时候才会阻塞(直到线程执行完返回结果)
        Future future1 = executorService.submit(new SelectTask<>(this, "selectIndustryData", new Object[]{cardId}));

        Future future2 = executorService.submit(new SelectTask<>(this, "selectJudicialData", new Object[]{cardId}));

        Future future3 = executorService.submit(new SelectTask<>(this, "selectTdData", new Object[]{cardId}));

        //此处用循环保证三个线程执行完毕,再去拼接三个结果
        do{
            System.out.println("多任务同时执行中...");
        }while (!(future1.isDone() && future2.isDone() && future3.isDone()));

        String result = (String)future1.get() + future2.get() + future3.get();

        long end = System.currentTimeMillis();
        System.out.println("并行执行:" + (end-start));

        return result;

    }

    //下面是三个真正执行任务(查数据库)的方法
    public String selectIndustryData(String cardId) throws Exception{
        String result = baseMapper.selectIndustryData(cardId);
        Thread.sleep(1000);    //模拟添加1s耗时
        return result;
    }

    public String selectJudicialData(String cardId) throws Exception{
        String result = baseMapper.selectJudicialData(cardId);
        Thread.sleep(1000);
        return result;
    }

    public String selectTdData(String cardId) throws Exception{
        String result = baseMapper.selectTdData(cardId);
        Thread.sleep(1000);
        return result;
    }

    //任务线程类
    class SelectTask<T> implements Callable<T> {

        private Object object;
        private Object[] args;
        private String methodName;

        public SelectTask(Object object, String methodName, Object[] args) {
            this.object = object;
            this.args = args;
            this.methodName = methodName;
        }

        @Override
        public T call() throws Exception {
            Method method = object.getClass().getMethod(methodName,String.class);   //此处应用反射机制,String.class是根据实际方法参数设置的
            return (T) method.invoke(object, args);
        }
    }
}

控制层:

package com.moerlong.yj.controller;


import com.moerlong.yj.Service.TestCallable;
import com.moerlong.yj.Service.TestNoCallable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class TestController {
@Autowired
private TestNoCallable testNoCallable; @Autowired private TestCallable testCallable; @RequestMapping(value = "/test1/{cardId}") public String test1(@PathVariable String cardId) throws Exception{ String result = testNoCallable.test1(cardId); return result; } @RequestMapping(value = "/test2/{cardId}") public String test2(@PathVariable String cardId) throws Exception{ String result = testCallable.test2(cardId); return result; } }

补充:关于使用Callable多线程:

一.通过Callable接口实现多线程

实现Callable重写call方法
实现Callable和实现Runnable类似,但是功能更强大,具体表现在
a.可以在任务结束后提供一个返回值,Runnable不行
b.call方法可以抛出异常,Runnable的run方法不行
c.可以通过运行Callable得到的Fulture对象监听目标线程调用call方法的结果,得到返回值,(fulture.get(),调用后会阻塞,直到获取到返回值)


1.Callable接口介绍:

(1)java.util.concurrent.Callable是一个泛型接口,只有一个call()方法

(2)call()方法抛出异常Exception异常,且返回一个指定的泛型类对象

2.Callable接口实现多线程的应用场景

(1)当父线程想要获取子线程的运行结果时

3.使用Callable接口实现多线程的步骤

(1)第一步:创建Callable子类的实例化对象

(2)第二步:创建FutureTask对象,并将Callable对象传入FutureTask的构造方法中(注意:FutureTask实现了Runnable接口和Future接口)

  (3)第三步:实例化Thread对象,并在构造方法中传入FurureTask对象

  (4)第四步:启动线程

猜你喜欢

转载自www.cnblogs.com/ZJOE80/p/12131045.html