Java多线程下载

来源:互联网 发布:下载识谱软件 编辑:程序博客网 时间:2024/06/07 17:00

最近在做一个简单的多线程下载,记录下遇到的难题

主要思路

  1. 下载之前需要创建一个同等大小的空文件来占取储存空间
  2. 每个线程只下载一部分资源,如果有2个线程,则第一个线程下载前面一半,第二个线程下载后一半
  3. 将每个线程获取的资源,按资源顺序写入目标文件
  4. 最后一个线程下载完后,主线程通知用户下载完成

类介绍

java.io.RandomAccessFile

提供对文件的读写功能,与普通的输入输出流不一样的是RamdomAccessFile可以任意的访问文件的任何地方。

//以读写方式打开指定文件,不存在就创建新文件。RandomAccessFile randomAccessFile = new RandomAccessFile(“data.temp”,"rw");//设置data.temp文件的大小randomAccessFile.setLength(1024);//设置读取或写入的开始位置randomAccessFile.seek(0);

java.net.HttpURLConnection

//设置访问资源的范围 如果设置了Range 则 response code=206 (部分连接)httpURLConnection.setRequestProperty("Range","bytes="+startPos+"-"+endPos);//获取链接成功返回的数据InputStream inputStream = httpURLConnection.getInputStream();

java.util.concurrent.CountDownLatch

CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的某一指定目标,计数器的值就会减1,然后该线程继续执行。如我们创建3个下载线程,主线程中就需要等待3个下载线程完成后再通知用户下载完成。而每个子线程下载完成(目标),先让计数器减去1,然后该干嘛干嘛去,不需要等其他下载线程。

//3表示需要等待的线程个数CountDownLatch countDownLatch = new CountDownLatch(3);//获取未完成线程的个数countDownLatch.getCount();//等待线程个数减去1countDownLatch.countDown();//等待计数器等于0,再执行后面的代码countDownLatch.await();

具体代码

FileDownloader

import java.io.File;import java.io.IOException;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;import java.util.concurrent.CountDownLatch;public class FileDownloader {    private String address;    public FileDownloader(String address) {        this.address = address;    }    public void download(int threadCount) {        try {            URL url = new URL(address);            HttpURLConnection httpURLConnection = (HttpURLConnection) url                    .openConnection();            int length = httpURLConnection.getContentLength();            System.out.println("文件大小:"+length);            // 写死了,没有从Header中获取文件类型,以及文件名            File file = new File("E:\\download.jpg");            RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");            randomAccessFile.setLength(length);            randomAccessFile.close();            CountDownLatch countDownLatch = new CountDownLatch(threadCount);            // 计算每个线程下载的数据大小            int blockSize = length / threadCount;            for (int i = 0; i < threadCount; i++) {                int startPos = blockSize * i;                int endPos = blockSize * (i + 1);                if (i == threadCount - 1) {                    endPos = length;                }                new DownloadThread(file, countDownLatch, address, startPos,                        endPos - 1).start();            }            while (countDownLatch.getCount() != 0) {                System.out.println("下载中....");                try {                    // 休眠                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            System.out.println("下载完成");        } catch (IOException e) {            e.printStackTrace();        }    }}

DownloadThread

import java.io.File;import java.io.IOException;import java.io.InputStream;import java.io.RandomAccessFile;import java.net.HttpURLConnection;import java.net.URL;import java.util.concurrent.CountDownLatch;public class DownloadThread extends Thread {    private File file;    private CountDownLatch countDownLatch;    private String address;    private int startPos;    private int endPos;    public DownloadThread(File file, CountDownLatch countDownLatch,            String address, int startPos, int endPos) {        super();        this.file = file;        this.countDownLatch = countDownLatch;        this.address = address;        this.startPos = startPos;        this.endPos = endPos;    }    public void run() {        Thread current = Thread.currentThread();        System.out.println(current.getName() + "开始下载:" + startPos + "-"                + endPos);        RandomAccessFile randomAccessFile = null;        InputStream inputStream = null;        try {            URL url = new URL(address);            HttpURLConnection httpURLConnection = (HttpURLConnection) url                    .openConnection();            httpURLConnection.setRequestProperty("Range", "bytes=" + startPos                    + "-" + endPos);            inputStream = httpURLConnection.getInputStream();            randomAccessFile = new RandomAccessFile(file, "rw");            randomAccessFile.seek(startPos);            byte[] bytes = new byte[1024];            int read = 0;            while ((read = inputStream.read(bytes)) != -1) {                randomAccessFile.write(bytes, 0, read);            }        } catch (IOException e) {            e.printStackTrace();        } finally {            try {                if (randomAccessFile != null) {                    randomAccessFile.close();                }                if (inputStream != null) {                    inputStream.close();                }            } catch (IOException e) {                e.printStackTrace();            }            System.out.println(current.getName() + "下载完成");            countDownLatch.countDown();        }    }}

DownloadTest

public class DownloadTest {    public static void main(String[] args) {        String url = "http://7xq43s.com1.z0.glb.clouddn.com/yunanding-6.jpg";//3.82M        FileDownloader fileDownloader = new FileDownloader(url);        fileDownloader.download(3);    }}

输出

文件大小:4013554Thread-0开始下载:0-1337850Thread-1开始下载:1337851-2675701下载中....Thread-2开始下载:2675702-4013553下载中....下载中....下载中....下载中....下载中....下载中....下载中....下载中....下载中....下载中....下载中....下载中....Thread-1下载完成下载中....Thread-0下载完成下载中....下载中....下载中....Thread-2下载完成下载完成

本人对线程的理解还不够深入,如有错误,恳请指出,感激不尽

0 0