多线程下载(基础)

  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 }

 

你可能感兴趣的:(多线程下载)