マルチスレッドダウンロードネットワークリソース

3978 ワード

複数のスレッドを作成すると、単位時間でより多くのサービス・エンド・リソースが得られ、ダウンロードが高速化されます.しかし、スレッドが多ければ多いほど良いわけではありません.クライアントに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();
		}
	}
}

十分な帯域幅がある場合、スレッドの個数を適切に増やせば、ダウンロードの速度が確実に速くなります.