您的位置:首页 > 理论基础 > 计算机网络

多线程下载网络资源

2015-03-11 23:43 183 查看
创建多个线程在单位时间内便可以获得更多的服务端资源,可以加快下载速度。但是也并不是线程越多越好,假设我们在客户端新建了10000个线程,此时服务端的CPU就会在线程间的轮询切换上消耗大量的时间,而真正用来下载数据资源的时间就会减少。同时,由于客户端和服务端物理带宽的限制,下载速度也会受到极大的关联。

下面我将用多线程下载网络上的资源,代码如下:

package hxl.insist.two;

import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.CountDownLatch;

/**
* 多线程从网络服务器上下载资源
* @author Hanxl
*/
public class MultiThreadDownload {
/**
* 下载的线程数量
*/
private int threadCount;

/**
* 资源的Url路径
*/
private String resourcePath;

/**
* 保存到本地的文件名
*/
private String fileName;

/**
* 锁存器,判断所有子线程是否运行完毕
*/
final CountDownLatch cdl = new CountDownLatch(threadCount);

public MultiThreadDownload(int threadCount,String resourcePath,String fileName) {
this.threadCount = threadCount;
this.resourcePath = resourcePath;
this.fileName = fileName;
}

/**
* 在本地创建一个和网络资源相同大小的文件
* @return 网络资源文件大小
*/
private int createLocalFile() throws Exception {
URL url = new URL(resourcePath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//将请求方式设为Get
conn.setRequestMethod("GET");
//设置请求超时时间
conn.setConnectTimeout(5000);
//获取响应的状态码
int statusCode = conn.getResponseCode();
int resourceSize = 0;
if(statusCode == 200) {
//取得网络资源文件的大小
resourceSize = conn.getContentLength();
//在本地创建一个和网络资源相同大小的文件
RandomAccessFile localFile = new RandomAccessFile(fileName, "rw");
localFile.setLength(resourceSize);
}
return resourceSize;
}

/**
*	创建线程并从网络上开始下载资源
*/
private void createThreadAndDownload(final int startIndex,final int endIndex) {
new Thread(new Runnable() {
@Override
public void run() {
try {
URL url = new URL(resourcePath);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
//为服务器指定下载的资源是哪一部分
conn.setRequestProperty("Range", "bytes=" + startIndex + "-"+endIndex);
//206表示请求部分数据成功
int code = conn.getResponseCode();
if(code == 206) {
RandomAccessFile localFile = new RandomAccessFile(fileName, "rw");
InputStream is = conn.getInputStream();
localFile.seek(startIndex);
System.out.println(Thread.currentThread().getName() + " : " + "开始下载" + startIndex + "---" + endIndex);
int len = -1;
byte[] bufferArea = new byte[1024];
while((len = is.read(bufferArea)) != -1) {
localFile.write(bufferArea, 0, len);
}
is.close();
localFile.close();
//递减锁存器的计数,如果计数到达零,则释放所有等待的线程。
cdl.countDown();
System.out.println(Thread.currentThread().getName() + " : " + "下载完毕");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
}).start();
}

/**
* 让程序开始从网络上下载资源
*/
public void startDownload() throws Exception {
int resourceSize = createLocalFile();
if(resourceSize != 0) {
//将资源大小按线程数量等分
int resourceAverageSize = resourceSize / threadCount;
for(int threadIndex = 0;threadIndex < threadCount;threadIndex++) {
//为每个线程指定下载位置
final int startIndex = threadIndex * resourceAverageSize;
int endIndex = startIndex + resourceAverageSize - 1;
if(threadIndex == (threadCount - 1)) {
endIndex = resourceSize - 1;
}
createThreadAndDownload(startIndex,endIndex);
}
}

while (true) {
//直到锁存器倒计数至零之前一直等待
cdl.await();
break;
}
}

public static void main(String[] args) {
try {
if(args.length == 3) {
MultiThreadDownload mtd = new MultiThreadDownload(Integer.parseInt(args[0]),args[1],args[2]);
mtd.startDownload();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}


如果在有足够带宽的情况下,适当增加线程的个数,确实是加快了下载的速度。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: