多线程实现下载文件带返回值
这一篇说的是多线程Callable ,Callable 实现的线程是可以实现有返回值的。
下面将全面啊讲述使用多线程下载网页图片的一个小案例
- 先创建一个StartThreadCallable 线程类 实现 Callable
参数 allUrl:网络地址多个用逗号隔开,可以根据你的需求进行修改
filepat:本地保存的路径地址 例:D:/img
taskNumber:此方法是在那个线程下运行的
@SuppressWarnings("all")
public class StartThreadCallable implements Callable<Object>{
private String allUrl;
private String filepath;
private int taskNumber; //第几个线程
public StartThreadCallable(String allUrl,String filepath,int taskNumber) {
this.allUrl=allUrl;
this.filepath=filepath;
this.taskNumber=taskNumber;
}
public Object call() throws Exception {
System.out.println("callable 带返回值多线程 启动 ---参数 allUrl--> "+ allUrl+"--filepath--"+filepath );
String retMsg="";
String stringArray[]= this.allUrl.split(",");
for (int i = 0; i < stringArray.length; i++) {
System.err.println("多线程执行方法"+taskNumber);
if(retMsg.length()>0){
retMsg+=",";
}
retMsg+=download(stringArray[i],filepath);
}
System.out.println("线程返回内容-->"+retMsg);
return retMsg;
}
/**
*
* @param downUrl
* @param filepath
* @return
*/
private String download(String downUrl ,String filepath){
String fileName="";
System.out.println();
URL url=null;
try {
if(downUrl.length()>0){
fileName=taskNumber+"-"+downUrl.substring(downUrl.lastIndexOf("/")+1);
//网络图片路径下载
url = new URL(downUrl);
DataInputStream dataInputStream = new DataInputStream(url.openStream());
//本地路径图片路径
filepath =filepath+"/"+fileName;
//输出流
FileOutputStream fileOutputStream = new FileOutputStream(new File(filepath));
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = dataInputStream.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
byte[] context=output.toByteArray();
fileOutputStream.write(output.toByteArray());
dataInputStream.close();
fileOutputStream.close();
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("下载图片出错");
fileName="";
}
return fileName;
}
}
- 创建CreatThreadCallable 类,用来实现创建多个线程使用
参数allUrl:是一个数组,我是用的数组的长度来创建的线程的长度,一般不建议,如果数组长度过大,会造高并发问题。
filePath 本地文件路径
taskSize 要创建的线程数,下面会由数组长度覆盖这个值(不建议这样写)
注意:不要在创建多线程的for 循环中 做输出语句以及对线程返回值的处理,这样会把多线程变成单线程,这样多线程就毫无意义啦,可以通过 list.add(f); 直接把返回值存到 list中在下面再写一个for循环进行逻辑的操作,这样就避免啦多线程变单线程。
public class CreatThreadCallable {
public String createThreadCallable(String[] allUrl,String filePath,int taskSize) {
String stringArray="";
try {
System.err.println("----进入线程 创建方法----");
//可以给根据 数组的长度 来 创建线程数量 也可以 写固定值
taskSize=allUrl.length;
// 创建一个线程池 taskSize 线程数量
ExecutorService pool = Executors.newFixedThreadPool(taskSize);
// 创建多个有返回值的任务
List<Future> list = new ArrayList<Future>();
for (int i = 0; i < taskSize; i++) {
Callable c = new StartThreadCallable(allUrl[i],filePath,i);
// 执行任务并获取Future对象
Future f = pool.submit(c);
list.add(f);
}
// 执行完线程 关闭线程池
pool.shutdown();
// 获取所有并发任务的运行结果
for (Future f : list) {
// 从Future对象上获取任务的返回值,并输出到控制台
//System.out.println(">>>" + f.get().toString());
if(stringArray.length()>0){
stringArray+=",";
}
stringArray+=f.get().toString();
}
} catch (Exception e) {
e.printStackTrace();
}
return stringArray;
}
}
- 创建实体类进行测试
我这就直接用数组放图片地址,多个地址用逗号隔开。
public class text {
public static void main(String[] args) {
try {
CreatThreadCallable creatThreadCallable=new CreatThreadCallable();
String[] allUrl=new String[3];
allUrl[0]="http://img.tupianzj.com/uploads/allimg/140418/3-14041Q43F40-L.jpg,http://img.tupianzj.com/uploads/allimg/140319/4-1403191055450-L.jpg,http://img.tupianzj.com/uploads/allimg/131120/3-1311200954320-L.jpg";
allUrl[1]="http://img.tupianzj.com/uploads/allimg/130802/4-130P21036010-L.jpg";
allUrl[2]="http://img.tupianzj.com/uploads/allimg/180523/9-1P5231000080-L.jpg,http://img.tupianzj.com/uploads/allimg/140604/3-1406041414480-L.jpg,http://img.tupianzj.com/uploads/allimg/171017/9-1G01G15T00-L.jpg,http://img.tupianzj.com/uploads/allimg/170805/9-1FP51IA80-L.jpg,http://img.tupianzj.com/uploads/allimg/180522/9-1P5221631200-L.jpg,http://img.tupianzj.com/uploads/allimg/180331/9-1P3311131060-L.jpg,http://img.tupianzj.com/uploads/allimg/160724/9-160H41A4550-L.jpg,http://img.tupianzj.com/uploads/allimg/150317/7-15031G511460-L.jpg,http://img.tupianzj.com/uploads/allimg/180202/9-1P2021AS60-L.jpg,http://img.tupianzj.com/uploads/allimg/180202/9-1P2021A5070-L.jpg";
String stringArray=creatThreadCallable.createThreadCallable(allUrl,"D:/临时/threadimg/",3);
String[] strA=stringArray.split(",");
for (int i = 0; i < strA.length; i++) {
System.out.println("main----"+strA[i]);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
这就是简单的使用多线程下载文件,并且会有返回值的全部操作。具体应用的时候需要加上一些报错的处理等操作,
想要免费学习dubbo分布式开发,以及redis共享session等学习资料可以通过微信进行扫码获取