0

I want to do operations like

class A {
}

ConcurrentHashMap<A, Integer> map = new ConcurrentHashMap<>();

public void fun() {  
     Integer count = map.get(Object);
     if (count != null) {
         map.put(Object, count+1);
     }
}
public void add() {
     // increase Object count by 1
}
public void remove() {
     // deduct Object count by 1
}

How can I make fun() thread safe ?

I know a way to do this is to add synchronized block

public void fun() {  
    synchronized("") {
        Integer count = map.get(Object);
        if (count != null) {
            map.put(Object, count+1);
        }
    }
}

But are there any other ways to do it ? Or are there any libraries to do it ?

like thread safe entry processor ?


I also want to implement something like

public void remove() {
     int count = map.get(Object);
     count -= 5;
     if (count <= 0) {
         map.remove(Object);
     } else {
         map.put(Object, count + 2);
     }
}

Any ways to do this  ? 
Thank you
Peng
  • 1
  • 2
  • Have you checked http://stackoverflow.com/a/26214475/4764198 ? – arkki Oct 19 '16 at 05:35
  • 1
    In your sample code, synrchonizing on the empty string may or may not work depending on the behavior of interning and you exact usage pattern, but it is not standard practice in general. If you use synchronize, you should either synchronize on the map itself, or on a dedicated object, but not on the empty String. – GPI Oct 19 '16 at 07:24
  • Which version of Java are you using? This is much easier in Java 8 than other versions. – Louis Wasserman Oct 19 '16 at 18:31
  • @LouisWasserman I am using Java 8, How can I solve it in Java 8 ? Thank you – Peng Oct 19 '16 at 19:52
  • 1
    Use Map.compute. Really that's the complete solution. – Louis Wasserman Oct 19 '16 at 19:53
  • @GPI: it does *not* work. It doesn’t matter whether the OP uses the canonical empty string or any other object here. As long as only this specific method uses that object as synchronization key while all other operations access the map without synchronizing on the object, there is no thread safety. However, if all operations synchronize on that object, there is no point in using `ConcurrentHashMap`. – Holger Oct 24 '16 at 17:37
  • @Holger : agreed. That's what I meant by "exact usage pattern". Thoug I guess it **may** work, if everybody syncs on the same empty string, that gets interned at runtime into the same instance, which you should never *ever* count on. But, it may happen. Once in a million year. As we do not have the whole code available, for all we know, this could just be a shortcut of the poster, so I made it a comment like so. – GPI Oct 25 '16 at 07:49
  • 1
    @GPI: well, the literal string `""` is guaranteed to be resolved to the same instance, so code locking on it will have mutual exclusion guarantees, but the bigger problem is that you have no control over who has the same stupid idea of locking on a literal string, hence, this would be asking for deadlocks. And *then*, try to understand the debug output showing on which objects the threads are locked, when the the objects are empty strings. If you want to max it out, let some threads lock on `" "`, others on `""` and some on `""` (the latter contains a zero width space)… – Holger Oct 25 '16 at 10:06
  • Thanks. I didn't know this was **guaranteed** behavior. (I never use/count on the interning of Strings). – GPI Oct 25 '16 at 10:36

1 Answers1

-1

Use AtomicInteger and ConcurrentHashMap.putIfAbsent()

Also look at the ConcurrentHashMap.remove(key, value) -- removes the key only if it is mapped to the given value.

I am not sure, if it is possible to implement the exact logic (which is not very well defined in the question above), but those methods could be very useful in doing something similar.

More hints (that could be useful or may be not too much):

You (probably!) can use methods: computeIfAbsent, computeIfPresent (or replace), and remove(key, value). ConcurrentHashMap could be defined on values are Integers.

It will be very dirty solution, and I do not recommend you to use it, but as something to think about, it could be very challenging.

Let me know if you need more hints.

Slava
  • 827
  • 5
  • 13
  • Can you tell me more about this ? How can I use them here ? Thank you – Peng Oct 19 '16 at 06:00
  • This is perfectly OK for the `fun()` method, but for the sample `remove()` one, it's not obvious to me neither if this works. – GPI Oct 19 '16 at 07:25
  • You can user remove(key, value) – Slava Oct 19 '16 at 07:26
  • AtomicInteger does not have hashCode/equals semantic so I really do not see how one could use remove(key, value) to have something like the post's remove method (although I do agree that this method is not that well defined, it's behavior and effects are clear) – GPI Oct 19 '16 at 07:33
  • I do not state that AtomicInteger must be used as a value in Map. I do not claim I provide a complete solution, I gave hints. – Slava Oct 19 '16 at 07:43