0

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

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

我对线程有点困惑,找不到任何与此类似的示例。我本质上想要多个线程将他们的单词输出到一个 SortedMap 中,这样我就可以获得实时的总字数。

我该怎么做呢?

谢谢

4

3 回答 3

2
  1. 如果要让多个线程写入地图,则需要使用 a ConcurrentSkipListMap,它既是 aSortedMap又是 a ConcurrentMap
  2. 您可以为CharacterReader集合中的每个创建一个Runnable调用wordCount函数(访问前面描述的映射)的 a。
  3. 创建Runnables 后,您可以创建一个ExecutorService(例如使用Executors.newCacheThreadPool()),将所有Runnables 传递给它并等待它们完成(参见class的javadocExecutorService中的示例)。

您也可以在将Runnables 发送到ExecutorService.

于 2012-07-18T20:48:18.563 回答
1

vainolo 和 JB 的答案都很好。

我将添加一件事,即描述如何制作一个高度并发的数据结构来存储您的字数。

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

您可以使用 ConcurrentMap 的putIfAbsent方法安全地向地图添加新事物。但是,仅此还不够,因为您每次使用它时都必须提供潜在价值,这可能很昂贵。最简单的做法是使用一种双重检查锁定模式,您首先简单地尝试获取现有值,然后如果发现没有,则使用 putIfAbsent 添加一个新值(您不能简单地调用 put,因为两个线程同时 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;
    }
}
于 2012-07-18T21:30:20.280 回答
1

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

创建此类的一个实例。使用Executors类创建具有ExecutorService您想要的特征的对象。

然后遍历集合,并为每个阅读器创建一个Callable或一个Runnable用在此阅读器中找到的单词填充 WordMap 实例,并将此Callable或提交RunnableExecutorService.

于 2012-07-18T20:46:30.333 回答