Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 我的代码已经是线程安全的了吗_Java_Multithreading - Fatal编程技术网

Java 我的代码已经是线程安全的了吗

Java 我的代码已经是线程安全的了吗,java,multithreading,Java,Multithreading,我有一个单身班: public class MySingleton { private static MySingleton instance; // here the Map entry's value is also a Map private Map<String, Map> dataMap; private MySingleton() { dataMap = new HashMap<String, Map>(); Map&

我有一个单身班:

public class MySingleton {
  private static MySingleton instance;

  // here the Map entry's value is also a Map
  private Map<String, Map> dataMap;

  private MySingleton() {
     dataMap = new HashMap<String, Map>();

     Map<String, String> dataTypeOneMap = new HashMap<String, String>();
     Map<String, String> dataTypeTwoMap = new HashMap<String, String>();

     dataMap.put("dataTypeOne", dataTypeOneMap);
     dataMap.put("dataTypeTwo", dataTypeTwoMap);

  }

  public static MySingleton getInstance() {
     if(instance == null) {
        instance = new MySingleton();
     }
     return instance;    
  }

  public synchronized void storeData(String data, String type) {
       dataMap.get(type).put("my_data", data);
  } 

  public synchronized String getData(type) {
       return dataMap.get(type).get("my_data");
  } 
}

对于
dataMap
,是否需要使用
ConcurrentHashMap
类型?或者它已经是线程安全的了?我觉得我的代码已经是线程安全的了,但我只是想确保没有任何极端情况会破坏它。谢谢。

简短回答

这部分代码不是线程安全的:

  public static MySingleton getInstance() {
    if(instance == null) {
      instance = new MySingleton();
    }
    return instance;    
  }
长答案

让我们逐一处理代码部分

例如,假设一个线程正在执行getInstance方法,并且达到了if条件:

if(instance == null) {
现在,如果另一个线程开始调用该方法,if条件仍然为true,它还将尝试创建一个新实例。因此,它可能会创建一些用例:

  • 两个调用方法将以不同的实例结束
  • 稍后的线程将覆盖先前创建的实例的实例,反之亦然
  • 解决方案:

    同步实例创建块:

    synchronized(MySingleton.class){
      if(instance == null) {
        instance = new MySingleton();
      }
    }
    

    不,它不是线程安全的。使用允许从不同线程进行访问和修改。它还允许您异步读取映射,而不会影响性能


    同步getInstance()方法,并尽量减少对该方法的调用量-在另一个线程上运行的每个对象上存储对单例的引用以避免重复getInstance()调用将有所帮助。

    根据注释,实例的延迟实例化不是线程安全的,即如果两个线程调用
    getInstance()
    同时进行两次调用可能会导致
    instance=new MySingleton()
    甚至返回一个不同的
    实例
    ,这意味着两个线程操作不同的对象

    要解决这个问题,您可以在类本身上同步
    getInstance()
    ,甚至使用双重检查锁定来减少同步开销(如果您不能首先消除懒惰):

    使用双重检查锁定,您将只能同步创建部分,检查null并返回实例(如果不是null),而不必是线程安全的

  • 线程安全单例

    您可以通过以下帖子定义线程安全的LazySingleton:

  • 您的
    dataMap
    是线程安全的。但是您可以进一步优化代码。您可以用
    ConcurrentHashMap
    替换
    Map
    ,并在
    storeData
    getData
    方法中删除
    synchronized



  • 您可以查看此文档页面,了解它是否真的必须懒惰?那部分不是线程安全的。@Fildor,你能分享更多你的想法吗?谢谢。除了问题:请注意,如果
    type
    的值不在映射中,您会在storeData中得到一个NPE。请考虑两个线程第一次调用
    getInstance()
    :两个线程都可能得到不同的实例,因为在调用
    instance
    时为空,如果一个线程调用
    storeData(),您将丢失数据
    在一个被另一个覆盖的实例上。还有其他详细信息吗?它们是如何修复的?这就是您回答问题的方式。请您解释一下“它不是线程安全的”,谢谢。请注意,
    在静态方法中不可用。“你需要另一个锁监视器,例如班级本身”。@Thomas,好帮手。错过了。使用适当的解决方案更新答案。使用
    ConcurrentHashMap
    无法解决
    getInstance()
    不具备线程安全性的问题,但它是一个单一的、已使用的公共方法
    synchronized
    关键字,为什么它不具备线程安全性?你能再解释一下吗?谢谢。因为
    私有静态MySingleton实例getInstance()
    多次重新分配code>,因为此方法不可用synchronized@Brad仅当他没有在每个数据库上存储对象的实例时thread@Brad如何重新分配MySingleton?单例的目的不是为了防止这种事情发生吗?在Java 8中,
    实例
    是否仍然必须是易变的?复杂的东西:)@Fildor啊,我不完全确定,但根据“读取和写入对于引用变量是原子的”所以我说不。-更新:根据Jack volatile链接的wiki文章,volatile可能仍然有助于防止由于编译器重新排序而导致的错误。添加
    volatile
    无论如何都不会有什么坏处。@Thomas,因此,作为一个结论,
    dataMap
    不需要使用ConcurrentHashMap,对吗?只有延迟初始化才是需要解决的问题?对于
    实例
    变量,使用
    volatile
    很好,我还好吗?@Leem.fin看看Jack链接的wiki文章。当然,我会包括
    volatile
    。至于映射:如果同步所有访问映射的方法,但删除该同步并使用
    ConcurrentHashMap
    可以提高性能,那么就不需要
    ConcurrentHashMap
    ,因为它使用(大部分)无锁算法(即,不同存储桶上的写入/读取通常根本不需要同步)。
    synchronized(MySingleton.class){
      if(instance == null) {
        instance = new MySingleton();
      }
    }
    
    private volatile MySingleton  instance;
    
    public static MySingleton getInstance() {
      //check if the instance doesn't exist yet, this is not threadsafe
      if(instance == null) {
        //the instance doesn't exist yet so synchronize and check again, since another thread 
        // might have entered this block in the meantime and instance is not null anymore
        synchronized(MySingleton.class) {
          if(instance == null) {
            instance = new MySingleton();
          }
        }
      }
      return instance;    
    }