package com.sphere.multithread; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.concurrent.Executor; import java.util.concurrent.Executors; public class MultiThreadDownload { // 线程池默认线程数量 private static final int DEFAULT_THREAD_COUNTS = 3; // 创建线程池对象 private Executor threadPool = Executors.newFixedThreadPool(DEFAULT_THREAD_COUNTS); // 文件总长度 private int fileTotalLength = 0; // 当前已下载的文件长度 private int currentFileDownloadLength = 0; private class DownloadRunnable implements Runnable{ private int threadId; // 标识线程号 private String url; private String fileName; private long startIndex; private long endIndex; public DownloadRunnable(int threadId, String url, String fileName, long start, long end){ this.threadId = threadId; this.url = url; this.fileName = fileName; this.startIndex = start; this.endIndex = end; } @Override public void run() { System.out.println("线程"+threadId +"开始执行..."); RandomAccessFile accessFile = null; InputStream inputStream = null; try { URL httpUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection(); conn.setReadTimeout(5000); conn.setRequestMethod("GET"); // 指定读取的开始和结束的位置 conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex); accessFile = new RandomAccessFile(new File(fileName), "rwd"); accessFile.seek(startIndex); inputStream = conn.getInputStream(); byte[] buffer = new byte[8*1024]; int len = 0; long currentIndex = startIndex; while((len = inputStream.read(buffer)) != -1){ accessFile.write(buffer, 0, len); System.out.println("线程"+threadId +"正在读取"+currentIndex+"到"+(currentIndex+len) +"之间的字节."); currentIndex = currentIndex+len; synchronized(this){ currentFileDownloadLength += len; if(currentFileDownloadLength == fileTotalLength){ System.out.println("-------------------------------"); System.out.println("文件读写完毕。 总长度为"+fileTotalLength + "个字节。 "); } } } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if (accessFile != null){ try { accessFile.close(); } catch (IOException e) { e.printStackTrace(); } } if (inputStream != null){ try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } } protected void downFileByMultiThread(String url){ try{ URL httpUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection(); conn.setReadTimeout(5000); conn.setRequestMethod("GET"); // 此连接的 URL 引用的资源的内容长度,或者如果内容长度未知,则返回 -1 int countLength = conn.getContentLength(); int block = countLength / DEFAULT_THREAD_COUNTS; fileTotalLength = countLength; String fileName = getFileName(url); File file = new File("C:\\"+fileName); for (int i = 0; i < DEFAULT_THREAD_COUNTS ; i++){ long start = i * block; long end = (i + 1) * block -1; if (i == DEFAULT_THREAD_COUNTS - 1){ end = countLength; } DownloadRunnable runnable = new DownloadRunnable((i+1), url, file.getAbsolutePath(), start, end); threadPool.execute(runnable); } } catch (Exception e) { e.printStackTrace(); } } /** * 得到图片的文件名 */ public static String getFileName(String str){ String fileName = str.substring(str.lastIndexOf("/") + 1); return fileName; } }
测试类:
package com.sphere.multithread; public class Test { public static void main(String[] args) { String url = "http://b.zol-img.com.cn/desk/bizhi/image/1/1920x1080/1348626500448.jpg"; new MultiThreadDownload().downFileByMultiThread(url); } }
打印的log信息如下:
线程1开始执行...
线程2开始执行...
线程3开始执行...
线程2正在读取100695到108887之间的字节.
线程2正在读取108887到117079之间的字节.
线程2正在读取117079到125271之间的字节.
线程2正在读取125271到133463之间的字节.
线程3正在读取201390到209582之间的字节.
线程2正在读取133463到136295之间的字节.
线程3正在读取209582到217774之间的字节.
线程3正在读取217774到225966之间的字节.
线程1正在读取0到8192之间的字节.
线程3正在读取225966到234118之间的字节.
线程2正在读取136295到139191之间的字节.
线程2正在读取139191到144983之间的字节.
线程2正在读取144983到149327之间的字节.
线程2正在读取149327到152223之间的字节.
线程2正在读取152223到155119之间的字节.
线程2正在读取155119到163311之间的字节.
线程3正在读取234118到235566之间的字节.
线程3正在读取235566到243758之间的字节.
线程3正在读取243758到251950之间的字节.
线程3正在读取251950到260142之间的字节.
线程3正在读取260142到268334之间的字节.
线程3正在读取268334到276526之间的字节.
线程3正在读取276526到284718之间的字节.
线程3正在读取284718到292910之间的字节.
线程3正在读取292910到296382之间的字节.
线程3正在读取296382到302087之间的字节.
线程1正在读取8192到11885之间的字节.
线程2正在读取163311到171047之间的字节.
线程1正在读取11885到20077之间的字节.
线程2正在读取171047到179239之间的字节.
线程1正在读取20077到28269之间的字节.
线程2正在读取179239到187431之间的字节.
线程1正在读取28269到36461之间的字节.
线程2正在读取187431到195623之间的字节.
线程2正在读取195623到201390之间的字节.
线程1正在读取36461到44653之间的字节.
线程1正在读取44653到52845之间的字节.
线程1正在读取52845到61037之间的字节.
线程1正在读取61037到69229之间的字节.
线程1正在读取69229到77421之间的字节.
线程1正在读取77421到85613之间的字节.
线程1正在读取85613到93805之间的字节.
线程1正在读取93805到100695之间的字节.
-------------------------------
文件读写完毕。 总长度为302087个字节。