1. 程式人生 > >實現多執行緒下載同一個檔案

實現多執行緒下載同一個檔案

原理:
示例程式碼:
public class LoadFile {

	private static int threadCount = 3;// 下載的執行緒數量

	public static void main(String[] args) {
		
		// 1、與伺服器建立連線,獲得檔案的大小,在本地建立一個與需下載檔案同等大小的臨時檔案
		String path = "http://localhost/safe.exe";
		try {
			URL url = new URL(path);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("GET");
			conn.setReadTimeout(5000);
			
			int code = conn.getResponseCode();
			if(200 == code) {
				// 獲得檔案的長度
				int length = conn.getContentLength();
				System.out.println("檔案總長度為:"+length);
				// 在本地建立一個可以隨機讀取的與原始檔同等大小的臨時檔案
				RandomAccessFile raf = new RandomAccessFile("safe.exe", "rwd");
				// 指定檔案的長度
				raf.setLength(length);// 設定檔案長度
				raf.close();
				
				// 2、實現多執行緒下載資源
				int blockSize = length / threadCount ;// 每個執行緒平均需要下載檔案的大小
				for(int threadId = 1; threadId <= threadCount; threadId++) {
					// 每個執行緒下載檔案的初始位置和結束位置
					int startIndex = (threadId-1) * blockSize;
					int endIndex = threadId * blockSize - 1;
					// 下載的最後一塊的情況
					if(threadCount == threadId) {
						endIndex = length - 1;// 如果不減1的話,就超出了檔案的範圍
					}
					System.out.println("執行緒 "+threadId+"下載位置為:"+startIndex+"--->"+endIndex);
					// 啟動下載執行緒
					new DownloadThread(path, startIndex, endIndex, threadId).start();
				}
				
			} else {
				System.out.println("伺服器出現錯誤");
			}
			
		} catch (Exception e) {
			System.out.println("連線伺服器URL出現錯誤");
			e.printStackTrace();
		}
		
	}

}

public class DownloadThread extends Thread {

	private String path;// 伺服器路徑
	private int startIndex;// 塊檔案開始位置
	private int endIndex;// 快檔案結束位置
	private int threadId;// 執行緒編號

	public DownloadThread() {

	}

	public DownloadThread(String path, int startIndex, int endIndex, int threadId) {
		this.path = path;
		this.startIndex = startIndex;
		this.endIndex = endIndex;
		this.threadId = threadId;
	}

	@Override
	public void run() {
		try {
			URL url = new URL(path);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("GET");
			conn.setReadTimeout(5000);
			// 提交請求可以從指定位置讀取檔案
			conn.setRequestProperty("Range", "bytes=" + startIndex + "-"
					+ endIndex);
			int code = conn.getResponseCode();
			// 請求全部檔案成功返回200, 請求部分檔案成功返回206
			if (206 == code) {
				RandomAccessFile raf = new RandomAccessFile("safe.exe", "rwd");
				// 隨機檔案從哪裡讀
				raf.seek(startIndex);// 定位檔案

				InputStream is = conn.getInputStream();
				int len = 0;
				byte[] buffer = new byte[1024];
				while ((len = is.read(buffer)) != -1) {
					raf.write(buffer, 0, len);
				}
				
				is.close();
				raf.close();
				System.out.println("執行緒" + threadId + "下載完畢!!!!");
			} else {
				System.out.println("執行緒"+threadId+"請求的部分資源失敗");
			}

		} catch (Exception e) {
			System.out.println("下載執行緒的URL連線異常");
			e.printStackTrace();
		}
	}

}
// 別下載太大的檔案,可能等待時間很長
/*Output:
檔案總長度為:11556608
執行緒 1下載位置為:0--->3852201
執行緒 2下載位置為:3852202--->7704403
執行緒 3下載位置為:7704404--->11556607
執行緒2下載完畢!!!!
執行緒1下載完畢!!!!
執行緒3下載完畢!!!!
*/