2016-08-18 69 views
0

我正在编写一个使用map作为缓存存储的实用类。现在它将用于多线程环境。我想出了在执行put操作时使用同步hashmap或使用putIfAbsent的ConcurrentHashMap,但我仍然对它是否易于覆盖键值(尽管键值在我的情况下是唯一的)感到困惑,并且两者都有优点和缺点。所以我无法做出决定。可能有一些其他的缓存存储我可以用于这个目的,但建议,但我更有兴趣知道哪些将被使用CHM或哈希图如果这是唯一的选择。在这种情况下哪个更好的ConcurrentHashMap或Synchronized Hash Map?

在程序的评论是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其中有字符串的国家,语言的字符串作为成员变量和两者的hashCode和equals方法已被覆盖。

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

+0

添加同一个'CountryLanguage'两次会出现什么问题? – Marvin

+0

@Marvin:没有问题,但Map如何包含两次相同的密钥。我认为并发hashmap可以有多个相同的键值。 –

+1

您没有正确使用同步。如果多个线程访问共享的可变状态(映射),则必须同步** all **访问该状态,读取和写入。不只是写道。 –

回答

4

同步的HashMap:

  1. 每一种方法是使用对象级锁同步。所以得到 并把方法放在synchMap上获得一个锁。
  2. 锁定整个集合是一个性能开销。当一个线程持有锁定时,其他线程不能使用该集合。

的ConcurrentHashMap:(在JDK 5被引入)

  1. 有在对象级别没有锁定,该锁定是在一个多 更精细的粒度。对于ConcurrentHashMap,这些锁可能位于 散列映射存储桶级别。
  2. 较低级锁定的效果是,您可以同时拥有 读取器和编写器,这对于同步 集合是不可能的。这导致更多的可扩展性。
  3. ConcurrentHashMap不会抛出ConcurrentModificationException 如果一个线程试图修改它而另一个线程正在迭代它。

所以,我建议你ConcurrentHashMap,它不会阻止所有的“cahce”所有的时间。

如果您想了解更多信息HashMap vs 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); 
    } 
} 

此: Is ConcurrentHashMap totally safe?

+0

嗨。我并没有把整个hashmap做为同步,只是把它放在put操作中,如果你会看到代码,你会发现我在put操作时使用同步块。并发hashmap可以有多个相同的键值对。 –

+2

@ balboa_21刚刚同步put是不正确的,并且不,ConcurrentMap是一个Map,所以它不能有重复的键。 –

+0

@JBNizet:是的,地图不会有多个相同的键值对。但是如果多线程同时执行putIfAbsent(key,value)呢?因为按照ConcurrentHashMap文档检索不是线程安全的。 –

1

我会用ConcurrentHashMap实现这个是线程安全的并且是必需的无需外部同步。

相关问题