前言
多线程是java的比较重要的特性之一,现在记录一个使用多线程解决实际问题的栗子
背景
假设有一个模型服务,它的功能是通过输入的手机号来计算分数。例如支付宝的芝麻分。现在我有一个很大的客户手机号集合,数据量集是百万级别的。产品的要求是用尽可能短的时间将客户手机号集合中的每一个手机号都要匹配出分数。
可行性分析
假设模型服务成功处理一笔交易的时间是50ms,如果使用传统单线程的方式,每秒最多处理20笔交易。即TPS=20。假如需要跑批的数据量是100w,成功处理完这些数据需要消耗 100w/ 7.2w=13.8小时。假设我们模型服务的系统处理能力可以达到每秒中成功处理100笔交易,那么 成功处理完这些数据只消耗 100w/36w=2.7小时,缩短了 11个小时。
首先了解一种线程池
java 自带的线程池中有一个固定大小线程池
newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
核心思想
我们将访问模型服务这个行为通过线程来实现,这个线程的任务就是通过访问评分服务将一个手机号的分数记录下来。首先我们维护一个长度为1000的定长线程池,在向线程池添加工作线程时,通过控制线程加入线程池的时间间隔 来实现控制tps。比如我们需要控制tps是 100,我们可以设置添加线程的间隔是 10ms,即每一秒最多有100个线程加入到线程池。这样就可以实现以tps100的方式来访问评分服务。注意,这里的tps是期望tps,实际tps可能达不到100。
关键代码
WorkThread
package com.batch.threadapp;
public class WorkThread implements Runnable{
private String mobile = "";
private Integer num;
public WorkThread(String _mobile,Integer num){
this.mobile = _mobile;
this.num=num;
}
@Override
public void run() {
String reqData = mobile;
try {
System.out.println("["+num+"]request data :"+reqData);
String respStr = accessScoreService(reqData);
System.out.println("["+num+"]response data :"+respStr);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
//TODO 在这里写访问评分服务的逻辑,通常是http的
private String accessScoreService(String reqData) {
return reqData+"res";
}
}
Main
package com.batch.threadapp;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
List<String> mobList=new ArrayList<String>();
mobList.add("18654444444");
mobList.add("18654444443");
mobList.add("18654444442");
Integer tps=10;
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(1000);
int sleepTime = 1000 / tps;
for(Integer i=0,size=mobList.size();i<size;i++){
String mob=mobList.get(i);
fixedThreadPool.execute(new WorkThread(mob, i));
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("线程初始化完成");
}
}
后记
到目前为止,简单的跑批程序已经写完。但是有一个问题是程序什么时候可以停止未知。即在主线程中,无法得知子线程的处理情况。这个问题留在以后解答。