最近项目上有个需求,需要从FTP服务器中下载大批量的数据文件,然后解析该数据文件进行入库,数据库为oracle,最后在通过web工程,以报表和图表的形式进行展现。
这些批量的数据文件为纯文本文件,每天产生数据文件大概有1500个,每个文件大概有500KB,且随着时间的推移这些数据文件会逐渐增多。
之前的实现方式是,通过每天按时触发,建立一个FTP连接,使用这个连接读取文件,读取一个下载一个。部署到生成环境后,测试发现全部完成后,需要7个小时,如果文件随时间的增长,显然是不能接受的。
因此,这里需要改成多线程来处理,这样就可以缩短读取的时间,这里做了个案例,用来套用到修改的程序中,案例代码如下:
实现代码:package com.what21.thpool;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadPoolExecutor.AbortPolicy;
public class ThreadPoolMain {
/**
* @param args
*/
public static void main(String[] args) {
//线程池维护线程的最少数量
int corePoolSize = 50;
//线程池维护线程的最大数量
int maximumPoolSize = Integer.MAX_VALUE;
//线程池维护线程所允许的空闲时间
long keepAliveTime = 4;
//线程池维护线程所允许的空闲时间的单位
TimeUnit unit = TimeUnit.SECONDS;
BlockingQueue taskQueue = new ArrayBlockingQueue(10);
// AbortPolicy 策略
// 处理程序遭到拒绝将抛出运行时RejectedExecutionException
AbortPolicy handler = new ThreadPoolExecutor.AbortPolicy();
// 初始化线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
keepAliveTime, unit, taskQueue, handler);
// 线程池执行
for(int i=0;i<1000;i++){
final int count = i;
threadPool.execute(new Thread(new Runnable(){
@Override
public void run() {
try {
Thread.sleep(1*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(count);
}
}));
}
}
}
执行流程描述:
1、线程池threadPool初始化时,任务队列taskQueue中的线程为空,线程池是不会马上执行的。
2、当调用 线程池threadPool的execute()方法时,添加一个线程,线程池会做出如下的判断:
a、如果当前正在运行的线程数量小于corePoolSize,就立即创建并执行这个线程;
b、如果当前正在运行的线程数量大于或等于corePoolSize,新添加的线程会放入队列;
c、如果队列满了,正在运行的线程数量小于 maximumPoolSize,就继续创建线程运行这个任务;
d、如果队列满了,正在运行的线程数量大于或等于 maximumPoolSize,线程池threadPool会抛出不能接受新任务的异常。
3、当一个线程完成任务时,它会从队列taskQueue中取出一个任务来进行执行。
4、当一个线程执行完毕时,超过一定的时间keepAliveTime时,线程池threadPool会判断,如果当前池中运行的线程数大于corePoolSize,那么这个线程就被停掉。线程池threadPool的所有任务完成后,它最终会收缩到corePoolSize的大小。
通过使用上述原理的多线程功能实现,且每次都有50个线程并发执行,测试后,发现大大的降低了执行时间,变成了2个多小时,实践证明多线程就是好!!!