Java线程之CountDownLatch

来源:互联网 发布:网络诈骗代办信用卡 编辑:程序博客网 时间:2024/05/27 16:43

CountDownLatch是一个高级的线程同步工具,可以理解为一个闸门,先运行一些线程,计算出一些结果,满足条件后,开闸,然后另一些线程启动。换句话说,它将多个线程分为2类,一类开闸前运行,一类开闸后运行。

对于开闸后运行的线程,调用await()方法后,进入等待状态,等待开闸。它内部有一个计数器,初始状态计数器为用户设定的正整数,当开闸前某个线程运行完毕后,调用它的countDown()方法将计数器减1,当计数器为0时,开闸。

典型应用:统计硬盘上文件的数目。针对硬盘的每一个分区,例如C盘、D盘、E盘等,单独开一个线程统计该分区内的文件数。另设一个线程对所有分区的文件数汇总,显示给用户,此线程运行在开闸后,必须等每个分区都统计完毕之后,开闸,汇总报告给用户。countDown()方法最好不要由开闸前的线程直接调用,而应该由汇总线程对其进行封装,开闸前的线程之调用封装后的方法,CountDownLatch尽量对开闸前的线程透明。

/** * 负责将多线程查找的各分区文件数目合并汇总, * 打印出硬盘上存在的总文件数 */class CombineResult implements Runnable {private CountDownLatch latch;private long fileCount;public CombineResult(int n) {latch = new CountDownLatch(n);fileCount = 0;}public synchronized void commitResult(long count) {fileCount += count;latch.countDown();}@Overridepublic void run() {try {latch.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("\n硬盘上共有" + fileCount + "个文件");}}/** * 统计一个硬盘分区内的文件数 */class CountFilesInPartition implements Runnable{private CombineResult result;private Path partition;//需要Java 1.7支持private long count;public CountFilesInPartition(CombineResult result, Path partition) {this.result = result;this.partition = partition;count = 0;}@Overridepublic void run() {long n;n = countFiles(partition);result.commitResult(n);}private long countFiles(Path p) {if(Files.isDirectory(p)) {try(DirectoryStream<Path> paths = Files.newDirectoryStream(p)) {for(Path path:paths) {count = countFiles(path);}} catch (IOException e) {}}else {count++;}return count;}}/** * 进度条 */class ProgressBar extends Thread{private int interval;//显示进度的时间间隔,单位是毫秒public ProgressBar(int interval) {this.interval = interval;setDaemon(true);}@Overridepublic void run() {System.out.print("正在进行中");while(true) {try {Thread.sleep(interval);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.print(" .");}}}public class CountFile {public static void main(String[] args) {int ptCount = getPartitionCount();CombineResult result = new CombineResult(ptCount);new Thread(result).start();Iterable<Path> partitions = FileSystems.getDefault().getRootDirectories();for(Path p:partitions) {new Thread(new CountFilesInPartition(result, p)).start();}new ProgressBar(1000).start();}private static int getPartitionCount() {Iterable<Path> partitions = FileSystems.getDefault().getRootDirectories();int n = 0;for(Path p:partitions) {n++;}return n;}}

以下是不使用CountDownLatch,而是直接使用Lock和Condition的实现,做一个对比

public class CountFiles {/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stublong start = System.currentTimeMillis();Iterable<Path> drivers = FileSystems.getDefault().getRootDirectories();int n = 0;for(Path driver:drivers) {n++;}Result r = new Result(n);for(Path driver:drivers) {new MyThread(driver, r).start();}System.out.println(r.getFileCount());System.out.println(System.currentTimeMillis()-start);}private static class MyThread extends Thread {private Path driver;private long count;private Result result;public MyThread(Path driver, Result r) {super();this.driver = driver;count = 0;result = r;}@Overridepublic void run() {countFiles(driver);result.addFileCount(count);result.cutThreadCount();}private void countFiles(Path path) {if(Files.isDirectory(path)) {DirectoryStream<Path> paths;try {paths = Files.newDirectoryStream(path);for(Path p:paths) {countFiles(p);}} catch (IOException e) {}}else {count++;}}}private static class Result {private long fileCount = 0;private int threadCount = 0;public Result(int n) {threadCount = n;}public synchronized void addFileCount(long n) {fileCount += n;}public synchronized long getFileCount() {while(threadCount >0) {try {wait();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}return fileCount;}public synchronized void cutThreadCount() {threadCount--;notifyAll();}}}


原创粉丝点击