构造多个线程以将单词输出到地图

时间:2012-07-18 20:36:42

标签: java multithreading

我有一个wordCount(CharacterReader charReader)函数,它接受一个字符流,将它们转换为单词。

我还有一个Collection<CharacterReader> characerReaders,包含多个字符流。集合中的读者数量可能会有所不同,我想从所有流中读取并计算所有单词。

我对线程有点困惑,找不到任何类似的例子。 我基本上希望多个线程将他们的单词输出到SortedMap,这样我就可以实时计算总字数。

我将如何做到这一点?

由于

3 个答案:

答案 0 :(得分:2)

  1. 如果您要将多个主题写入地图,则需要使用ConcurrentSkipListMap SortedMapConcurrentMap
  2. 您可以为集合中的每个CharacterReader创建一个调用Runnable函数的wordCount(访问前面描述的映射)。
  3. 创建Runnable后,您可以创建ExecutorService(例如使用Executors.newCacheThreadPool()),将其全部传递给Runnable并等待它们完成(请参阅类ExecutorService的{​​{3}}中的示例。)
  4. 您也可以在将Runnable发送到ExecutorService之前创建{{1}}。

答案 1 :(得分:1)

创建一个WordMap类,它封装您的有序地图,并确保所有对地图的访问都已正确同步。或者使用已经是线程安全的并发映射。

创建此类的实例。使用Executors类创建具有所需特征的ExecutorService

然后遍历集合,并为每个读者创建一个CallableRunnable填充WordMap实例,其中包含此阅读器中的单词,并提交此Callable或{ {1}} Runnable

答案 2 :(得分:1)

vainolo和JB的答案都很好。

我将添加一个内容,即描述如何建立高度并发的数据结构来存储您的字数。

正如vainolo所说,ConcurrentSkipListMap是你想要的基本数据结构,因为它既有排序又有并发。为了好好利用它,你想避免做任何锁定。这意味着您必须避免涉及锁定 - 读 - 写 - 解锁周期的模式。这有两个结果:首先,在地图中添加一个新单词不应该涉及锁定,并且增加现有单词的计数不应该涉及锁定。

您可以使用ConcurrentMap的putIfAbsent方法安全地向地图添加新内容。然而,仅凭这一点还不够,因为每次使用它时都必须提供潜在的价值,这可能很昂贵。最简单的方法是使用一种双重检查的锁定模式,你首先只是尝试获取一个现有值,然后如果你发现没有一个,用putIfAbsent添加一个新模式(你不能简单地call put,因为两个线程之间可能会同时发生竞争。)

通过不在地图中存储整数,而不是在整数中包含整数的对象,可以轻松地进行无锁定的增量。这样,您就不必在地图中添加增量值,只需增加已存在的对象即可。 AtomicInteger似乎是一个很好的候选人。

把它们放在一起,你得到:

public class WordCounts {
    private final ConcurrentMap<String, AtomicInteger> counts
         = new ConcurrentSkipListMap<String, AtomicInteger>();

    public void count(String word) {
        AtomicInteger count = getCount(word);
        count.incrementAndGet();
    }

    private AtomicInteger getCount(String word) {
        AtomicInteger count = counts.get(word);
        if (count == null) {
            AtomicInteger newCount = new AtomicInteger();
            count = counts.putIfAbsent(word, newCount);
            if (count == null) count = newCount;
        }
        return count;
    }
}