java多线程查询_利用Java函数式接口处理多线程查询

Java函数式接口

有且只有一个抽象方法的接口被称为函数式接口.

@FunctionalInterface注解: 该注解可用于一个接口的定义上, 一旦使用该注解来定义接口, 编译器将会强制检查该接口是否确实有且仅有一个抽象方法, 否则将会报错.该注解不是必须的, 只要符合函数式接口的定义,那么这个接口就是函数式接口.

1. Java中函数式接口应用

Runnable 接口

@FunctionalInterface

public interface Runnable {

// 仅有一个run方法

public abstract void run();

}

Executor接口定义

public interface Executor {

// 接收一个Runnable对象

void execute(Runnable command);

}

线程池中使用submit()方法提交任务

public class ThreadPoolDemo {

private final static ThreadPoolExecutor EXECUTOR =

new ThreadPoolExecutor(8, 8, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1000000), new ThreadPoolExecutor.AbortPolicy());

public static void main(String[] args) {

for (int i = 1; i <= 100; i ++){

// () -> System.out.println("hello world") 即表示一个Runnable对象, Java8之前为匿名内部类

EXECUTOR.execute(() -> System.out.println("hello world"));

// EXECUTOR.execute(new Runnable() {

// @Override

// public void run() {

// System.out.println("hello world");

// }

// });

}

}

}

2. 自定义函数接口

public interface ExecuteService {

void execute(String message);

}

public class Demo {

public void execute(ExecuteService service, String message){

service.execute(message);

}

public static void main(String[] args) {

Demo demo = new Demo();

String message = "你好";

demo.execute(message1 -> System.out.println(message1), message);

}

}

使用场景

在实际开发中, 经常会遇到针对多个业务过程统计表的统计查询.

比如:

指定一个时间段, 查询该时间段的统计数据

指定一个时间段, 查询该时间段的统计数据, 并根据时间分组(比如按每天)

在表的数据量较小的情况下, 一般可以直接进行统计.

SELECT COUNT(*) FROM 表 WHERE create_time >= #{T1} AND create_time <= #{T2};

如果表的数据量很大的情况下, 则COUNT的数据量可能很大, 导致SQL执行慢.

遇到这种情况一般先会针对SQL进行优化, 比如走索引. 如果走索引还是因为数据量大而导致查询慢,那么就需要将查询时间进行拆分, 拆分成一天一天查询.并开通多线程进行查询, 以多次IO数据库换取减少慢SQL操作.

SELECT COUNT(*) FROM 表 WHERE create_time = #{T};

实际场景应用

定义函数式接口

public interface OldFlowTrendCallback {

/**

* 查询数据趋势

* @param param

* @return

*/

List execute(OldFlowDashBoardParamDTO param);

}

定义针对批量多线程查询的接口方法

@Service

@Slf4j

public class OldFlowBatchSelectExecutor extends BaseBatchSelect {

/** 业务线程池*/

@Autowired

private ThreadPoolExecutor statThreadPoolExecutor;

public List execute(OldFlowTrendCallback callback, OldFlowDashBoardParamDTO dto){

Date startTime = dto.getStartTime();

Date endTime = dto.getEndTime();

// 判断是否查询的时间段是同一天, 如果是, 则直接执行

if (DateUtil.isTheSameDay(startTime, endTime)) {

setAssignDate(dto);

return callback.execute(dto);

}

// 创建队列, 接收异步线程执行结果

BlockingQueue>> queue = new LinkedBlockingQueue<>();

// 如果查询时间段为一个时间段, 那么则拆分成一天一天的查询处理

while (startTime.getTime() < endTime.getTime()) {

OldFlowDashBoardParamDTO dayParam = VOUtil.from(dto, OldFlowDashBoardParamDTO.class);

dayParam.setStartTime(startTime);

dayParam.setEndTime(startTime);

setAssignDate(dayParam);

// 通过线程池异步执行任务, 返回Futrue

Future> future = statThreadPoolExecutor.submit(() -> callback.execute(dayParam));

queue.add(future);

startTime = DateUtil.getNextDateFirst(startTime);

}

// 封装返回接口, 主要是使用Futrure接口get()方法, 阻塞获取异步线程执行的结果

return packBatchSelectResult(queue);

}

private void setAssignDate(OldFlowDashBoardParamDTO dto) {

Date startAssignDate = DateUtil.addDateDays(dto.getStartTime(), - dto.getAssignDateType());

Date endAssignDate = DateUtil.getYestodayFirst(dto.getStartTime());

dto.setStartAssignDate(startAssignDate);

dto.setEndAssignDate(endAssignDate);

}

}

业务方法

public List listOldFlowGroupByStatDate(OldFlowDashBoardParamDTO dto) {

// 通过OldFlowBatchSelectExecutor 统一处理拆分多线程查询

// (dayParam) -> effectiveFollowingMapper.listOldFlow(dayParam)): 即是OldFlowTrendCallback接口实现

return oldFlowBatchSelectExecutor.execute(((OldFlowTrendCallback) (dayParam) -> effectiveFollowingMapper.listOldFlow(dayParam)), dto);

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值