先说下使用场景:
由于业务需要,要从服务器下载约50G文件,首先想到的是多线程,于是自己写了个多线程就开始跑。这样做会有什么问题?
1.开多少线程合适10个?20个?我自己测了测,下载速度都不理想,应该和机器配置有关。
2.假如开了20,或者50个,后期切换维护是不是也很花时间?
所以就用到了线程池,可以让线程池来根据任务动态的管理调度线程。
实现方式:
首先是线程池的配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!--<context:property-placeholder location="mongo.properties"/>-->
<bean id="threadPoolTaskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<!-- 核心线程数,默认为1 -->
<property name="corePoolSize" value="10" />
<!-- 最大线程数,默认为Integer.MAX_VALUE -->
<property name="maxPoolSize" value="50" />
<!-- 队列最大长度,一般需要设置值>=notifyScheduledMainExecutor.maxNum;默认为Integer.MAX_VALUE-->
<property name="queueCapacity" value="1000" />
<!-- 线程池维护线程所允许的空闲时间,默认为60s -->
<property name="keepAliveSeconds" value="60" />
<!-- 线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy、CallerRunsPolicy;默认为后者 -->
<property name="rejectedExecutionHandler">
<!-- AbortPolicy:直接抛出java.util.concurrent.RejectedExecutionException异常 -->
<!-- CallerRunsPolicy:主线程直接执行该任务,执行完之后尝试添加下一个任务到线程池中,可以有效降低向线程池内添加任务的速度 -->
<!-- DiscardOldestPolicy:抛弃旧的任务、暂不支持;会导致被丢弃的任务无法再次被执行 -->
<!-- DiscardPolicy:抛弃当前任务、暂不支持;会导致被丢弃的任务无法再次被执行 -->
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" />
</property>
</bean>
</beans>
接着是单个线程代码的编写,每一个线程要做的工作。
public class DownloadThreadUtiil implements Runnable{
private String url;
public DownloadThreadUtiil(String url){
this.url = url;
}
@Override
public void run() {
Utiil utiil = new Util();
utiil.downLoadFile(url);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
最后在主线程中读取线程池配置,执行任务。
List<String> list = utiil.getfileNames(url);
ApplicationContext context = new ClassPathXmlApplicationContext("/config.xml");
ThreadPoolTaskExecutor taskExecutor =
(ThreadPoolTaskExecutor)context.getBean("threadPoolTaskExecutor");
String foldName = "E:/"+"tarFile/";
utiil.mkFolder(foldName);
for(int i = 0; i < list.size(); i++){
DownloadThreadUtiil downloadThread = new DownloadThreadUtiil(url);
taskExecutor.execute(downloadThread);
}
long start = System.currentTimeMillis();
while (true){
int count = taskExecutor.getActiveCount();
System.out.println("Active Threads : " + count);
try{
Thread.sleep(1000);
}catch(InterruptedException e){
e.printStackTrace();
}
if(count==0){
taskExecutor.shutdown();
long end = System.currentTimeMillis();
System.out.println("totalTime:"+(end-start)/1000 +"s");
break; //所有线程任务执行完
}
}