线程池可以认为是回调的方式。将匿名内部类传递给调用的线程。等线程池做完后,就可以调用内部类的方法。
下面代码展示了一个请求(实际上是会有多个请求,这里只做一个demo)到来,后端用多线程回调的方式找到对应的数据源的过程。
程序只有一下几个类:
首先是实现ThreadFactory的工厂类,可以对线程进行命名。Daemon会在jvm退出后继续工作。
package callback;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.ThreadFactory;
public class NamedThreadFactory implements ThreadFactory {
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
private final boolean makeDaemons;
private final ThreadGroup group;
public NamedThreadFactory(String poolName) {
this(poolName, false);
}
public NamedThreadFactory(String namePrefix, boolean makeDaemons) {
this.namePrefix = namePrefix;
this.makeDaemons = makeDaemons;
this.group = Thread.currentThread().getThreadGroup();
}
public Thread newThread(Runnable runnable) {
Thread ret = new Thread(group, runnable, namePrefix + "#" + threadNumber.getAndIncrement());
// java虚拟机退出后也不会终止的线程
ret.setDaemon(makeDaemons);
return ret;
}
public ThreadGroup getThreadGroup() {
return group;
}
}
WorkUnit类,定义了选择的线程池,以及线程池的各项操作,如submit()函数,getResult()函数等。getResult函数调用了回调函数。即实现了callback的匿名内部类中callback()函数。
使用泛型,因为call()、callback()函数返回类型可以多样,这样写更通用。使用CompletionService,对main方法定义的pool进一步封装。
package callback;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class WorkUnit<T> {
private static final long DEFAULT_TIMEOUT = 10 * 60 * 1000;
private CompletionService<T> completion;
private AtomicInteger taskCount;
private long timeout;
public WorkUnit(Executor pool, long timeout) {
completion = new ExecutorCompletionService<T>(pool);
this.taskCount = new AtomicInteger();
this.timeout = timeout;
}
public WorkUnit(Executor pool) {
this(pool, DEFAULT_TIMEOUT);
}
public void submit(Runnable runnable) {
completion.submit(runnable, null);
taskCount.incrementAndGet();
}
public boolean waitForCompletion() {
boolean success = true;
for (int i = 0; i < taskCount.intValue(); i++) {
try {
Future<T> r = completion.take();
r.get(timeout, TimeUnit.MILLISECONDS);
} catch (Exception e) {
// logger.error("wait for execute completion failed,e=" + e, e);
success = false;
}
}
return success;
}
public void submit(Callable<T> callable) {
completion.submit(callable);
taskCount.incrementAndGet();
}
public void getResult(WorkUnitCallback<T> WorkUnitCallback) throws Exception {
for (int i = 0; i < taskCount.intValue(); i++) {
Future<T> f = completion.take();
WorkUnitCallback.callback(f.get(timeout, TimeUnit.MILLISECONDS));
}
}
}
WorkUnitCallback接口,只定义了callback函数的声明。方便main方法采用匿名内部类的方式定义不同的callbcak()方法。main方法中把这个实现了WorkUnitCallback的匿名内部类传递给WorkUnit,在线程池做完相关的操作后,就会调用callback方法把结果放到List容器。
package callback;
public interface WorkUnitCallback<T> {
void callback(T t);
}
Main类,程序的执行入口。重要的是两个匿名内部类——call()和callback()。调用WorkUnit去执行。
StandardDataCoreRequest是请求类。可以忽略不看。
package callback;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class Main {
// list多线程方法
public static List<Map<String, Object>> responses = Collections.synchronizedList(new LinkedList<Map<String, Object>>());
// NamedThreadFactory用途在于给创建的线程起名字,这样可以在控制台、日志显示是哪个线程
protected static Executor WORKER_POOL = Executors.newFixedThreadPool(10, new NamedThreadFactory("KeyWordReportExecutor",true));
public static void main(String[] args) throws Exception {
StandardDatacoreRequest request = new StandardDatacoreRequest();
List<StandardDatacoreRequest> requestGroups = new LinkedList<StandardDatacoreRequest>();
requestGroups.add(request);
WorkUnit<List<Map<String, Object>>> unit = new WorkUnit<List<Map<String, Object>>>(WORKER_POOL,
1000L);
for (final StandardDatacoreRequest req : requestGroups) {
unit.submit(new Callable<List<Map<String, Object>>>() {
@Override
public List<Map<String, Object>> call() throws Exception {
return requestDataCore(req);
}
});
}
unit.getResult(new WorkUnitCallback<List<Map<String, Object>>>() {
@Override
public void callback(List<Map<String, Object>> t) {
if (t != null && !t.isEmpty()) {
responses.addAll(t);
}
}
});
}
public static List<Map<String, Object>> requestDataCore(StandardDatacoreRequest req) {
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
System.out.println(134);
return list;
}
}
StandardDataCoreRequest和程序相关性不大。是写的一个请求类。
package callback;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import org.apache.commons.beanutils.BeanUtils;
public class StandardDatacoreRequest implements Cloneable {
// private static Set<DatacoreColumn> EMPTY_DATACORECOLUMN = new HashSet<DatacoreColumn>();
private Random random = new Random();
private long logId = generateLogId();// 每个请求分配一个ID,唯一对应一个请求
private Set<Long> userid;
private Date beginTime;
private Date endTime;
// private TimeColumnGranularity timeColumnGranularity = TimeColumnGranularity.Daily;// 请求数据的time列,默认为分日(即,数据以哪种时间粒度呈现)
// private Set<DatacoreColumn> idColumns;// 请求数据的id列(即,包含哪些维度)
// private Set<DatacoreColumn> dataColumns;// 请求数据的data列(即,包含哪些数据指标)
// private InCondition[] idConditions;// 具体的id集合,可指定多个层级(即,要请求物料范围)
// private Set<DatacoreColumn> sumByColumns;// 根据哪个维度进行分维度求和
// private Limit limit;// 分页参数,limit m,n
// private Orders orderBy;// 排序列
private boolean needSum;
private int weekDayStartFrom = 1;
private Set<String> processConf = new HashSet<String>(); // 特殊处理的一些标志集
// private FamilyName family = FamilyName.FC;//区分报告来源家族,比如凤巢,知心教育等
// private SQLCondition filterCondition; // 过滤条件
private boolean isKeyWordOneDayRequest; //是否为关键词报告ID预取请求
private Integer reportType; // 请问报告类型
/**
* @return the reportType
*/
public Integer getReportType() {
return reportType;
}
/**
* @param reportType the reportType to set
*/
public void setReportType(Integer reportType) {
this.reportType = reportType;
}
// public String getMD5ForRequest() {
// ToStringBuilder str = new ToStringBuilder(this);
// str.append(userid).append(beginTime).append(endTime).append(timeColumnGranularity).append(idColumns).append(
// dataColumns).append(idConditions).append(limit).append(orderBy).append(weekDayStartFrom);
// try {
// MessageDigest md5 = MessageDigest.getInstance("md5");
// byte[] md5Bytes = md5.digest(str.toString().getBytes("GBK"));
// StringBuilder sb = new StringBuilder();
// for (byte b : md5Bytes) {
// sb.append(String.format("%02x", b));
// }
// return sb.toString();
// } catch (Exception e) {
// throw new RuntimeException("generate md5 failed");
// }
// }
/**
* 生成近似唯一的ID,用于标识每个请求 <br>
* 在不同毫秒内,任意请求的ID不会重复 <br>
* 在同一毫秒内,两个请求ID重复的概率约为1/65536
*
* @return
*/
private long generateLogId() {
long now = System.currentTimeMillis();
long rand = random.nextLong() & 0xFFFF;
return now << 16 | rand; // 41 bits 系统时间 + 16 bits 随机数
}
public void addProcessConf(String... processorConfs) {
if (processorConfs != null && processorConfs.length > 0) {
this.processConf.addAll(Arrays.asList(processorConfs));
}
}
public boolean hasProcessConf(String conf) {
return this.processConf.contains(conf);
}
// @Override
// public String toString() {
// return new ReflectionToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).toString();
// }
// org.apache.commons.beanutils
@Override
public StandardDatacoreRequest clone() {
StandardDatacoreRequest obj = null;
try {
obj = (StandardDatacoreRequest) BeanUtils.cloneBean(this);
} catch (Exception e) {
throw new RuntimeException(e);
}
obj.logId = generateLogId();
return obj;
}
public Set<String> getProcessConf() {
return processConf;
}
public void setProcessConf(Set<String> processConf) {
this.processConf = processConf;
}
public boolean isNeedSum() {
return needSum;
}
public void setNeedSum(boolean needSum) {
this.needSum = needSum;
}
public int getWeekDayStartFrom() {
return weekDayStartFrom;
}
public void setWeekDayStartFrom(int weekDayStartFrom) {
this.weekDayStartFrom = weekDayStartFrom;
}
/**
* 用于标识每个请求的ID <br>
* 该ID近似唯一,但不保证严格的唯一性,因此不能用于实际业务逻辑 <br>
* 在不同毫秒内,任意请求的ID不会重复 <br>
* 在同一毫秒内,两个请求ID重复的概率约为1/65536
*
* @return
*/
public long getLogId() {
return logId;
}
public Set<Long> getUserid() {
return userid;
}
public void setUserid(Set<Long> userid) {
this.userid = userid;
}
public Date getBeginTime() {
return beginTime;
}
public void setBeginTime(Date beginTime) {
this.beginTime = beginTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public void setKeyWordOneDayRequest(boolean isKeyWordOneDayRequest) {
this.isKeyWordOneDayRequest = isKeyWordOneDayRequest;
}
}