java分片下载核心是用callable配合线程池,按range头切分字节范围并行下载,通过randomaccessfile定位写入,invokeall聚合结果,校验总大小与哈希值确保完整性。

Java中用Callable配合线程池实现分片下载,核心是把文件按字节范围切分成多个任务,每个任务独立下载一段并返回实际写入长度或校验结果,主线程汇总后合并文件。关键在于HTTP Range头的正确设置、随机访问文件写入的线程安全、以及异常时的重试与偏移对齐。
分片策略与Range请求构造
根据文件总大小(需先HEAD请求获取Content-Length)计算每片字节数(如1MB),生成start和end偏移。注意:HTTP Range是闭区间,bytes=0-1023表示前1024字节。
- 最后一片的
end应设为fileSize - 1,避免越界 - 每个
Callable任务封装一个URL、start、end及本地RandomAccessFile句柄(或共享通道) - 务必设置连接超时、读取超时,并捕获
IOException和InterruptedException
Callable任务编写要点
实现Callable<long></long>,返回本片成功写入的字节数(用于后续校验)。不要在任务内创建新线程或阻塞等待,所有I/O需带超时。
- 打开
HttpURLConnection,调用setRequestProperty("Range", "bytes="+start+"-"+end) - 用
RandomAccessFile定位到start位置(seek(start)),再循环write(),避免覆盖其他分片 - 返回
end - start + 1(理论值)或实际写入字节数(建议后者,便于检测截断)
线程池调度与结果聚合
使用ExecutorService.invokeAll()提交全部Callable列表,它会阻塞直到全部完成(或超时),并按提交顺序返回Future列表。
- 遍历
Future.get()获取每个分片写入长度,累加验证是否等于文件总大小 - 任一任务抛出异常(如网络中断),
get()会抛出ExecutionException,需捕获并记录失败分片信息 - 不建议用
submit()+轮询,易造成主线程空转;也不推荐固定CountDownLatch,丢失返回值语义
文件合并与完整性保障
分片下载本身不需“合并”操作——各片已按偏移直接写入目标文件指定位置。重点在事后校验:
- 用
Files.size(path)确认总大小匹配 - 可选:计算整个文件的MD5/SHA256,与服务端
ETag或单独提供的摘要比对 - 若某片失败,仅需重提该分片任务(传入相同
start/end),无需锁全文件
不复杂但容易忽略:Range请求可能被服务器忽略(返回200而非206),需检查响应码;RandomAccessFile要以"rw"模式打开;多任务并发写同一文件时,确保seek+write原子性——JDK自身保证单次write()不会交叉,无需额外同步。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











