最近几天写我的自己的项目的时候用到数据的实例化,这个要求多张表查询数据源,当时我是想的直接按照顺序进行查询然后在通过map集合返回到前台,但是感觉这样数据量一高 估计前端等待时间有点久。所以我想起用多线程的方式去同时查询数据返回。
* 类名称:ThreadPoolUtil
* 类描述:线程池查询
* 创建人:fulln
* 创建时间:2018年1月25日 下午7:15:22
* @version
*
*/
public class ThreadPoolUtil{
private static final Logger log = Logger.getLogger(ThreadPoolUtil.class);
ThreadPoolExecutor executor = new ThreadPoolExecutor(5,8, 3000, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(2000)) {
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
printException(r, t);
}
};
LinkedBlockingQueue<Runnable> queue = (LinkedBlockingQueue<Runnable>) executor.getQueue();
List<ThreadEntity> li = new ArrayList<ThreadEntity>();//查询的参数list
Method refle ;
public void getStart() {
Integer countTool = li.size();//决定要启动的线程数量
final CountDownLatch countDownLatch = new CountDownLatch(countTool);//线程计数器
final List<ThreadEntity> Threadli = new ArrayList<ThreadEntity>();//查询的参数list
Threadli.addAll(li);
for ( int i =0 ;i<Threadli.size();i++) {//开始开辟线程
final Object oc = ApplicationContextProvider.getBean(Threadli.get(i).getClazz());
Map<String,Object> map = new HashMap<String, Object>();
List<Object> resultli = new ArrayList<>();
Class<? extends Object> tgg = oc.getClass();
Method[] me = tgg.getDeclaredMethods();
String name = Threadli.get(i).getMethodName();
map = Threadli.get(i).getCondition();
for (Method method : me) {
if(name!=null && method.getName().equals(name)) {
if(!method.isAccessible()) { //判断是不是公共方法
method.setAccessible(true);
}
Parameter[] p = method.getParameters();
for (int j = 0; j < (p==null?0:p.length); j++) { // 将参数全部取出来
for (Entry<String, Object> e :map.entrySet()) {
if( e.getKey().equals(p[j].getName())) {//1.8提供的新方法可以取出参数名
resultli.add(e.getValue());
}
}
}
setRefle(method);
}
}
executor.execute(new Runnable() {
@Override
public void run() {
meta(oc,resultli.toArray());
countDownLatch.countDown();
}
});
}
try {
countDownLatch.await();
found();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void meta(Object oc, Object[] objects) {}
public void found() {}
private static void printException(Runnable r, Throwable t) {
if (t == null && r instanceof Future<?>) {
try {
Future<?> future = (Future<?>) r;
if (future.isDone())
future.get();
} catch (CancellationException ce) {
t = ce;
} catch (ExecutionException ee) {
t = ee.getCause();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt(); // ignore/reset
}
}
if (t != null)
log.error(t.getMessage(), t);
}
public Method getRefle() {
return refle;
}
public void setRefle(Method refle) {
this.refle = refle;
}
public List<ThreadEntity> getLi() {
return li;
}
}
这个是util类,要想完成功能还要一个类去继承它
/**
*
* 项目名称:QueryDAO
* 类名称:ThreadDemo
* 类描述:一个多线程连接的sql查询demo
* 创建人:fulln
* 创建时间:2018年1月22日 上午11:17:06
* @version
*
*/
public class ThreadDemo extends ThreadPoolUtil{
private WideCls<?> wide;
public WideCls<?> getWide() {
return wide;
}
public void setWide(WideCls<?> wide) {
this.wide = wide;
}
ConcurrentLinkedQueue<User> cqli = new ConcurrentLinkedQueue<User>();//线程安全的list集合
List<User> usLi = new ArrayList<User>();//装载list返回值集合
/**
* setCondition(设置传入的参数)
* TODO()
* @param name
* @param clazz
* @param map
* void
* 2018-01-25
*/
public void setCondition(String name,Class<?> clazz,Map<String,Object> map) {
usLi = new ArrayList<User>();
ThreadEntity tey = new ThreadEntity();
tey.setMethodName(name);
tey.setClazz(clazz);
tey.setCondition(map);
getLi().add(tey);
}
@Override
public void meta(Object oc, Object[] objects) {
try {
User u = (User)getRefle().invoke(oc, objects);
cqli.add(u);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void found() {
usLi.addAll(cqli);
}
public List<User> getUsLi() {
return usLi;
}
public void setUsLi(List<User> usLi) {
this.usLi = usLi;
}
}
然后是测试类
@Test
public void testThread() {
ThreadDemo t = new ThreadDemo();
t.setWide(new WideCls<User>());
Map<String, Object> map = new HashMap<String, Object>();
map.put("tableName", "user_emp");
map.put("userId",1);
t.setCondition("findUserByUserid", regService.getClass(), map);
t.setCondition("findUserByName", regService.getClass(), map);
t.getStart();
List<User> li = t.getUsLi();//获得结果值
for (User user : li) {
System.out.println(user);
}
}
参数实体类
public class ThreadEntity{
private String MethodName;
private Class<?> clazz;
private Map<String, Object> condition;
public String getMethodName() {
return MethodName;
}
public void setMethodName(String methodName) {
MethodName = methodName;
}
public Class<?> getClazz() {
return clazz;
}
public void setClazz(Class<?> clazz) {
this.clazz = clazz;
}
public Map<String, Object> getCondition() {
return condition;
}
public void setCondition(Map<String, Object> condition) {
this.condition = condition;
}
// public T getConditionEntity() {
// return conditionEntity;
// }
// public void setConditionEntity(T conditionEntity) {
// this.conditionEntity = conditionEntity;
// }
}
讲下写的时候遇见的问题
1,我写第一个demo的时候是直接用的dao层,这导致了一个问题, 我后来想去抽离实体 泛型的时候 dao层写不了反射,因为我用的mybatis注解,dao层直接连接orm了,这样耦合度就有点高了
2.我改用service层后。开始用反射的形式来抽离代码,发现invoke()不能成功,dao层显示为null, 这里我知道是没有引入spring的bean,然后改用获取ApplicationContext的形式获取class对象
@Component
public class ApplicationContextProvider implements ApplicationContextAware{
private static ApplicationContext applicationContext;
public static Object getBean(String name){
return getApplicationContext().getBean(name);
}
public static <T> T getBean(Class<T> clazz){
return getApplicationContext().getBean(clazz);
}
public static <T> T getBean(String name,Class<T> clazz){
return getApplicationContext().getBean(name, clazz);
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//
this.applicationContext = applicationContext;
}
}
直接获取了spring里面的对象后才行
3.当我开启线程时发现主线程等待,threadpoolexcuter 一直处于inwork,debug模式下跳转afterExecute()方法,后面进入死循环出不来,然后在网上找原因,看到一篇说要重写afterExecute()方法的,不然错误在子线程被捕获传入exception类中出不来。这个方法实行后发现并没有报错,我百度了很久,一直没有头绪,最后我想到个方法,因为一开始我用dao层写的时候是能够开启多线程查询的,我开始注释多线程方法里面的代码,看到底是哪一块导致了线程的等待,于是发现我的excute方法在2个for循环里面,虽然我在第二个for循环里面写了条件,满足条件才能开启线程,但是他还是显示是这个多for循环的问题, 于是我将excute提出到最外层for循环中,运行成功。
4. 目前最大的问题是泛型的问题。 由此我只能用map的形式来接受条件,我想象中的最终版本是暴露借口填参数的形式,但是能力问题,一直不能解决泛型实体类,泛型实体类里面的泛型list,泛型queue,invoke的方法返回的类型也没能够用泛型的形式去接收。那就只能在demo中多写一系列代码,这很不爽,我这么懒的人也只能将就,等以后技术好点了再去改。
参考文章:
http://www.jb51.net/article/47300.htm