线程池的使用框架
来源:互联网 发布:mysql 阻止连接半小时 编辑:程序博客网 时间:2024/05/22 22:45
线程池可以认为是回调的方式。将匿名内部类传递给调用的线程。等线程池做完后,就可以调用内部类的方法。
下面代码展示了一个请求(实际上是会有多个请求,这里只做一个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; }}
- 线程池的使用框架
- 通用的线程池框架
- Executor框架的线程池
- 线程池的原理以及java的线程池框架
- 线程池的原理以及Java的线程池框架
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 线程池的使用
- 自定义ViewGroup——圆形排列LinearLayout
- response.sendRedirect无法传递中文参数的问题
- Android属性动画
- AR Face Database 人脸识别数据集
- 服务器使用json时报错java.lang.ClassNotFoundException: org.json.JSONException
- 线程池的使用框架
- Java并发编程(四)Java内存模型
- 随便收集
- 深入理解java异常处理机制
- CSS应用:复杂背景图案
- oracle全文检索功能
- java的动态代理机制详解
- ReactiveCocoa之RAC合并(九)
- java中的多态