java 多线程断点下载

package com;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 *  多线程断点下砸
 *
 *1. 通过网络访问获取文件大小, 然后调用RandomAccess生成相同大小的空文件(如果文件存在就不需要生成)
 *
 *2. 生成三个线程同时定义一个集合来保存下载标记
 *
 *3. 当下载标记满足的时候,就表示加载完成
 *
 * 多线程断点下载 同时支持多个任务执行 ,设计上还是有问题的 , 比如应该将任务集体封装, 其内部实现三个线程进行下载.
 */
public class MutilDownLoadDemo {

	private static volatile MutilDownLoadDemo demo;
	/** 默认的线程数, 一个任务分配三个线程来完成, 比如 两个任务就需要 3 * 2 = 6 个线程来执行 */
	private static final int DEFAULT_THREAD_COUNT = 3;
	private int mThreadCount;
	private ThreadPoolExecutor mExecutor;
	
	public static MutilDownLoadDemo newInstance(){
		if(demo == null){
			synchronized (MutilDownLoadDemo.class) {
				if(demo == null){
					demo = new MutilDownLoadDemo(DEFAULT_THREAD_COUNT);
				}
			}
		}
		return demo;
	}
	
	private MutilDownLoadDemo(int threadCount){
		this.mThreadCount = threadCount;
		//初始化线程池
		mExecutor = new ThreadPoolExecutor(mThreadCount, mThreadCount, 1, 
				TimeUnit.MINUTES, new LinkedBlockingDeque<Runnable>());
	}
	
	private synchronized void load(String path){
		try {
			//1. 获取文件的大小
			URL url = new URL(path);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("GET");
			conn.setReadTimeout(5000);
			int code = conn.getResponseCode();
			if(code == 200){
				long contentLength = conn.getContentLength();
				System.out.println("contentLength:" + contentLength);
				
				//2. 根据文件的大小来设置每个线程下砸的文件的数量
				long block = contentLength / mThreadCount;
				long remain = contentLength % mThreadCount;
				System.out.println("block:" + block + " remain:" + remain);
				
				//3. 定义一个锁,让三个线程同时完成之后,才能执行之后的
				CyclicBarrier barrier = new CyclicBarrier(mThreadCount, new ClearCacheThread(path));
				
				//4. 开启线程进行下载
				for(int i = 0 ; i < mThreadCount ; i ++){
					long start = i * block;
					long end = (i + 1) * block - 1;
					if(i == mThreadCount -1){end = contentLength;}
					mExecutor.execute(new DownLoadThread(path, start, end, barrier, i));
				}
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		String url = "http://192.168.0.194:8080/a.zip";
		
		MutilDownLoadDemo demo = MutilDownLoadDemo.newInstance();
		demo.load(url);
		
		String url1 = "http://192.168.0.194:8080/b.zip";
		demo.load(url1);
	}
	
	
	/** 用来下载的线程类  */
	public class DownLoadThread extends Thread{
		private String path;
		private long start;
		private long end;
		private CyclicBarrier mBarrier;
		private int tag;
		public DownLoadThread(String path ,long start, long end,CyclicBarrier barrier,int tag){
			this.path = path;
			this.start = start;
			this.end = end;
			this.mBarrier = barrier;
			this.tag = tag;
		}
		
		@Override
		public void run() {
			try {
				//需要判断下载文件是否存在,如果存在,已经下载了多少
				long loadLen = buildTempFile(path,tag);
				start += loadLen;
				URL url = new URL(path);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setRequestMethod("GET");
				conn.setConnectTimeout(5000);
				conn.setRequestProperty("Range", "bytes="+start+"-"+end);
				
				System.out.println(Thread.currentThread().getName() + "/start:" + start + " end:" + end);
				
				int code = conn.getResponseCode();
				System.out.println(Thread.currentThread().getName() + "/code:" + code);
				if(code == 206){
					//使用RandomAccessFile一个字节一个字节的写
					RandomAccessFile raf = new RandomAccessFile(new File(getFilePath(path)), "rwd");
					raf.setLength(conn.getContentLengthLong());
					raf.seek(start);
					
					InputStream iStream = conn.getInputStream();
					int len = -1;
					byte[] buf = new byte[1024];
					while((len = iStream.read(buf)) != -1){
						raf.write(buf, 0, len);
						loadLen += len;
						RandomAccessFile tempRaf = new RandomAccessFile(getFilePath(path) + "_" + tag + ".txt", "rwd");
						tempRaf.write(String.valueOf(loadLen).getBytes());
						System.out.println(Thread.currentThread().getName() + "/loadLen:" + loadLen);
						tempRaf.close();
					}
					raf.close();
					iStream.close();
					conn.disconnect();
					mBarrier.await();
					System.out.println(Thread.currentThread().getName() + "/ await");
				}
			} catch (MalformedURLException | InterruptedException | BrokenBarrierException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		private long buildTempFile(String path, int tag) {
			String filePath = getFilePath(path) + "_" + tag + ".txt";
			System.out.println("filePath:" + filePath);
			File file = new File(filePath);
			if(file.exists()){
				try {
					BufferedReader bufr = new BufferedReader(new FileReader(file));
					String count = bufr.readLine();
					bufr.close();
					return Long.parseLong(count);
				} catch (IOException e) {
					e.printStackTrace();
				}
				return 0;
			}else{
				try {
					file.createNewFile();
					BufferedWriter bufW = new BufferedWriter(new FileWriter(file));
					bufW.write(String.valueOf(0));
					bufW.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				return 0;
			}
		}
	}
	
	private String getFilePath(String path) {
		return "d:\\download\\" + path.substring(path.lastIndexOf("/") + 1);
	}
	
	/** 下载完成之后清除相应的缓存数据  */
	public class ClearCacheThread extends Thread{
		private String path;
		public ClearCacheThread(String path){
			this.path = path;
		}
		
		@Override
		public void run() {
			System.out.println("下载完成-" + path);
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值