为了账号安全,请及时绑定邮箱和手机立即绑定

并发和并发数据结构

并发和并发数据结构

人到中年有点甜 2021-08-06 10:06:40
我正在练习一点并发。public class WordOccurrencesBigFile {    private String words;    private ConcurrentHashMap<String, Pair<String, Integer>> wordOccurrencesMap = new ConcurrentHashMap<>();    public WordOccurrencesBigFile(String wordsLine) {        this.words = wordsLine;    }    public void processWords() {        parseWordsLines();        printOrderAlphabetically();        printOrderByCount();        printByInsertionOrder();    }    private void parseWordsLines() {        String[] wordsLinesArray = words.split("\n");        ExecutorService executor = Executors.newFixedThreadPool(5);        for(String wordsLine: wordsLinesArray) {            executor.execute(() -> parseWords(wordsLine));        }        executor.shutdown();        while (!executor.isTerminated()) {        }        System.out.println("Finished all threads");    }    private void parseWords(String wordsLine) {        System.out.println(Thread.currentThread().getName() + " Start.");        System.out.println(Thread.currentThread().getName() + " Processing line: '" + wordsLine + "'");        String[] wordsArray = wordsLine.split(" ");}}在 parseWordsLines 上,使用 5 个线程池创建了一个 ExecutorService,并且 WordOccurrencesBigFile 类使用由“\n”创建的多行字符串实例化。目的是让每一行由不同的线程处理,并在 Map 上插入唯一单词的计数。我期望通过使用 ConcurrentHashMap 足以处理我有多个线程读取和写入地图的事实。但是在我执行课程的大部分时间里,我得到了不同的计数。(奇怪的是主要是针对“bb”这个词。但是添加了 synchronized(this) 问题就解决了。有人可以解释为什么这种行为,解决这个问题的最佳方法,我应该将“this”传递给同步块或线程正在访问的对象吗?
查看完整描述

3 回答

?
慕后森

TA贡献1802条经验 获得超5个赞

ConcurrentHashMap 是线程安全的,可以保证每一个操作都是线程安全的。


但是这些操作不是原子的:


            if (!wordOccurrencesMap.containsKey(word)) {

                pair = new Pair<>(word, 1);

                //System.out.println(Thread.currentThread().getName() + " Creating Pair: " + pair);

            } else {

                pair = wordOccurrencesMap.get(word);

                pair.setValue(pair.getValue() + 1);

                //System.out.println(Thread.currentThread().getName() + " Updating Pair: " + pair);

            }


            wordOccurrencesMap.put(word, pair);

您可以改为使用单个操作:


wordOccurrencesMap.compute(word,

        (s, pair) -> pair == null ?

                new Pair<>(word, 1) : pair.setValue(pair.getValue() + 1));


查看完整回答
反对 回复 2021-08-06
?
蓝山帝景

TA贡献1843条经验 获得超7个赞

好吧,添加可以synchronized(this)解决问题,但是您将失去多线程和并行化的所有好处。


你需要的是 的computeIfAbsent方法ConcurrentMap。所以你的for循环体将转换为


Pair<String, Integer> pair = wordOccurrencesMap.computeIfAbsent(word, w -> new Pair<>(w, 0));

synchronized(pair) {

    pair.setValue(pair.getValue()+1);

}

现在你可以省略你的synchronized(this)块。


编辑:但是您必须确保当第一个线程调用pair.setValue() 时,没有另一个线程可以调用pair.getValue(),如注释所述。


查看完整回答
反对 回复 2021-08-06
  • 3 回答
  • 0 关注
  • 143 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信