简单的多线程查询

简单的使用多线程查询

在这里插入图片描述
主要的逻辑处理是在util包下,web层和mapper是简单的显示和sql查询,service层则是添加多个sql执行任务。

下面是显用来显示方法执行的时间,但是暂时没有显示出方法名称,
之前在做多数据源的时候,在用到aop根据注解来切换数据源的方法中,有根据JoinPoint参数来得到一个方法名称,之后可以考虑添加一下。

public class MethodTimer {

    private static ThreadLocal<Long> time = new ThreadLocal<>();

    private static final Logger LOGGER = LoggerFactory.getLogger(MethodTimer.class);

    public static void start(){
        time.set(System.currentTimeMillis());
    }

    public static void end(){
        if(null != time.get()){
            LOGGER.info("方法执行时长:"+(System.currentTimeMillis() - time.get()));
        }else{
            LOGGER.info("请先调用start()方法");
        }
    }
}

这是一个简单的接口,里面只有一个方法,就是用来在实现这个接口中的invoke方法里重写,具体的方法体里面加的是mapper层查询的语句,这个在后面的service里会有体现。

public interface Invoke {

    public String invoke();
}
public class Worker implements  Runnable {


    private String name;

    private CountDownLatch latch;

    private Invoke invoke;

    public String result;

    public String getName() {
        return name;
    }

    public String getResult() {
        return result;
    }

    public Worker(String name, CountDownLatch latch, Invoke invoke) {
        this.name = name;
        this.latch = latch;
        this.invoke = invoke;
    }

    @Override
    public void run() {
        try{
            MethodTimer.start();
            result = invoke.invoke();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            latch.countDown();
            MethodTimer.end();
        }

    }
}

具体解释看注释

public class Worker implements  Runnable {

    /**
     * 这里我起的名是sql查询的结果,比如:tjxx-tpfl(统计信息-图片分类)
     */
    private String name;

    /**
     * 了解的不多,暂时知道是计数器,在执行多线程查询的时候,任务的数量对应计数器的最大值,
     * 只有计数器归0的时候,会在查询的主方法中结束
     */
    private CountDownLatch latch;

    /**
     * 就是用来执行sql任务的,实现了Runnable接口,所有将invoke方法放在了run方法里面
     */
    private Invoke invoke;

    /**
     * 用来存放sql查询的结果,类型不一定是String,根据需要变化。
     */
    public String result;

    public String getName() {
        return name;
    }

    public String getResult() {
        return result;
    }

    public Worker(String name, CountDownLatch latch, Invoke invoke) {
        this.name = name;
        this.latch = latch;
        this.invoke = invoke;
    }

    @Override
    public void run() {
        try{
            MethodTimer.start();
            result = invoke.invoke();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            /**
             * 计数器需要减一 别忘了
             */
            latch.countDown();
            MethodTimer.end();
        }

    }
}

这里创建线程是通过线程池来创建的,线程池部分还需要多去了解

public class ThreadPoolUtil {
    private static ExecutorService service;

    static{
        service = new ThreadPoolExecutor(5,8,2, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
    }

    public static void calcaulate(Runnable r){
        service.execute(r);
    }
}

主要的部分处理

public class ThreadManager {

    /**
     * 因为是线程查询,所以会有多个查询结果,所以用集合接
     */
    private Map<String,String> result = new HashMap<>();

    /**
     * 多线程查询对应的多个执行任务,都是放在每一个invoke方法里面的
     */
    private static Map<String,Invoke> invokes = Collections.synchronizedMap(new HashMap<String,Invoke>());

    /**
     * 计数器
     */
    private CountDownLatch latch = null;

    /**
     * 添加执行任务的方法,也就是添加需要查询的sql
     * @param name
     * @param invoke
     */
    public static void add(String name,Invoke invoke){
        invokes.put(name,invoke);
    }

    /**
     * 主要的处理
     * @return
     */
    public Map<String,String> calculate(){
        try{
            MethodTimer.start();
            List<Worker> workers = new ArrayList<>();
            //invoke里面存放的是执行任务的数量,所以这个数量就是计数器的开始值
            latch = new CountDownLatch(invokes.size());
            //遍历需要的执行sql任务
            Set<Map.Entry<String,Invoke>> entrys = invokes.entrySet();
            for(Map.Entry<String,Invoke> entry : entrys){
//              构建一个Woker对象,然后invoke里的sql查询任务就会在Worker对象中的run方法中执行
                Worker w = new Worker(entry.getKey(),latch,entry.getValue());
                workers.add(w);
//              执行sql任务,查询的结果会赋值给Woker对象的result属性
                ThreadPoolUtil.calcaulate(w);
            }
//           在计数器没有归0的时候会一直阻塞
            latch.await();
            for(Worker worker : workers){
//               因为每一个woker中的run方法都会将sql的查询结果赋值给result,所以这边将结果添加进result集合里面
                result.put(worker.getName(),worker.getResult());
            }
            MethodTimer.end();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
}

下面就是service处理的部分,就是通过ThreadManager对象的add方法,添加每一个执行任务,执行任务就是通过实现Invoke的invoke方法执行的。

@Service
public class MultipleNumService {

    @Autowired
    private MultipleNumMapper mapper;

    public Map<String,String> calcaulate(){
        ThreadManager manager = new ThreadManager();
        manager.add("第一个", new Invoke() {
            @Override
            public String invoke() {
                return mapper.queryNum1();
            }
        });
        manager.add("第二个", new Invoke() {
            @Override
            public String invoke() {
                return mapper.queryNum2();
            }
        });
        manager.add("第三个", new Invoke() {
            @Override
            public String invoke() {
                return mapper.queryNum3();
            }
        });

        return manager.calculate();
    }
}

有个小插曲,就是在service层中注入mapper对象时,一直提示No bean…什么的,我在启动类中加了MapperScan注解,在mapper类中也加了mapper注解,但是最后,百度一下,使用的解决办法是在idea中将这个提示改为waring
file ----> settings—>Editor---->Inspections ----->spring----->
spring core ----> code -------> AutoWiring for Bean class 等级改为warning。
yl,wxhn.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值