Java 多线程下载

辅助类介绍:

1、CountDownLatch(int count);

所属:java.lang.Object

  java.util.concurrent.CountDownLatch

详解:一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待(更多请查看java-API)。

使用方法:CountDownLatch latch = new CountDownLatch(count);

 

2、currentTimeMillis();

  所属:java.lang.Object

 java.lang.System

详解:返回以毫秒为单位的当前系统时间

使用方法:long startTime = System.currentTimeMillis();

 

3、URL(String url);

  所属:java.lang.Object

 java.net.URL

详解: URL 代表一个统一资源定位符,它是指向互联网“资源”的指针。资源可以是简单的文件或目录。

使用方法:

//建立一个连接路径url

     URL url = new URL(serverPath);

     //打开连接

     HttpURLConnection conn = (HttpURLConnection) url.openConnection();

     //设置一个指定的超时值(以毫秒为单位),该值将在打开到此 URLConnection 引用的资源的通信链接时使用。

     conn.setConnectTimeout(5000);

     //设置 URL 请求的方法, GET POST HEAD OPTIONS PUT DELETE TRACE 以上方法之一是合法的,具体取决于协议的限制。

     conn.setRequestMethod("GET");

     // 从 HTTP 响应消息获取状态码。

     int code = conn.getResponseCode();

     if (code == 200) {

     //服务器返回的数据的长度,实际上就是文件的长度,单位是字节

     int length = conn.getContentLength();

 

4、RandomAccessFile(File file, String mode)

所属:java.lang.Object

     java.io.RandomAccessFile
详解:此类的实例支持对随机访问文件的读取和写入,创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。

使用方法:

   RandomAccessFile raf = new RandomAccessFile(localPath, "rwd");

       //指定创建的文件的长度

       raf.setLength(length);

  raf.close();

 

 

具体实现代码

工具类:

package download;

import java.io.InputStream;

import java.io.RandomAccessFile;

import java.net.HttpURLConnection;

import java.net.URL;

import java.util.concurrent.CountDownLatch;

 

public class MutiThreadDownLoad {

/**

     * 同时下载的线程数

     */

    private int threadCount;

    /**

     * 服务器请求路径

     */

    private String serverPath;

    /**

     * 本地路径

     */

    private String localPath;

    /**

     * 线程计数同步辅助

     */

    private CountDownLatch latch;

    

    //多线程下载工具类(线程数,下载服务地址,本地存储地址,同步占用线程数)

    public MutiThreadDownLoad(int threadCount, String serverPath, String localPath, CountDownLatch latch) {

        this.threadCount = threadCount;

        this.serverPath = serverPath;

        this.localPath = localPath;

        this.latch = latch;

    }

 

    public void executeDownLoad() {

 

        try {

        //建立一个连接路径url

            URL url = new URL(serverPath);

            //打开连接

            HttpURLConnection conn = (HttpURLConnection) url.openConnection();

            //设置一个指定的超时值(以毫秒为单位),该值将在打开到此 URLConnection 引用的资源的通信链接时使用。

            conn.setConnectTimeout(5000);

            //设置 URL 请求的方法, GET POST HEAD OPTIONS PUT DELETE TRACE 以上方法之一是合法的,具体取决于协议的限制。

            conn.setRequestMethod("GET");

            // 从 HTTP 响应消息获取状态码。

            int code = conn.getResponseCode();

            if (code == 200) {

                //服务器返回的数据的长度,实际上就是文件的长度,单位是字节

                int length = conn.getContentLength();

                System.out.println("文件总长度:" + length + "字节(B)");

                RandomAccessFile raf = new RandomAccessFile(localPath, "rwd");

                //指定创建的文件的长度

                raf.setLength(length);

                raf.close();

                //分割文件

                int blockSize = length / threadCount;

                for (int threadId = 1; threadId <= threadCount; threadId++) {

                    //第一个线程下载的开始位置

                    int startIndex = (threadId - 1) * blockSize;

                    //线程结束位置

                    int endIndex = startIndex + blockSize - 1;

                    if (threadId == threadCount) {

                        //最后一个线程下载的长度稍微长一点

                        endIndex = length;

                    }

                    System.out.println("线程" + threadId + "下载:" + startIndex + "字节~" + endIndex + "字节");

                    new DownLoadThread(threadId, startIndex, endIndex).start();

                }

 

            }

 

        } catch (Exception e) {

            e.printStackTrace();

        }

 

 

    }

 

 

    /**

     * 内部类用于实现下载

     */

    public class DownLoadThread extends Thread {

        /**

         * 线程ID

         */

        private int threadId;

        /**

         * 下载起始位置

         */

        private int startIndex;

        /**

         * 下载结束位置

         */

        private int endIndex;

 

        public DownLoadThread(int threadId, int startIndex, int endIndex) {

            this.threadId = threadId;

            this.startIndex = startIndex;

            this.endIndex = endIndex;

        }

 

 

        @Override

        public void run() {

 

            try {

                System.out.println("线程" + threadId + "正在下载...");

                URL url = new URL(serverPath);

                HttpURLConnection conn = (HttpURLConnection) url.openConnection();

                conn.setRequestMethod("GET");

                //请求服务器下载部分的文件的指定位置

                conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);

                conn.setConnectTimeout(5000);

                int code = conn.getResponseCode();

 

                System.out.println("线程" + threadId + "请求返回code=" + code);

 

                InputStream is = conn.getInputStream();//返回资源

                RandomAccessFile raf = new RandomAccessFile(localPath, "rwd");

                //随机写文件的时候从哪个位置开始写

                raf.seek(startIndex);//定位文件

 

                int len = 0;

                byte[] buffer = new byte[1024];

                while ((len = is.read(buffer)) != -1) {

                    raf.write(buffer, 0, len);

                }

                is.close();

                raf.close();

                System.out.println("线程" + threadId + "下载完毕");

                //计数值减一

                latch.countDown();

 

            } catch (Exception e) {

                e.printStackTrace();

            }

 

        }

    }

}

 

测试类:

package download;

 

import java.util.concurrent.CountDownLatch;

 

public class Client {

public static void main(String[] args) {

//线程数量

        int threadSize = 6;

        //下载的服务路径

        String serverPath = "http://file.ws.126.net/3g/client/netease_newsreader_android.apk";

        //本地存放路径

        String localPath = "F:\\NewsReader.apk";

        //同步辅助类初始化线程数量(int count)

        CountDownLatch latch = new CountDownLatch(threadSize);

        //初始化多线程下载类(线程数,下载服务地址,本地存储地址,同步占用线程数)

        MutiThreadDownLoad m = new MutiThreadDownLoad(threadSize, serverPath, localPath, latch);

        //返回以毫秒为单位的当前开始下载时间

        long startTime = System.currentTimeMillis();

        

        try {

        //调用方法开始下载

            m.executeDownLoad();

            latch.await();

        } catch (InterruptedException e) {

        //将此 throwable 及其追踪输出到指定的 PrintWriter。

            e.printStackTrace();

        }

        //下载完成的当前时间

        long endTime = System.currentTimeMillis();

        //计算下载共耗时多久

        System.out.println("全部下载结束,共耗时" + (endTime - startTime) / 1000 + "s");

    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值