java 多线程 Callable -- 分段处理一个大的list 然后再合并结果

时间:2022-05-10 22:22:56

本文代码参考 http://bbs.csdn.net/topics/391070227?page=1

java 多线程  Callable  --  分段处理一个大的list 然后再合并结果

下面是贴出的代码:

public void dealListWithMutiThread(){
List<Object> list = new ArrayList<Object>();
int index = ;
ExecutorService ex = Executors.newFixedThreadPool();
int dealSize = ;
List<Future<List<Object>>> futures = new ArrayList<>();
//分配
for(int i=;i<= ;i++,index+=dealSize){
int start = index;
if(start>=list.size()) break;
int end = start + dealSize;
end = end>list.size() ? list.size() : end;
futures.add(ex.submit(new Task(list,start,end)));
}
try {
//处理
List<Object> result = new ArrayList<>();
for(Future<List<Object>> future : futures){
//合并操作
result.addAll(future.get());
}
} catch (Exception e) {
e.printStackTrace();
}
} private class Task implements Callable<List<Object>>{ private List<Object> list;
private int start;
private int end; public Task(List<Object> list,int start,int end){
this.list = list;
this.start = start;
this.end = end;
} @Override
public List<Object> call() throws Exception {
Object obj = null;
List<Object> retList = new ArrayList<Object>();
for(int i=start;i<end;i++){
obj = list.get(i);
//你的处理逻辑
}
//返回处理结果
return retList;
}
}

注: 多线程操作一定比单线程快么?

  多线程编程的目的,就是"最大限度地利用CPU资源",当某一线程的处理不需要占用CPU而只和I/O,OEMBIOS等资源打交道时,让需要占用CPU资源的其它线程有机会获得CPU资源。 所以我开单线程时 cpu占用率可能不会达到100% ,但开多线程 cpu使用率 经常会达到100%;

多线程 和 多进程  
如果采用多进程,那么就需要将线程所隶属的该进程所需要的内存进行切换,这时间代价是很多的。而线程切换代价就很少,线程是可以共享内存的。所以采用多线程在切换上花费的比多进程少得多。
但是,线程切换还是需要时间消耗的,所以采用一个拥有两个线程的进程执行所需要的时间比一个线程的进程执行两次所需要的时间要多一些。即采用多线程不会提高程序的执行速度,反而会降低速度,但是对于用户来说,可以减少用户的响应时间。

综上所述: 如果涉及到 IO等,不是一直占用cpu的操作时,多线程是可以提升效率的; 但是如果只是大量的计算,则多线程的效率会很明显的不如单线程;

下面又粘入了一段 使用 ThreadLocal 的代码 ;
来源:  http://blog.csdn.net/hardworking0323/article/details/52266325
/*
ThreadLocal
它就是一个容器,用于存放线程的局部变量,我认为应该叫做 ThreadLocalVariable(线程局部变量)才对,
真不理解为什么当初 Sun 公司的工程师这样命名。
早在 JDK 1.2 的时代,java.lang.ThreadLocal 就诞生了,
它是为了解决多线程并发问题而设计的,只不过设计得有些难用,所以至今没有得到广泛使用
可以解决同步抢占资源的问题
ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了线程保持对象的方法和避免参数传递的方便的对象访问方式
ThreadLocal的应用场合,最适合的是按线程多实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。
*/
public class DBUtil {
// 数据库配置
private static final String driver = "com.mysql.jdbc.Driver";
private static final String url = "jdbc:mysql://localhost:3306/test";
private static final String username = "root";
private static final String password = "root"; // 定义一个用于放置数据库连接的局部线程变量(使每个线程都拥有自己的连接)
private static ThreadLocal<Connection> connContainer = new ThreadLocal<Connection>(); // 获取连接
public static Connection getConnection() {
Connection conn = connContainer.get();
try {
if (conn == ) {
Class.forName(driver);
conn = DriverManager.getConnection(url, username, password);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
connContainer.set(conn);
}
return conn;
} // 关闭连接
public static void closeConnection() {
Connection conn = connContainer.get();
try {
if (conn != ) {
conn.close();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
connContainer.remove();
}
}
}