多线程下载
一、原理
二、示例代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.shz; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; public class Demo { // 定义将要开启的线程的数量 private static int threadCount = 6; // 正在执行下载任务的线程总数 private static int runningThreadCount = threadCount; public static void main(String[] args) throws Exception { String path = "http://192.168.1.101/MyWebSite/sogou.exe"; URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(5000); conn.setRequestMethod("GET"); int code = conn.getResponseCode(); if (code == 200) { // 获取要下载的文件的大小 int length = conn.getContentLength(); System.out.println("文件大小:" + length); // 在客户端本地创建一个大小跟服务器文件大小一样的临时文件 RandomAccessFile raf = new RandomAccessFile("sogou.exe", "rwd"); raf.setLength(length); // 每个线程下载的部分文件大小(由于可能无法整除,最后一个线程下载的大小不一定为blockSize) int blockSize = length / threadCount; for (int threadId = 1; threadId <= threadCount; threadId++) { int startIndex = (threadId - 1) * blockSize; int endIndex = threadId * blockSize - 1; if (threadId == threadCount) { endIndex = length; } System.out.println("线程" + threadId + ":" + startIndex + "--->" + endIndex); new DownloadThread(path, startIndex, endIndex, threadId).start(); } } else { System.out.println("连接服务器失败"); } } public static String getNowString() { DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return format.format(new Date()); } private static class DownloadThread extends Thread { private String path; private int startIndex; private int endIndex; private int threadId; /** * 子线程下载的构造方法 * * @param path * 要下载的服务器文件路径 * @param startIndex * 开始下载位置 * @param endIndex * 结束下载位置 * @param threadId * 线程Id */ public DownloadThread(String path, int startIndex, int endIndex, int threadId) { this.path = path; this.startIndex = startIndex; this.endIndex = endIndex; this.threadId = threadId; } public void run() { try { // 判断是否存在和当前线程threadId同名的文件名称“x.txt”, // 如果存在,则读取文件中内容,该内容记录了上次线程已下载资源的总长度,那么当前线程开始下载的位置要加上此总长度 File downloadFile = new File(threadId+".txt"); if(downloadFile.exists() && downloadFile.length() > 0) { FileInputStream fis = new FileInputStream(downloadFile); byte[] buffer = new byte[1024]; int len = fis.read(buffer); String strHasDownloadLen = new String(buffer,0,len); System.out.println(getNowString()+":线程"+this.threadId+"上次已下载 "+strHasDownloadLen); this.startIndex += Integer.parseInt(strHasDownloadLen); fis.close(); } System.out.println(getNowString()+":线程"+this.threadId+"开始下载..."); URL url = new URL(this.path); HttpURLConnection conn = (HttpURLConnection) url .openConnection(); conn.setReadTimeout(5000); conn.setRequestMethod("GET"); conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); // 如果是请求全部资源,服务器返回200;如果是请求部分资源,服务器返回206 int code = conn.getResponseCode(); if (code == 206) { InputStream is = conn.getInputStream(); RandomAccessFile raf = new RandomAccessFile("sogou.exe", "rwd"); raf.seek(this.startIndex); int len = 0; int hasDownloadLen = 0; byte[] buffer = new byte[1024]; // 把当前线程已下载的资源总长度写到文件中 File downloadLenFile = new File(threadId+".txt"); while ((len = is.read(buffer)) > 0) { raf.write(buffer, 0, len); // 记录当前线程已下载的资源总长度 hasDownloadLen += len; FileOutputStream fos = new FileOutputStream(downloadLenFile); fos.write(String.valueOf(hasDownloadLen).getBytes()); fos.close(); } is.close(); raf.close(); System.out.println(getNowString()+":线程"+this.threadId+"下载结束..."); } else { System.out.println("线程" + this.threadId + "下载失败,服务器返回错误码:" + code); } } catch (Exception e) { System.out.println("线程" + this.threadId + "下载出现异常:" + e.toString()); } finally { runningThreadCount --; if(runningThreadCount <= 0) { for(int threadId=1;threadId<=threadCount;threadId++) { File file = new File(threadId+".txt"); if(file.exists()) { file.delete(); } } System.out.println(getNowString()+":文件下载结束"); } } } } }