多线程下载

package com.thread.test;

import java.io.File;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MultiThThread implements Runnable
{
    private String urlLocation;
    private String filePath;
    private long start;
    private long end;
    
    public MultiThThread(String urlLocation, String filePath, long start, long end) {
        super();
        this.urlLocation = urlLocation;
        this.filePath = filePath;
        this.start = start;
        this.end = end;
    }
    
    /**
     * 开启网络连接
     * @return
     * @throws Exception 
     */
    public HttpURLConnection getHttp() throws Exception
    {
        /**
         * 创建url对象,中文名为统一资源定位符,
         * 有时也被俗称为网页地址。
         * 表示为互联网上的资源,如网页或者FTP地址。
         */
        URL url = null;
        
        if(urlLocation !=null)
        {
            url = new URL(urlLocation);
        }
        //开启网络连接
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        //添加配置
        conn.setReadTimeout(5000);
        //传输方法
        conn.setRequestMethod("GET");
        
        return conn;
    }

    @Override
    public void run() 
    {
        // TODO Auto-generated method stub
        try 
        {
            //获取指定网页地址的资源
            HttpURLConnection conn = getHttp();
            /**
             * 告诉服务器,只要目标段的数据,
             * 这样就需要通过Http协议的请求头去设置(range:bytes=0至start-end )
             */
            conn.setRequestProperty("Range", "bytes = "+"start"+"-"+"end");
        
            File file = new File(filePath);
            
            RandomAccessFile out = null;
            if(file!=null)
            {
                /**
                 * 创建一个RandomAccessFile对象,写到文件指定的范围,
                 * rw表示文件即可读也可写
                 */
                out = new RandomAccessFile(file,"rw");
            }
            //让out写字节流之前,需要移动raf到指定的位置开始写
            out.seek(start);
            InputStream in = conn.getInputStream();
            byte[] b = new byte[1024];
            int len = 0;
            while((len = in.read(b))>=0)
            {
                out.write(b);
            }
            in.close();
            out.close();
        } 
        catch (Exception e) 
        {
            // TODO: handle exception
            e.getMessage();
        }
    }
    public static void main(String[] args) 
    {
        Date startDate = new Date();
        ThreadPool pool = new ThreadPool();
        try 
        {
            pool.getThreadPool("http://mpge.5nd.com/2016/2016-11-15/74847/1.mp3", "D:\\1.mp3", 100);
        } 
        catch (Exception e) 
        {
            // TODO: handle exception
            e.printStackTrace();
        }
        System.out.println(new Date().getTime()-startDate.getTime());
    }
}
class ThreadPool
{
    public void getThreadPool(String urlLocation,String filePath,int poolLength) throws Exception
    {
        /**
         * 创建一个可缓存线程池,如果线程池长度超过处理需要,
         * 可灵活回收空闲线程,若无可回收,则新建线程。
         */
        ExecutorService threadPool = Executors.newCachedThreadPool();
        long len =     getContentLength(urlLocation);    
        System.out.println(len);
        for(int i=0;i<poolLength;i++)
        {
            //开始索引位置
            long start = i*len/poolLength;
            //结束索引位置
            long end = (i+1)*len/poolLength-1;
            /**
             * 多线程下载最理想状态是:多条线程均分担
             * 有时多条线程分担,不能均分。
             * 当不能均分时,
             * 剩余的多余下载任务需要最后一条线程承担
             */
            if(i == poolLength-1)
            {
                end = len;
            }
            System.out.println(start+"--------------"+end);
            MultiThThread downLoad = new MultiThThread(urlLocation, filePath, start, end);
            threadPool.execute(downLoad);
        }
        threadPool.shutdown();
    }
    
    public static long getContentLength(String urlLocation) throws Exception
    {
        URL url = null;
        if(urlLocation!=null)
        {
            url = new URL(urlLocation);
        }
        HttpURLConnection conn = (HttpURLConnection)url.openConnection();
        conn.setReadTimeout(5000);
        conn.setRequestMethod("GET");
        
        long len = conn.getContentLength();
        return len;
    }
}

多线程下载的大体几个步骤:

1:获取目标文件大小

2:开启线程池

3:统计每个线程需要下载的字节数

4:计算线程下载字节范围

5:获取各个线程的目标文件的开始索引和结束索引的范围。

6:使用RandomAccessFile随机文件访问类。创建一个RandomAccessFile对象,将返回的字节流写到文件指定的范围

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值