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

时间:2017-03-10 13:02:35

标签: 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<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");
  } 
}

多个线程可以访问公共方法storeData(...)&amp; getData(...)。 e.g:

MySingleton.getInstance().storeData("hello", "dataTypeOne");

MySingleton.getInstance().getData("dataTypeOne");

我需要ConcurrentHashMap使用dataMap类型吗?或者它已经是线程安全的?我觉得我的代码已经是线程安全的,但只是想确保没有角落案例会破坏它。感谢。

4 个答案:

答案 0 :(得分:4)

根据注释,实例的延迟实例化不是线程安全的,即如果2个线程同时调用getInstance()两个调用都可能导致instance = new MySingleton();,甚至返回不同的instance意味着两个线程都在不同的对象上运行。

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

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;    
}

使用双重检查锁定,你只能同步创建部分,检查null并返回实例,如果它不是null,则不必是线程安全的。

答案 1 :(得分:1)

简短回答

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

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

答案很长

让我们一个一个地处理代码部分。

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

if(instance == null) {

现在,如果另一个线程开始调用该方法,则if条件仍为true,并且还将尝试创建新实例。所以它可能会创建一些用例:

  1. 两种调用方法将以不同的实例结束。
  2. 后来的线程会覆盖先前创建的实例的实例,反之亦然。
  3. <强>解决方案:

    同步实例创建块:

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

答案 2 :(得分:0)

不,它不是线程安全的。使用ConcurrentHashMap允许从不同的线程进行访问和修改。它还允许您在没有性能命中的情况下异步读取地图。

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

答案 3 :(得分:0)

  1. 线程安全的Singleton

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

    Why is volatile used in this example of double checked locking

  2. 您的class A: def __init__(self, items): self.items = list(items) # or items[:] li = [1, 2] obj = A(li) li[0] = 9 print(obj.items) # [1, 2] 是线程安全的。但您可以进一步优化代码。您可以将dataMap替换为Map,并删除ConcurrentHashMapsynchronized方法中的storeData

  3. 您可以查看有关high level concurrency

    的此文档页面