多线程下载

本文探讨了一个基于多线程的断点续传下载程序的设计与实现,重点分析了不同线程数量下程序的表现及存在的问题,如文件大小计算误差、线程间同步冲突等,并对比了模拟器与真实设备上的表现差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先要说的是。。。这代码绝对的有bug。。。只要处理稍微大点的文件,就会出错。。。

不过还是写出来吧。。。

1.两个文本框,一个用来输入下载的网络地址,一个用来输入保存的文件路径,一个下载按钮,一个进度条查看进度

2.主文件:

获取下载的网络地址和存放的文件路径还有线程数,调用DownUtil类的方法来实现下载操作。创建一个Timer类,每秒获取一次下载进度,并发消息给Handler,更新进度条。

3.DownUtil文件:

download方法负责按照下载地址来建立网络连接,得到文件的大小,按照程序设定的线程数,将文件分成几个块,每个块使用一个单独的线程下载。这里用到了RandomAccessFile类,这是一个可以再文件中随意设置读写位置的类,使用seek函数实现随意设置读写位置。计算每个块(即每个线程)的起始下载位置,块大小,每个块使用一个RandomAccessFile。启动下载线程,将这三个参数传递给线程。

DownloadThread线程:建立网络连接,找到要下载的文件后,根据传入的起始下载位置参数,跳转到自己这块要下载的位置(使用skip函数)开始下载。期间随时检查已下载的大小和文件是否已经到末尾。

但这里其实是有问题的,比如,我设定了1024byte为单位下载,如果块的大小不是1024的整数倍,而且下载的块不是最后一块,那么最后那个1024分组必然也会是满的,因为在最后那一轮循环时,没有读到文件尾部,也没有使得已下载的大小大于本块的大小。

byte[] buffer = new byte[1024];
    int hasRead = 0;

    //读取网络数据,并写入本地文件
    while (length < currentPartSize
      && (hasRead = inStream.read(buffer)) != -1)
     {
      currentPart.write(buffer, 0, hasRead);
      // 累计该线程下载的总大小
      length += hasRead;
     }

这里用到了read函数,这个函数的返回值如下:

  • 读取成功,读完buffer要求的字数后还未到达文件结尾,则返回值等于buffer要求的字节数
  • 读取成功,读取的文件的长度小于buffer要求的字节数,返回值为文件实际的长度
  • 读取时,已到达文件末尾,返回0
  • 读取出错,返回-1

下面是错误的一些数据和图片,分析什么的。。。

文件大小为491052字节

两个线程:起始位置分别为0,245527,每块240个hasRead,最后那个790byte,下载的图片正确

 线程数 起始位置 每块hasRead数 最后一个组的长度 下载图片正确否 结果是否有反复
 2

 0,245527

 240 790 正确 
 3 0.163685,327370 160 866 正确 
 4

 0,122764,

245528,368292

 120 1024 只有一次正确 反复
 5

 0,98211,196422,

294633,392844

 96 1024 只有一次正确 反复
 6

 0,81843,163686,

245529,327372,

409215

 80 1024 没正确过 反复

只有那么一阵子,模拟器无论分成几个线程,都能得出正确结果,甚至试了8线程。

模拟器,随机错误,图片拒不重复,MP3是从头开始的某部分一直不断重复,大致大小是1M,以1M左右大小,循环。

模拟器实现了多个线程并发执行,问题可能再分块上,经过System。out输出,分块的起始位置又没有问题。。。下载下来的文件有时比实际大小要大,有时又小。。。前几个线程,每个hasRead都是1024,这可能是因为直接对文件进行分块读取,只设置了读取开始位置,而没有设置读取终止位置,从而覆盖了正确的读取结果。但事实上,错误的图片显示出局部的重复性,就像是线程3的位置上却又是线程2的内容,就造成了图片局部重复。但不止这样,还有些位置会出现一片灰色。错误完全是随机的。有时,执行多次能得出不同的结果。。。并且这些错误都出现在下载大一些的文件中。其实也不大,才几百k。最后一个线程的最后一个hasRead应该小于1024,因为读到了文件末尾了,但是有时候会小于,有时候又等于。。。

也可能是几个线程共用了buffer???没有懂。。。

真机测试,下载结果一切正常,但是过程非常慢,看System。out可以发现,线程并没有并行,而是第一个线程的内容完全下载完成后,第二个线程开始工作。而且,不像虚拟机中一直显示1024(除了虚拟器的正确结果时,最后一个线程的最后一分组,那组理应小于1024),真机下载是,会循环出现1024和几个固定的,小于1024的数值。这可能是真机强制执行的操作。。。

真是,费流量啊这个测试。。。十几兆没了。。。

 

综上,这代码弄了一天,也没有明白它为什么会这样,但好在,至少知其然了,虽然还是不知其所以然。总比连这代码会出bug都不知道好,只能这么安慰自己了。

看来,问题肯定是出在并行操作上了,应该是共用了什么内存,缓冲区什么的吧。。。纠结。。。

 代码


以下图片分别为,2线程,3线程,4线程,5线程,6线程,8线程,和莫名正常了一阵子的n线程

多线程下载

多线程下载

多线程下载

多线程下载

多线程下载

多线程下载

多线程下载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值