战狂粗人张

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  228 随笔 :: 0 文章 :: 12 评论 :: 20万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

一.使用Callable多线程:

通过Callable接口实现多线程

实现Callable重写call方法;

实现Callable和实现Runnable类似,但是功能更强大,具体表现在:

a.可以在任务结束后提供一个返回值,Runnable不行;

b.call方法可以抛出异常,Runnable的run方法不行;

c.可以通过运行Callable得到的Fulture对象监听目标线程调用call方法的结果,得到返回值,(fulture.get(),调用后会阻塞,直到获取到返回值);

 

1Callable接口介绍:

(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)第四步:启动线程;

 

二.需求:

做一个报表功能:在一个方法中查询多个数据库表的结果,然后汇总返回;

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

DAO层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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);<br>}

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; } }
复制代码

 

posted on   战狂粗人张  阅读(3078)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示