多线程之Future和Callable【高性能应用场景java.util.concurrent】
2017-04-09 17:39
585 查看
业务场景:
如查一个数据集合,第一页至第一百页,返回总页数的总结集,然后导出。
一次需要limit 0 10000,这样,一个SQL查询出非常慢。
但用100个线程,一个线程只查limit0 10 就非常快了,
利用多线程的特性,返回多个集合,在顺序合并成总集合。
下面是concurrent.Future 例子
concurrent.Callable
===================================华丽分割线=================================================================================
总结:两种方式,应用场景不一样
Future<List<User>> future = executos.submit(new DemoThread(pageIndex)); 这种可以保证返回的顺序
CompletionService<List<User>> cs = new ExecutorCompletionService<List<User>>(threadPool);,返回不保证顺序,谁先执行完,谁先返回。
效率上CompletionService更高,实际项目需要根据具体业务需求选择。
如查一个数据集合,第一页至第一百页,返回总页数的总结集,然后导出。
一次需要limit 0 10000,这样,一个SQL查询出非常慢。
但用100个线程,一个线程只查limit0 10 就非常快了,
利用多线程的特性,返回多个集合,在顺序合并成总集合。
下面是concurrent.Future 例子
concurrent.Callable
package com.test.thread; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * Future<List<User>> * * 应用场景 :1.多线程,每个线程平均任务耗时一样 * 2.需要顺序返回的 * * 顺序返回,如多个分页,但第一页需要先返回 * * @author 汪兴安 * */ public class ThreadTest { /** * 定义线程池 */ public static ExecutorService executos = Executors.newFixedThreadPool(5); public static void main(String[] args) { /** * 定义集合装结果集 */ List<User> totalList = new ArrayList<User>(); /** * 定义 Future泛型的集合对象,装多线程的,返回信息 */ List<Future<List<User>>> list = new ArrayList<Future<List<User>>>(); try { int pageIndex = 0; int maxPage = 6; for (pageIndex = 0; pageIndex < maxPage; pageIndex++) { /** * executos.submit 返回线程未来结果 */ Future<List<User>> future = executos.submit(new DemoThread(pageIndex)); list.add(future); } for (Future<List<User>> dataFuture : list) { //// 获得第一个任务的结果,如果调用get方法,当前线程会等待任务执行完毕后才往下执行 totalList.addAll(dataFuture.get()); //dataFuture.get() 这里会阻塞 有顺序的哦 } //得到分页后结果总共集合 for (int i = 0; i < totalList.size(); i++) { System.out.println(totalList.get(i).getName()); } } catch (Exception e) { e.printStackTrace(); } executos.shutdownNow(); } /** * 查询第1页 查询第3页 查询第5页 查询第2页 查询第4页 查询第0页 -----结果会顺序返回,不用你操心顺序问题啦 anan0 anan1 anan2 anan3 anan4 anan5 */ }
package com.test.thread; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; /** * Callable 支持有返回值的多线程 * @author 汪兴安 * */ public class DemoThread implements Callable<List<User>> { private int pageIndex; /** * 通过构造器,初始化 * @param pageIndex */ public DemoThread(int pageIndex) { this.pageIndex = pageIndex; } @Override public List<User> call() throws Exception { //模拟每个线程执行耗时不一样 if(pageIndex%2==0) { Thread.sleep(5000); }else { Thread.sleep(2000); } System.out.println("查询第" + pageIndex + "页"); List<User> list = new ArrayList<User>(); /** * 模拟查询的数据对象 */ User user=new User(); user.setAge(""+pageIndex); user.setName("anan"+pageIndex); list.add(user); return list; } }
===================================华丽分割线=================================================================================
package com.test.thread; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ExecutorService; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutionException; /** * * @author 汪兴安 * 应用场景 :1.每个线程耗时差别大,谁先完成,谁返回 * 对顺序没有要求。 * * * * CompletionService 的性能更高。 * 考虑如下场景:多线程下载,结果用Future返回。 * 第一个文件特别大,后面的文件很小。 * 用方法1,能很快知道已经下载完文件的结果(不是第一个); * */ public class CallableAndFuture { public static void main(String[] args) { List<User> totalList = new ArrayList<User>(); ExecutorService threadPool = Executors.newCachedThreadPool(); CompletionService<List<User>> cs = new ExecutorCompletionService<List<User>>(threadPool); for(int i = 0; i < 6; i++) { cs.submit(new DemoThread(i)); } // 可能做一些事情 for(int i = 0; i < 6; i++) { try { totalList.addAll(cs.take().get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } //得到分页后结果总共集合 for (int i = 0; i < totalList.size(); i++) { System.out.println(totalList.get(i).getName()); } } /** * 查询第3页 查询第1页 查询第5页 查询第2页 查询第0页 查询第4页 anan5 anan1 anan3 anan2 anan0 anan4 */ }
总结:两种方式,应用场景不一样
Future<List<User>> future = executos.submit(new DemoThread(pageIndex)); 这种可以保证返回的顺序
CompletionService<List<User>> cs = new ExecutorCompletionService<List<User>>(threadPool);,返回不保证顺序,谁先执行完,谁先返回。
效率上CompletionService更高,实际项目需要根据具体业务需求选择。
相关文章推荐
- 多线程并发库高级应用 之 java5中的线程并发库--线程池、Callable&Future
- 【多线程】java.util.concurrent.Exchanger应用范例与原理浅析
- java多线程学习-java.util.concurrent详解(二)Semaphore/FutureTask/Exchanger
- java.util.concurrent.Callable, Runnable, Future,ExecutorService介绍
- JAVA---多线程之Callable与Future,FutureTask,及其简单应用
- java多线程学习-java.util.concurrent详解(二)Semaphore/FutureTask/Exchanger
- Java多线程与并发库高级应用之Callable和Future
- 多线程并发库高级应用 之 java5中的线程并发库--线程池、Callable&Future
- java多线程之线程并库Callable与Future的应用
- Java多线程与并发应用-(8)-Callable和Future
- Java.util.concurrent 包 使用Future,Callable实现抢答模式
- Java多线程与并发库高级应用-Callable与Future的应用
- java多线程并发库高级应用 之 java5中的线程并发库--线程池、Callable&Future
- java多线程学习-java.util.concurrent详解(二)Semaphore/FutureTask/Exchanger
- java多线程学习-java.util.concurrent详解(二)Semaphore/FutureTask/Exchanger
- java.util.concurrent中的Callable,Future
- java多线程学习-java.util.concurrent详解(二)Semaphore/FutureTask/Exchanger
- [转载] java多线程学习-java.util.concurrent详解(二)Semaphore/FutureTask/Exchanger
- java.util.concurrent包(4)――Callable和Future
- java.util.concurrent包(4)——Callable和Future