基于Java多线程的下载器源码剖析.docx

上传人:b****2 文档编号:17916123 上传时间:2023-08-04 格式:DOCX 页数:35 大小:513.34KB
下载 相关 举报
基于Java多线程的下载器源码剖析.docx_第1页
第1页 / 共35页
基于Java多线程的下载器源码剖析.docx_第2页
第2页 / 共35页
基于Java多线程的下载器源码剖析.docx_第3页
第3页 / 共35页
基于Java多线程的下载器源码剖析.docx_第4页
第4页 / 共35页
基于Java多线程的下载器源码剖析.docx_第5页
第5页 / 共35页
基于Java多线程的下载器源码剖析.docx_第6页
第6页 / 共35页
基于Java多线程的下载器源码剖析.docx_第7页
第7页 / 共35页
基于Java多线程的下载器源码剖析.docx_第8页
第8页 / 共35页
基于Java多线程的下载器源码剖析.docx_第9页
第9页 / 共35页
基于Java多线程的下载器源码剖析.docx_第10页
第10页 / 共35页
基于Java多线程的下载器源码剖析.docx_第11页
第11页 / 共35页
基于Java多线程的下载器源码剖析.docx_第12页
第12页 / 共35页
基于Java多线程的下载器源码剖析.docx_第13页
第13页 / 共35页
基于Java多线程的下载器源码剖析.docx_第14页
第14页 / 共35页
基于Java多线程的下载器源码剖析.docx_第15页
第15页 / 共35页
基于Java多线程的下载器源码剖析.docx_第16页
第16页 / 共35页
基于Java多线程的下载器源码剖析.docx_第17页
第17页 / 共35页
基于Java多线程的下载器源码剖析.docx_第18页
第18页 / 共35页
基于Java多线程的下载器源码剖析.docx_第19页
第19页 / 共35页
基于Java多线程的下载器源码剖析.docx_第20页
第20页 / 共35页
亲,该文档总共35页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

基于Java多线程的下载器源码剖析.docx

《基于Java多线程的下载器源码剖析.docx》由会员分享,可在线阅读,更多相关《基于Java多线程的下载器源码剖析.docx(35页珍藏版)》请在冰点文库上搜索。

基于Java多线程的下载器源码剖析.docx

基于Java多线程的下载器源码剖析

 

基于Java多线程的下载器源码剖析

(一)

分类:

 JavaHYPERLINK"21:

29 747人阅读 评论(6) 收藏 举报

多线程HYPERLINK"""""

目录(?

)[+]

本文实现了一个基于Java多线程的下载器,可提供的功能有:

1.对文件使用多线程下载,并显示每时刻的下载速度。

2.对多个下载进行管理,包括线程调度,内存管理等。

这篇文章的结构如下:

首先讨论如何实现利用Java多线程对单个文件进行下载。

然后讨论当系统中有多个文件下载,如何对这些下载进行管理。

包括线程调度,内存管理等。

一:

单个文件下载的管理

1.单文件下载类层次

首先简要介绍一下单个文件下载管理的类层次:

来一张图来表示。

 

∙为需要下载的文件创建一个Download类,Download负责管理该文件下载时的线程管理、文件管理、当前速度计算等操作。

∙根据线程的数目tNum,将该文件分为tNum段,每段为一个DownloadBlock。

在实际下载的过程中,并不是一次把所有的东西下载完,而是每次下载固定size的一段Di。

所以每个DownloadBlock又会分成n段。

∙为每个DownloadBlock申请一个线程DownloadThread。

其主要作用就是每次下载一段Di,并将其写入到文件中。

2.单文件下载

对于单个下载,步骤如下

∙连接资源服务器,获取资源信息,创建文件

∙ 切分资源,为每个线程分配固定的下载区域。

1)封装下载的属性

在建立下载之前,我们把每一次下载进行抽象封装。

首先把URL、目标文件等封装在一个DownloadConfig类中。

其中包含了4个属性:

[java] viewplainHYPERLINK"

∙private URL url; //文件下载地址  

∙private File file; //下载文件保存目标文件  

∙private int nthread; //下载该文件需要的线程数  

∙private int priority; //该下载的优先级  

如下如所示:

2)连接资源服务器,获取资源信息,创建文件,并指定文件大小

[java] viewplainHYPERLINK"

∙length = config.getUrl().openConnection().getContentLength();  

∙RandomAccessFile file = new RandomAccessFile(config.getFile(), "rw");  

∙file.setLength(length);  

∙file.close();  

3)切分资源,为每个线程分配固定的下载区域,并将当前的下载加入到队列中

[java] viewplainHYPERLINK"

∙int size = length / config.getNthread();  

∙for(int i = 0; i < config.getNthread(); i++){  

∙    int start = i * size;  

∙    int len;  

∙    if(i == config.getNthread() - 1)  

∙        len = length - start;  

∙    else len = size;  

∙//并将当前的下载加入到下载队列中  

∙    addDownloadBlock(getDownloadBlock(start, len));  

∙}  

3)启动线程进行下载

下载的步骤如下:

  1.创建缓存,创建连接。

设置获取资源数据的范围,创建文件,并设置写入位置

[java] viewplainHYPERLINK"

∙//创建缓存  

∙byte [] b;  

∙if(block.getLength() < Constants.BYTES_READ)  

∙    b = new byte[(int)block.getLength()];  

∙else  

∙    b = new byte[Constants.BYTES_READ];  

∙  

∙//创建连接。

设置获取资源数据的范围,从startPos到endPos  

∙URLConnection con = null;  

∙con.setRequestProperty("Range", "bytes=" + block.getStart() + "-" + block.getStart()+block.getLength()-1);  

∙RandomAccessFile file = new RandomAccessFile(block.getDownload().getConfig().getFile(), "rw");//创建RandomAccessFile  

∙file.seek(block.getStart()); //从startPos开始写入  

 2.如果当前block的length大于0,则从URL资源处获取固定大小的资源,并将其写入到文件中。

 3.更新block块的start,以及length,如果length大于0,继续进行2,否则则表示当前block已经下载完毕,退出该线程。

[java] viewplainHYPERLINK"

∙InputStream in = block.getDownload().getConfig().getUrl().openStream();  

∙int n;  

∙  

∙//对该block内的文件进行下载,  

∙while(count < block.getLength()){  

∙    if (needSplit()) { // 检查该Block是否还需要分块(即当前block剩余的大小大于一次下载的量)  

∙        long newLength = (block.getLength() - count) / 2;  

∙        long newStart = block.getStart() + block.getLength() - newLength;  

∙        DownloadBlock newBlock = block.getDownload().getDownloadBlock(newStart, newLength);  

∙        block.setLength(block.getLength() - newLength);  

∙        block.getDownload().addDownloadBlock(newBlock);  

∙    }  

∙  

∙  

∙    //写入文件  

∙    n = in.read(b);  

∙    if(n < 0){  

∙        break;  

∙    }else if(count + n > block.getLength()){  

∙        file.write(b, 0, (int)(block.getLength() - count));  

∙        count = block.getLength();  

∙    }else {  

∙        count += n;  

∙        file.write(b, 0, n);  

∙    }  

∙      

∙    // set block count in download  

∙    if(n > 0){  

∙        //统计每个block中已经下载的段的个数,用于计算当前下载的速度。

  

∙        block.getDownload().setBlockCount(block.getStart(), count);  

∙    }  

∙}  

∙  

∙in.close();  

∙file.close();  

二.当前文件下载速度与进度计算

如第一个图所表示的,每个Block中又分为了很多的段D1、D2、…Dn,因此当为了计算当前下载的速度,需要将下载的段D的数量统计出来,这里使用了一个ConcurrentHashMap来保存每个block已经下载完成的段D的数目。

其中key为每个block的start值,而value为该block已经下载完的段D。

在当前时刻,我们需要统计当前Download已经下载完成段D的数量,然后再和上一时刻的相比较,则可以得出当前的下载速度。

具体代码见下:

[java] viewplainHYPERLINK"

∙class CheckSpeedTask extends TimerTask{  

∙      

∙    private static final Log log = LogFactory.getLog(CheckSpeedTask.class);  

∙      

∙    private Download download;  

∙    private ConcurrentHashMap blockCounts;   

∙      

∙    private long speed = 0; // Byte/S  

∙    private long count = 0; // Total downloaded byte count  

∙    private long lastCount = 0;  

∙    private long time = 0; // Check time  

∙    private long lastTime = 0;  

∙      

∙    public CheckSpeedTask(Download download, long startTime, ConcurrentHashMap blockCounts){  

∙        this.download = download;  

∙        this.lastTime = startTime;  

∙        this.blockCounts = blockCounts;  

∙    }  

∙      

∙    @Override  

∙    public void run() {  

∙        try {     

∙            time = System.currentTimeMillis();  

∙            count = 0;  

∙//需要统计当前已经下载完成段D的数量。

  

∙            for(long c :

 blockCounts.values()){  

∙                count += c;  

∙            }  

∙            speed = (count -lastCount)/((time - lastTime)/1000);  

∙            log.debug(blockCounts.size() + " threads are downloading " + download + ", cuttent is " + speed + "Byte/S, " + (count * 1.0)/download.getLength()*100 + "% downloaded");  

∙            download.setCount(count);  

∙            download.setSpeed(speed);  

∙            lastTime = time;  

∙            lastCount = count;  

∙        } catch (Exception e) {  

∙            // TODO:

 handle exception  

∙            e.printStackTrace();  

∙        }         

∙          

∙    }  

∙}  

这样我们就可以在Thread类的run()函数中,计算当前下载的速度

[java] viewplainHYPERLINK"

∙while(activeThreads.size() > 0 || blockQueue.size() > 0){  

∙    Thread.sleep(1000);  

∙    checkSpeed();  

∙}  

上面的代码演示了如何使用Java多线程对单个文件进行下载,接下来我们继续讨论如何对多个下载进行调度、管理等

 

 

基于Java多线程的下载器源码剖析

(二)

分类:

 JavaHYPERLINK"10:

36 571人阅读 评论(6) 收藏 举报

多线程HYPERLINK"""""

目录(?

)[+]

三:

多个文件下载的管理

这一节我们主要来讲一下如何对多个文件的下载进行管理

首先来看一下整个系统的UML图

从最下面开始说起:

Download代表一个下载类,对每一个文件都需要创建一个Download实例,用于对该文件下载线程的管理。

其中每个Download中都有以下几个对象:

[java] viewplainHYPERLINK"

∙private ConcurrentLinkedQueue blockQueue;  

∙private ConcurrentLinkedQueue blockCache;  

∙private ConcurrentHashMap blockCounts;  

∙private ConcurrentLinkedQueue activeThreads;   

其中

∙blockQueue是一个队列,用于存储当前需要下载的DownloadBlock。

Download对文件进行切分形成的DownloadBlock会被放入到放入到blockQueue中,供以后的下载。

∙blockCache为block内存缓存池,主要是为了能够复用已经建立好的DownloadBlock。

∙blockCounts为一个Map,其中key为每个block的start值,而value为该block已经下载完的段D。

主要作用是统计出当前已经每个Block已经下载完的段D,以计算实时下载速度

∙activeThreads主要是为了存储该Thread中所有的活跃线程。

DownloadBlock是一个下载块,其里面有3个成员变量

[java] viewplainHYPERLINK"

∙private Download download; //其所属的Download  

∙private long start; //下载文件起始处  

∙private long length; //下载文件的长度  

DownloadThread是指下载进程,每个DownloadBlock都需要启动一个DownloadThread去进行下载。

[java] viewplainHYPERLINK"

∙new DownloadThread(block).start()  

DownloadDeamon为了一个守护线程。

其内部主要为了下载所有的需要下载DownloadBlock

[java] viewplainHYPERLINK"

∙private DownloadList downloads; //当前系统中所有的下载列表  

∙private ExecutorService threadPool; //线程池  

Downloader代表整个下载系统,整个系统中只有一个实例对象,因此我们需要保证系统中只有一个实例对象。

[java] viewplainHYPERLINK"

∙private DownloaderConfig config; // Downloader配置  

∙private DownloadList downloads; //当前系统所有的下载列表private Thread deamon; //守护进程  

∙private ConcurrentLinkedQueue blockCache; //当前系统的缓存  

∙private Timer timer; //  

 

看了上面一大堆的东西,我保证你现在很晕,OK,我们从使用的角度来看整个系统是如何运行的。

下面是示例代码。

[java] viewplainHYPERLINK"

∙public static void main(String[] args) {  

∙  

∙    Downloader downloader = Downloader.getInstance();  

∙  

∙    //下载第一个文件  

∙    String url1 = "  

∙    String saveFile1 = "data/tmsvm_src_v1.1.0.rar";  

∙    DownloadConfig config =  new DownloadConfig();  

∙    try {  

∙        config.setUrl(new URL(url1));  

∙        config.setFile(new File(saveFile1));  

∙        config.setNthread(new Integer(5));  

∙        config.setPriority(new Integer(6));  

∙        //将第一个下载加入到下载列表中  

∙        downloader.addDownload(new Download(config, downloader.getTimer()));  

∙    } catch (MalformedURLException e) {  

∙        // TODO Auto-generated catch block  

∙        e.printStackTrace();  

∙    }  

∙      

∙    //下载第二个文件  

∙    String url2 = "  

∙    String saveFile2 = "data/Tmsvm参考文档(v1.1.0).rar";  

∙    try {  

∙     

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 自然科学 > 物理

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2