通过使用CyclicBarrier类来实现并发抓取网络图片:
CyclicBarrier是一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为
循环 的 barrier。
CyclicBarrier 支持一个可选的
Runnable
命令,在一组线程中的最后一个线程到达之后(但在释放所有线程之前),该命令只在每个屏障点运行一次。若在继续所有参与线程之前更新共享状态,此
屏障操作 很有用。
实现的下载器代码如下:
package com.kkoolerter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
* 多线程网络图片下载器
*
* @author Jenson
*
*/
public class Downloader extends Thread {
private CyclicBarrier cb;
private String urlStr;
private String saveFileName;
public Downloader(String name, String url, String saveFileName,
CyclicBarrier cb) {
this.setName(name);
this.cb = cb;
this.urlStr = url;
this.saveFileName = saveFileName;
}
@Override
public void run() {
try {
System.out.println("开始下载"+this.saveFileName+"...");
URL url = new URL(this.urlStr);
DataInputStream dis = new DataInputStream(url.openStream());
OutputStream fos = new FileOutputStream(new File(this.saveFileName));
byte[] buff = new byte[1024];
int len = -1;
while((len = dis.read(buff))!=-1){
fos.write(buff, 0, len);
}
buff = null;
fos.close();
dis.close();
System.out.println("下载文件"+this.saveFileName+"完成");
this.cb.await();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
测试代码:
package com.kkoolerter;
import java.util.concurrent.CyclicBarrier;
public class CycleBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cb = new CyclicBarrier(10);
new Downloader("d1", "http://img2.3lian.com/img2007/17/08/001.jpg", "001.jpg", cb).start();
new Downloader("d2", "http://img2.3lian.com/img2007/17/08/002.jpg", "002.jpg", cb).start();
new Downloader("d3", "http://img2.3lian.com/img2007/17/08/003.jpg", "003.jpg", cb).start();
new Downloader("d4", "http://img2.3lian.com/img2007/17/08/004.jpg", "004.jpg", cb).start();
new Downloader("d5", "http://img2.3lian.com/img2007/17/08/005.jpg", "005.jpg", cb).start();
new Downloader("d6", "http://img2.3lian.com/img2007/17/08/006.jpg", "006.jpg", cb).start();
new Downloader("d7", "http://img2.3lian.com/img2007/17/08/007.jpg", "007.jpg", cb).start();
new Downloader("d8", "http://img2.3lian.com/img2007/17/08/008.jpg", "008.jpg", cb).start();
new Downloader("d9", "http://img2.3lian.com/img2007/17/05/0849m.jpg", "0849m.jpg", cb).start();
new Downloader("d10", "http://img2.3lian.com/img2007/17/05/08943m.jpg", "0849m.jpg", cb).start();
}
}
上述示例在我的电脑运行的结果如下:
开始下载001.jpg...
开始下载002.jpg...
开始下载004.jpg...
开始下载006.jpg...
开始下载008.jpg...
开始下载0849m.jpg...
开始下载003.jpg...
开始下载005.jpg...
开始下载0849m.jpg...
开始下载007.jpg...
下载文件002.jpg完成
下载文件007.jpg完成
下载文件001.jpg完成
下载文件003.jpg完成
下载文件006.jpg完成
下载文件0849m.jpg完成
下载文件004.jpg完成
下载文件0849m.jpg完成
下载文件008.jpg完成
下载文件005.jpg完成
参考文献:JDK文档