在这种情况下哪个更好的ConcurrentHashMap或同步哈希映射?

时间:2016-08-18 06:09:05

标签: java multithreading collections hashmap concurrenthashmap

我正在编写一个实用程序类,它使用map作为缓存存储。现在它将用于多线程环境。我想在执行put操作或ConcurrentHashMap(使用putIfAbsent)时使用了synchronized hashmap,如果它容易覆盖键值,我仍然感到困惑(虽然键值在我的情况下是唯一的)并且两者都有利弊。所以我无法决定。可能有一些其他缓存存储我可以用于此目的,建议但我更感兴趣知道哪个将使用CHM或Hashmap 如果这是唯一的选项。

在程序的评论是CHM使用,我认为我使用了HashMap。

public final class DateTime {

  private static final Map<CountryLanguage, Locale> localeMap = new HashMap<>();

 /*private static final Map<CountryLanguage, Locale> localeMap = new ConcurrentHashMap<>();*/

public static String getDateTime1(String pattern, LocalDateTime localDateTime, String language,
      String country) {
    if (language == null || language.isEmpty()) {
      throw new NullPointerException("Language cannot be null or empty");
    }
    CountryLanguage countryLanguage = new CountryLanguage(language, country);
    if (!localeMap.containsKey(countryLanguage)) {
      synchronized (localeMap) {
        // Putting double lock
        if (!localeMap.containsKey(countryLanguage)) {
          for (Locale locale : Locale.getAvailableLocales()) {
            if (locale.getLanguage().equals(language) && locale.getCountry().equals(country)) {
              localeMap.put(new CountryLanguage(language, country), locale);
            }
          }
        }
      }
    }
      /*for (Locale locale : Locale.getAvailableLocales()) {
        if (locale.getLanguage().equals(language) && locale.getCountry().equals(country)) {
          localeMap.putIfAbsent(new CountryLanguage(language, country), locale);
        }
    }*/
    Locale locale = localeMap.get(countryLanguage);
    if (locale == null) {
      locale = Locale.ROOT;
    }
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern, locale);
    return localDateTime.format(dateTimeFormatter);
  }

注意:

  • 我有一个内部类CountryLanguage,它有String国家,String语言作为成员变量,并且都覆盖了hashCode和equals方法。

编辑1:我没有将整个地图设为同步我只是在放置操作时使用地图上的同步。我正在使用双重检查以确保不存在两个键值

2 个答案:

答案 0 :(得分:4)

  

已同步的HashMap:

     
      
  1. 使用对象级锁定同步每个方法。所以得到   并将方法放在synchMap上获取锁。
  2.   
  3. 锁定整个集合是一种性能开销。一个人   线程保持锁定,没有其他线程可以使用该集合。
  4.         

    ConcurrentHashMap:(在JDK 5中引入)

         
        
    1. 对象级别没有锁定,锁定很多   更细的粒度。对于ConcurrentHashMap,锁可能位于a   hashmap bucket level。
    2.   
    3. 较低级别锁定的效果是您可以拥有并发   读者和作者不可能同步   集合。这样可以提高可扩展性。
    4.   
    5. ConcurrentHashMap不会抛出ConcurrentModificationException   如果一个线程试图修改它而另一个线程迭代它。
    6.   

所以,我建议你ConcurrentHashMap,它不会阻止所有&#34; cahce&#34;一直以来。

如果您想了解更多信息HashMap vs ConcurrentHashMap

修改

关于此事的其他一些帖子: Is ConcurrentHashMap totally safe?

答案 1 :(得分:1)

我会使用ConcurrentHashMap

来实现这一点
public final class DateTime
{
    private static final ConcurrentMap<CountryLanguage, Locale> localeMap = new ConcurrentHashMap<>();

    public static String getDateTime1(String pattern, LocalDateTime localDateTime, String language, String country)
    {
        if (language == null || language.isEmpty()) {
            throw new NullPointerException("Language cannot be null or empty");
        }

        CountryLanguage countryLanguage = new CountryLanguage(language, country);

        // See if it is already there
        Locale locale = localeMap.get(countryLanguage);
        if (locale == null) {
            // It's not there (probably), so look it up
            Local candidate = null;
            for (Locale l : Locale.getAvailableLocales()) {
                if (l.getLanguage().equals(language) && l.getCountry().equals(country)) {
                    candidate = l;
                    break;
                }
            }

            // If we found it, put it in the map
            if (candidate != null) {
                // It's possible that another thread beat us here, so use putIfAbsent()
                // and check the return value
                locale = localeMap.putIfAbsent(countryLanguage, candidate);
                if (locale == null) {
                    locale = candidate;
                }
            }
        }

        if (locale == null) {
            locale = Locale.ROOT;
        }

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern, locale);
        return localDateTime.format(dateTimeFormatter);
    }
}

这是线程安全的,不需要外部同步。