首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Java中使用线程安全集合时,处理并发问题的最佳方法是什么?

在Java中使用线程安全集合时,处理并发问题的最佳方法是什么?
EN

Stack Overflow用户
提问于 2013-10-01 15:47:46
回答 4查看 4.8K关注 0票数 2

这可能是我的天真之举,但我总是假设下面的代码示例在使用Java中的线程安全集合时总是可以工作,而不会与NullPointerException崩溃。不幸的是,线程t2似乎能够从调用containsKey()和在两个线程声明下面的get()方法之间的列表中删除该项。注释部分展示了一种在不获取NullPointerException的情况下处理此问题的方法,因为它只是测试get()的结果是否为null。

我的问题是,使用线程安全集合在Java中处理这个问题的正确方法是什么?当然,我可以使用互斥锁或同步块,但这种失败不是很大的好处,而且在线程安全集合方面使用起来也很容易吗?如果我必须使用互斥或同步块,难道我不能只使用非线程安全集合吗?此外,我一直听说(在学术界)检查代码中的空值是不好的编程实践。我只是疯了吗?这个问题有简单的答案吗?提前谢谢你。

代码语言:javascript
运行
复制
package test;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class Test {
    public static void main(String[] args) {
        final Map<Integer, Integer> test = new ConcurrentHashMap<>();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true) {
                    test.put(0, 0);
                    Thread.yield();
                }
            }           
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true) {
                    test.remove(0);
                    Thread.yield();
                }
            }           
        });

        t1.start();
        t2.start();

        while(true) {
            if (test.containsKey(0)) {
                Integer value = test.get(0);
                System.out.println(value);
            }
            Thread.yield();
        }   

        // OR
//      while(true) {
//          Integer value = test.get(0);
//          if (value != null) {
//              System.out.println(value);
//          }
//          Thread.yield();
//      }           
    }
}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-10-01 15:51:12

使用线程安全集合在Java中处理这个问题的正确方法是什么?

只执行一次操作,因此它是原子的。它也更快。

代码语言:javascript
运行
复制
    Integer value = test.get(0);
    if (value != null) {               
         System.out.println(value);
    }

我一直听说(在学术界)检查代码中的空值是不好的编程实践。我只是疯了吗?

有可能。我认为检查null,如果值可以是null,是最好的做法。

票数 3
EN

Stack Overflow用户

发布于 2013-10-01 15:50:36

代码语言:javascript
运行
复制
if (test.containsKey(0)) {
     Integer value = test.get(0);
     System.out.println(value);
}

仍然不是原子的。在检查containsKey之后,线程可以添加/删除。

您需要在该片段周围的共享资源上同步。或者在null之后检查get

ConcurrentHashMap中的所有操作都是线程安全的,但它们不会扩展过去的方法边界。

票数 2
EN

Stack Overflow用户

发布于 2013-10-01 15:50:50

你在滥用线程安全的集合。

线程安全集合无法阻止其他代码在containsKey()get()之间运行。

相反,它们为您提供了额外的线程安全方法,这些方法将原子地检查和获取元素,而不允许其他线程干预。

这意味着您不应该通过基本集合接口(MapList)使用并发集合。

相反,将您的字段声明为ConcurrentMap

在您的示例中,您可以简单地调用get(),如果找不到键,它将原子地返回null。

在这里,除了检查null之外,别无选择。(与更优雅的函数语言不同,函数语言使用的可能是monad )

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19120594

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档