使用BlockingQueue

时间:2013-12-07 21:20:05

标签: java blockingqueue

我正在尝试在我的代码中使用队列。关键是我希望它打印出文件中Word的总量,这意味着我需要它在完成后将所有结果一起添加。

目前,我的程序所做的是,我有一个运行文件的阅读器,并返回一个包含文件名称及其中单词数量的字符串。然后我使用我的main方法为args数组中给出的每个参数运行for循环。每当我们通过一个新文档检查有多少单词时,我们就会把它作为一个新的主题。

public static void main(final String[] args) {
    Thread t = null;
    if (args.length >= 1) {
        String destinationFileName = args[(args.length-1)];
            for (int l = 0; l < (args.length); l++) {
                final int q = l;
                final Thread y = t;
                Runnable r = new Runnable() {
                    public void run() {
                        String res = readTextFile(args[q]);
                        System.out.println(res);
                    }
                };
                t = new Thread(r);
                t.start();
            }
    } else {
        System.err.println("Not enough input files");
    }
}

那么,我如何建立一个以某种方式使他们彼此等待的队列,这样就不会错误地在同一时间添加结果呢?

2 个答案:

答案 0 :(得分:0)

此处似乎不需要阻塞队列。只需让每个线程将其结果添加到线程安全列表中,该列表可以像这样构造:

final List<String> results = 
        Collections.synchronizedList(new ArrayList<String>());

接下来,您希望在聚合结果之前等待所有线程完成。您可以通过在每个线程上调用join来完成此操作。将每个线程添加到名为threads的列表中,然后一旦所有线程都已启动,请调用:

for(Thread t : threads) {
    t.join();
}

此代码将有效地等待每个线程完成后再继续。

答案 1 :(得分:0)

这是一个非常常见的例子,当需要多个线程来处理IO操作,比如从磁盘读取文件时,我想这是用于辅导的目的,对于现实生活中的例子,考虑查看地图缩减框架,如Hadoop

了解如何使用hadoop here

完成类似的任务

但是,遵循一个伪示例:

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

class ConsumerProducer implements Runnable {
    private final BlockingQueue<String> map;
    private final BlockingQueue<Map<String, Integer>> reduce;

    ConsumerProducer(BlockingQueue<String> map,
            BlockingQueue<Map<String, Integer>> reduce) {
        this.map = map;
        this.reduce = reduce;
    }

    public void run() {
        try {
            while (true) {
                Map<String, Integer> wordToOccurrences = this.consume(map
                        .take());
                this.produce(wordToOccurrences);
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private void produce(Map<String, Integer> wordToOccurrences)
            throws InterruptedException {
        reduce.put(wordToOccurrences);
    }

    public Map<String, Integer> consume(String fileName) {
        // read the file and return 'word' -> number of occurrences
        return new HashMap<String, Integer>();
    }
}

class Setup {

    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> map = new LinkedBlockingQueue<String>();
        BlockingQueue<Map<String, Integer>> reduce = new LinkedBlockingQueue<Map<String, Integer>>();

        for (String fileName : args) {
            map.put(fileName);
            // assuming every thread process single file, for other options see
            // http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
            ConsumerProducer c = new ConsumerProducer(map, reduce);
            new Thread(c).start();
        }

        for (int i = 0; i < args.length; i++) {
            Map<String, Integer> wordToOccurrences = reduce.take();
            // start consuming results
        }

        // print merged map of total results
    }
}