业务场景:
如查一个数据集合,第一页至第一百页,返回总页数的总结集,然后导出。
一次需要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>
*
* 应用场景 :1.多线程,每个线程平均任务耗时一样
* 2.需要顺序返回的
*
* 顺序返回,如多个分页,但第一页需要先返回
*
* @author 汪兴安
*
*/
public class ThreadTest {
/**
* 定义线程池
*/
public static ExecutorService executos = Executors.newFixedThreadPool(5);
public static void main(String[] args) {
/**
* 定义集合装结果集
*/
ListtotalList = new ArrayList();
/**
* 定义 Future泛型的集合对象,装多线程的,返回信息
*/
List>> list = new ArrayList>>();
try {
int pageIndex = 0;
int maxPage = 6;
for (pageIndex = 0; pageIndex < maxPage; pageIndex++) {
/**
* executos.submit 返回线程未来结果
*/
Future> future = executos.submit(new DemoThread(pageIndex));
list.add(future);
}
for (Future> 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> {
private int pageIndex;
/**
* 通过构造器,初始化
* @param pageIndex
*/
public DemoThread(int pageIndex) {
this.pageIndex = pageIndex;
}
@Override
public Listcall() throws Exception {
//模拟每个线程执行耗时不一样
if(pageIndex%2==0)
{
Thread.sleep(5000);
}else
{
Thread.sleep(2000);
}
System.out.println("查询第" + pageIndex + "页");
Listlist = new ArrayList();
/**
* 模拟查询的数据对象
*/
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) {
ListtotalList = new ArrayList();
ExecutorService threadPool = Executors.newCachedThreadPool();
CompletionService> cs = new ExecutorCompletionService>(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> future = executos.submit(new DemoThread(pageIndex)); 这种可以保证返回的顺序
CompletionService> cs = new ExecutorCompletionService>(threadPool);,返回不保证顺序,谁先执行完,谁先返回。
效率上CompletionService更高,实际项目需要根据具体业务需求选择。