多个文件开启固定线程等待下载--java实现
来源:互联网 发布:雷云网络不可用 编辑:程序博客网 时间:2024/06/05 15:54
今天群友的一个需求,无聊中,所以写了个小的demo。
需求:要下载多个文件,但同时下载的文件最多为3个,如果超过则显示“等待下载”,等有文件下载完成后再从“等待下载”中开始下载,这样的下载应该在很多地方见过。
思路:这里不考虑多线程下载单个文件的情况,一切从简出发。先想到的是利用线程池(池A)把所有要下载的文件封装成一个线程放在这里做为资源,再有一个线程池(池B)用来存放正在下载的线程,池B类似生产者消费者模型。下载完一个后就从池B中移除,再从池A中添加一个进来。直到池A的线程用完。
需要考虑的是怎么知道什么时候池B要移除,池A要添加进去呢?且看代码:
下载的线程DownloadThread.java
public DownloadThread(String url, String toPath) { try { this.url = url; this.file = new File(toPath); }catch (Exception e){ System.err.println("Stub!"); } }
每个线程要下载的文件路径,和要保存的路径,当然也可以从url中解析出文件名,然后再默认一个存放路径,这样就只要传一个参数了,但现在:一切从简。
private volatile boolean isFinish = false;//是否下载完成
设置一个标志位,用来表示是否下载完成 ,在判断池B是否要移除当前线程很重要。
public void start(){ new Thread(new Download()).start(); }
开启下载。
class Download implements Runnable { private void downloadURL(){ InputStream is = null; FileOutputStream fos = null; try { URL uri = new URL(url); URLConnection conn = uri.openConnection(); conn.setDoInput(true); conn.setConnectTimeout(10 * 1000); is = conn.getInputStream(); fos = new FileOutputStream(file); byte[] buffer = new byte[1024]; int length = 0; while(-1 != (length = is.read(buffer))){ fos.write(buffer, 0, length); } is.close(); fos.flush(); fos.close(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(null != is) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } if(null != fos){ try { fos.flush(); } catch (IOException e) { e.printStackTrace(); } try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Override public void run() { if(null != url && !("").equals(url) && null != file){ //开启下载到本地 System.out.println(System.currentTimeMillis() + "current thread start==>" + hashCode()); downloadURL(); System.out.println(System.currentTimeMillis() + "current thread end==>" + hashCode()); isFinish = true; } } }
很简单,就是一个下载文件的线程。
线程池,其实包含了所有对线程的操作,没有再向上抽取一层了CustomThreadPool.java
private List<DownloadThread> customPool;// 线程池 private List<DownloadThread> startedPool; // 已开启的线程
定义两个线程池,也就是上面说的池A和池B
/** * 增加一个线程 * * @param thread */ public void addThread(DownloadThread thread) { customPool.add(thread); }
定义一个方法,把下载线程加到线程池中。
/** * 读取开启线程池 * @author Wicky * */ class StartPoolListener implements Runnable { boolean isRun = true; public void setIsRun(boolean isRun) { this.isRun = isRun; } @Override public void run() { while (isRun) { for (int i = 0; i < startedPool.size(); i++) { DownloadThread thread = startedPool.get(i); if (null != thread && thread.isFinish()) { //手动保证集合并发安全 synchronized (thread) { startedPool.remove(i); } } } } } }
另一个辅助线程,用来监听什么时候该移除线程,添加一个新线程了。
public void start() { // 开启消费者监听 StartPoolListener lsn = new StartPoolListener(); Thread startPoolThread = new Thread(lsn); startPoolThread.start(); // 不停的读取线程池中的线程,直到全部执行完成 while (customPool.size() > 0) { // System.out.println("thread pool left==>" + customPool.size()); // 每次取最后一个线程 DownloadThread thread = customPool.get(customPool.size() - 1); if (startedPool.size() < threadCount) { // 开始线程 thread.start(); // 追加到已开启的线程中 startedPool.add(thread); // 从原来的线程池中移除掉 customPool.remove(thread); } } lsn.setIsRun(false); startPoolThread.interrupt(); }
然后开始下载……这里分三块。
一、先开启一个监听线程
二、然后开始不停的读池A里的东西,如果发现池B中的数量小于指定的数量,就往里面添加一个新的线程
三、关闭监听线程
测试床MainTest.java
public static void main(String[] args){ String url1 = "http://f.hiphotos.baidu.com/image/pic/item/cc11728b4710b9125dcaf2ffc1fdfc03924522a3.jpg"; String url2 = "http://h.hiphotos.baidu.com/image/w%3D230/sign=f7bc78ce32adcbef013479059caf2e0e/5d6034a85edf8db1ec0d3d6e0a23dd54564e749c.jpg"; String url3 = "http://h.hiphotos.baidu.com/image/w%3D230/sign=56e13fbfaa014c08193b2fa63a7a025b/6a63f6246b600c3338816cde194c510fd9f9a128.jpg"; String url4 = "http://f.hiphotos.baidu.com/image/w%3D230/sign=e07d0317932397ddd6799f076983b216/8d5494eef01f3a29a8b0ef3e9b25bc315d607cc1.jpg"; String url5 = "http://c.hiphotos.baidu.com/image/pic/item/63d0f703918fa0ec4a43ba4c249759ee3c6ddbef.jpg"; String url6 = "http://h.hiphotos.baidu.com/image/pic/item/2e2eb9389b504fc2022d2904e7dde71190ef6d45.jpg"; String url7 = "http://g.hiphotos.baidu.com/image/w%3D230/sign=06cb213db8a1cd1105b675238912c8b0/d01373f082025aaf5a18bbc6f9edab64034f1a91.jpg"; DownloadThread thread1 = new DownloadThread(url1, "D:\\1.jpg"); DownloadThread thread2 = new DownloadThread(url2, "D:\\2.jpg"); DownloadThread thread3 = new DownloadThread(url3, "D:\\3.jpg"); DownloadThread thread4 = new DownloadThread(url4, "D:\\4.jpg"); DownloadThread thread5 = new DownloadThread(url5, "D:\\5.jpg"); DownloadThread thread6 = new DownloadThread(url6, "D:\\6.jpg"); DownloadThread thread7 = new DownloadThread(url7, "D:\\7.jpg"); CustomThreadPool pool = CustomThreadPool.getInstance(4); pool.addThread(thread1); pool.addThread(thread2); pool.addThread(thread3); pool.addThread(thread4); pool.addThread(thread5); pool.addThread(thread6); pool.addThread(thread7); //开启下载 pool.start(); }
线程操作还是有点不熟练,这里也只是提供下思路,肯定还会有更好的解决方案,大神勿喷
免费下载源码:http://download.csdn.net/detail/aj1031689/8909799
- 多个文件开启固定线程等待下载--java实现
- Java等待多个线程执行完毕
- Java 实现多条线程 下载文件
- java实现多个文件打包下载
- android开启多个线程网络获取数据后,等待所有线程完毕后跳转
- 【Java】Java实现zip压缩多个文件下载
- Java单线程文件下载实现
- java web 实现多个文件压缩下载
- Java实现zip压缩多个文件下载
- java实现多个线程互斥访问文件
- Web文件下载等待效果的实现
- java实现word下载及打包成zip下载(单个文件、多个文件)
- 【Java】之 写个线程下载文件(支持断点续传)
- 用JAVA实现线程等待提示框
- 用JAVA实现线程等待提示框
- 用JAVA实现线程等待提示框
- 用JAVA实现线程等待提示框
- 用JAVA实现线程等待提示框
- KEILC51编译问题ERROR L104: MULTIPLE PUBLIC DEFINITIONS
- 简述sleep()函数与wait()函数的区别
- codevs1008
- C++多线程编程入门
- openstack问题记录
- 多个文件开启固定线程等待下载--java实现
- Vmware克隆Centos后 重新设置eth0
- iOS NSString 与NSData转化
- 当中流击水,浪遏飞舟
- Matlab中数据拟合(简单粗暴不用写代码)
- NSNotificationCenter 发送 接受处理
- 我的Android进阶之旅------>如何将Activity变为半透明的对话框?
- android 自动化测试工具Robotium 之Solo类的详细说明
- PHP下载远程图片的3个方法