• 多线程下载(基础)


      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 }
  • 相关阅读:
    云原生 Serverless Database 使用体验
    如何画一张架构图(内含知识图谱)
    阿里云 Serverless Kubernetes 的落地实践分享
    【阿里云 CDP 公开课】 第二讲:CDH/HDP 何去何从
    阿里云数据治理系列(一):治理项目启动前的必答三问
    使用递归方法全选/反选TreeView中CheckBox子节点
    C# 安装部署项目 【转】
    HashTable存储树形数据
    Delphi中MessageBox用法【转】
    js nextSibling属性和previousSibling属性
  • 原文地址:https://www.cnblogs.com/Wen-yu-jing/p/4094765.html
Copyright © 2020-2023  润新知