多线程下载(基础)

  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 }
原文地址:https://www.cnblogs.com/Wen-yu-jing/p/4094765.html