1.开启三个下载线程;
2.开启一个监视线程,用于查看下载进度。
完整代码
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
public class JavaMultiThreadDown {
public static void main(String[] args) throws Exception {
// 下载路径使用的是百度网盘上文件的下载路径
String _下载路径 = "https://bjbgp01.baidupcs.com/file/1d9cedae59e9042a85cb0b98b4340c9c?bkt=p3-00007b4ef6ea09a0f17a89712f670b4985c6&fid=3255250463-250528-363978972781448&time=1554510897&sign=FDTAXGERQBHSKfW-DCb740ccc5511e5e8fedcff06b081203-1Sm5YGIZMjBwhUyJY4n2UBJLkJ0%3D&to=75&size=5528379&sta_dx=5528379&sta_cs=0&sta_ft=pdf&sta_ct=0&sta_mt=0&fm2=MH%2CQingdao%2CAnywhere%2C%2Chubei%2Cpbs&ctime=1554510826&mtime=1554510826&resv0=cdnback&resv1=0&vuk=3255250463&iv=2&htype=&newver=1&newfm=1&secfm=1&flow_ver=3&pkey=00007b4ef6ea09a0f17a89712f670b4985c6&expires=8h&rt=sh&r=458234945&mlogid=2211612084113124362&vbdid=1929586120&fin=%E4%B8%8B%E8%BD%BD%E6%B5%8B%E8%AF%95.pdf&fn=%E4%B8%8B%E8%BD%BD%E6%B5%8B%E8%AF%95.pdf&rtype=1&dp-logid=2211612084113124362&dp-callid=0.1.1&hps=1&tsl=0&csl=0&csign=4j3EXxSQdY9W8SenN6CIXXqjvfE%3D&so=0&ut=1&uter=4&serv=0&uc=4192912830&ti=90e00819b6f54250603b4062c17fc35df0cc8c47b8fc9467&by=themis";
String _本地文件 = "有那种网站嘛?有,还是合集哦.pdf";
int _线程数量 = 3;
// 初始化DownUtil对象
final Downloader downLoader = new Downloader(_下载路径, _本地文件, _线程数量);
// 开始下载
downLoader.download();
}
}
class Downloader {
private String netUrl;// 下载资源的路径
private String saveFile;// 下载的路径(含文件名)
private int threadNum;// 线程数量
private DownLoaderThread[] threads;// 线程数组
private int fileSize;// 下载的文件的Size
public Downloader(String netUrl, String targetFile, int threadNum) {
this.netUrl = netUrl;
this.saveFile = targetFile;
this.threadNum = threadNum;
// 初始化线程数组
this.threads = new DownLoaderThread[threadNum];
}
public void download() throws Exception {
URL url = new URL(netUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5 * 1000);
conn.setRequestMethod("GET");
fileSize = conn.getContentLength();
System.out.println("待下载文件的大小为:" + (double) (fileSize / 1024) / 1024 + "M");
conn.disconnect();
// 分部下载
int currentPartSize = fileSize / threadNum + 1;
RandomAccessFile file = new RandomAccessFile(saveFile, "rw");
// 设置本地文件大小
file.setLength(fileSize);
file.close();
// 开启下载线程
for (int i = 0; i < threadNum; i++) {
// 计算每条线程的下载的开始位置
int startPos = i * currentPartSize;
// 每个线程使用一个RandomAccessFile进行下载
RandomAccessFile currentPart = new RandomAccessFile(saveFile, "rw");
// 定位线程的下载位置
currentPart.seek(startPos);
// 创建下载线程
threads[i] = new DownLoaderThread(startPos, currentPartSize, currentPart);
// 启动下载线程
threads[i].start();
}
Thread overseer = new Thread(new Overseer(this));
overseer.start();
}
private class DownLoaderThread extends Thread {
private int startPos;// 当前线程的下载位置
private int currentPartSize;// 当前线程负责下载的文件大小
private RandomAccessFile currentPart;// 当前线程需要下载的文件块
public int length;// 该线程已下载的字节数
public DownLoaderThread(int startPos, int currentPartSize, RandomAccessFile currentPart) {
this.startPos = startPos;
this.currentPartSize = currentPartSize;
this.currentPart = currentPart;
}
@Override
public void run() {
try {
URL url = new URL(netUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5 * 1000);
conn.setRequestMethod("GET");
InputStream inStream = conn.getInputStream();
// 跳过不需要下载的部分
inStream.skip(this.startPos);
byte[] buffer = new byte[1024];
int hasRead = 0;
// 读取网络数据,并写入本地文件
while (length < currentPartSize && (hasRead = inStream.read(buffer)) != -1) {
currentPart.write(buffer, 0, hasRead);
// 累计该线程下载的总大小
length += hasRead;
}
currentPart.close();
inStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private class Overseer implements Runnable {
Downloader downLoader;
Overseer(Downloader downLoader) {
this.downLoader = downLoader;
}
@Override
public void run() {
double p;
while ((p = getCompleteRate()) < 100) {
// 隔段时间查询一次任务完成进度,
System.out.println("已完成:" + p + "%");
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("下载完毕");
}
// 获取下载的完成百分比
private double getCompleteRate() {
// 统计多条线程已经下载的总大小
int sumSize = 0;
for (int i = 0; i < threadNum; i++) {
sumSize += threads[i].length;
}
// 返回已经完成的百分比
int percent = (int) (sumSize * 100.0 / fileSize);
return percent;
}
}
}
运行结果
待下载文件的大小为:5.271484375M
已完成:0.0%
已完成:3.0%
已完成:13.0%
已完成:21.0%
已完成:29.0%
已完成:33.0%
已完成:35.0%
已完成:50.0%
已完成:64.0%
已完成:66.0%
已完成:66.0%
已完成:66.0%
已完成:66.0%
已完成:66.0%
已完成:73.0%
已完成:90.0%
下载完毕