1 package com.thread; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.RandomAccessFile; 7 import java.net.HttpURLConnection; 8 import java.net.URL; 9 10 public class MultiDownLoad { 11 private final static int threadCount = 4; 12 13 public static void main(String[] args) throws Exception { 14 URL url = new URL("http://ubmcmm.baidustatic.com/media/v1/0f000Qk-RgkVYN5NV_NaO6.jpg"); 15 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 16 long contentLength = conn.getContentLengthLong(); 17 long perLength = contentLength/threadCount; 18 File file = new File("E:/123.jpg"); 19 //为每个线程分配一个随机写入流 20 RandomAccessFile[] raf = new RandomAccessFile[threadCount]; 21 InputStream[]is = new InputStream[threadCount]; 22 for(int i=0;i<threadCount;i++){ 23 //确定每个线程应该写入的起始位置和至少写入字节数 24 //最后一个线程负责剩下的所有字节(小于其他线程负责的字节数) 25 //开启线程 26 long start = i*perLength; 27 raf[i] = new RandomAccessFile(file, "rw"); 28 is[i] = url.openStream(); 29 if(i != threadCount-1){ 30 new Thread(new DownLoad(start,perLength,raf[i],is[i])).start(); 31 }else { 32 long specialEnd = contentLength - perLength*(threadCount-1); 33 new Thread(new DownLoad(start,specialEnd,raf[i],is[i])).start(); 34 } 35 36 } 37 } 38 39 } 40 class DownLoad implements Runnable{ 41 42 private final int BUFFSIZE = 1024; 43 private long start; 44 private long end; 45 private RandomAccessFile raf; 46 private InputStream is; 47 48 public DownLoad(long start, long end, RandomAccessFile raf, 49 InputStream is) { 50 this.start = start; 51 this.end = end; 52 this.raf = raf; 53 this.is = is; 54 } 55 56 @Override 57 public void run() { 58 try { 59 is.skip(start); 60 raf.seek(start); 61 byte[] buf = new byte[BUFFSIZE]; 62 int times = (int) ((end/BUFFSIZE)+4); 63 //某个线程的下载超过了该线程应该下载量 是没有问题的 因为后面的线程会在它的起始位置重新写入 64 //但是如果该线程下载的量不足 就会导致图片显示异常!! 65 //由于每次读取buf缓冲区的字节 但并不是每次都能真实的读满 66 //防止下载量不足 让改线程多读几次故 +4 67 for(int i = 0; i<times;i++){ 68 int a = is.read(buf); 69 if(a<0){ 70 break; 71 } 72 raf.write(buf,0,a); 73 } 74 } catch (IOException e) { 75 e.printStackTrace(); 76 }finally{ 77 try { 78 is.close(); 79 } catch (IOException e) { 80 e.printStackTrace(); 81 } 82 try { 83 raf.close(); 84 } catch (IOException e) { 85 e.printStackTrace(); 86 } 87 } 88 89 } 90 91 /** 92 * @return the start 93 */ 94 public long getStart() { 95 return start; 96 } 97 98 /** 99 * @param start the start to set 100 */ 101 public void setStart(long start) { 102 this.start = start; 103 } 104 105 /** 106 * @return the end 107 */ 108 public long getEnd() { 109 return end; 110 } 111 112 /** 113 * @param end the end to set 114 */ 115 public void setEnd(long end) { 116 this.end = end; 117 } 118 119 /** 120 * @return the raf 121 */ 122 public RandomAccessFile getRaf() { 123 return raf; 124 } 125 126 /** 127 * @param raf the raf to set 128 */ 129 public void setRaf(RandomAccessFile raf) { 130 this.raf = raf; 131 } 132 133 134 /** 135 * @return the is 136 */ 137 public InputStream getIs() { 138 return is; 139 } 140 141 /** 142 * @param is the is to set 143 */ 144 public void setIs(InputStream is) { 145 this.is = is; 146 } 147 148 }