How to make concurrent hash map thread safe with get and put as an atomic operation?

ⅰ亾dé卋堺 提交于 2019-12-24 07:56:50

问题


Is my below method thread safe? This method is in Singleton class.

  private static final Map<String, PreparedStatement> holder = new ConcurrentHashMap<>();

  public BoundStatement getStatement(String cql) {
    Session session = TestUtils.getInstance().getSession();
    PreparedStatement ps = holder.get(cql);
    if(ps == null) { // If "ps" is already present in cache, then we don't have to synchronize and make threads wait.
        synchronized {
          ps = holder.get(cql);
          if (ps == null) {
            ps = session.prepare(cql);
            holder.put(cql, ps);
          }
        }
    }
    return ps.bind();
  }

I am working with Cassandra and using datastax java driver so I am reusing prepared statements and that's why I am caching it here. Prepared Statement and BoundStatement.

Is there any better way of making my getStatement method thread safe (if it is thread safe) instead of using synchronized block like that? Any other data structure which might be thread safe for these kind of operations? I am working with Java 7.


回答1:


Since .putIfAbsent is in Java7, you can use it:

 private static final ConcurrentHashMap<String, PreparedStatement> holder = new ConcurrentHashMap<>();

  public BoundStatement getStatement(String cql) {
    Session session = TestUtils.getInstance().getSession();
    PreparedStatement ps = holder.get(cql);
    if(ps == null) { // If "ps" is already present in cache, then we don't have to synchronize and make threads wait.

         if (holder.putIfAbsent(cql, session.prepare(cql)) != null) {
            // Someone else got there before, handle
         }
    }
    return ps.bind();
  }

Note that putIfAbsent still uses same synchronization internally.




回答2:


If you're looking to do some form of memoization, then this is the best/easiest you can do in Java 7. Guava has a computing Cache implementation you can use and Java 8 has a computeIfAbsent method in the Map interface, but you're obviously out of luck here.

If you can create objects on an empty race, like Alexey's answer suggests, that would be the best solution. If you cannot, your implementation is both thread-safe and reasonable.

It is a form of double-checked locking, however, with this implementation you are ensuring a happens-before ordering by using the put and get methods of the CHM.



来源:https://stackoverflow.com/questions/40831817/how-to-make-concurrent-hash-map-thread-safe-with-get-and-put-as-an-atomic-operat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!