Volatile won't help here. Volatile is useful for solving visibility problems, but you have another problem: atomicity .
Oh, and Volatile has nothing to do with locking. It will not acquire a lock when reading / writing, it will not release anything. He does this: all the actions that happened before are written in the volatile field, will be visible to every other stream after they read the same volatile field. There is no lock (they are similar to the fact that the memory effects when releasing / acquiring a lock are exactly the same).
The get and set operations are not atomic, which means that other things can happen between them.
For example, one thread will be a get value, then the ANOTHER stream will get same value, both increase the value, then the first will be set new value, then the second will do the same, the final result is not what you expected.
The most common solution to this problem is to serialize access (i.e. synchronize ) to a shared variable or use comparison and set (CAS) (so you don't need to perform synchronization).
1. synchronized
private final Map<String, Integer> m = new ConcurrentHashMap<String, Integer>(); synchronized incrementValue(final String valueName) { m.put(valueName, m.get(valueName) + 1); }
Please note that if you use this solution, then EVERY ACCESS to the card must be synchronized with the same lock.
2. CAS
Many CAS algorithms are already implemented in the JVM in a very efficient way (i.e., they use their own code, and the JIT can use instructions specific to the processor, which you cannot access in other ways - check the Unsafe class in the Sun JVM, for example).
One class that might come in handy is AtomicInteger . You can use it as follows:
private final Map<String, AtomicInteger> m = new ConcurrentHashMap<String, AtomicInteger>(); incrementValue(final String valueName) { m.get(valueName).incrementAndGet(); }
What the CAS algorithm will do is something like this:
for (;;) { state = object.getCurrentState(); if (object.updateValueAndStateIfStateDidntChange(state)) { break; } }
The updateValueAndStateIfStateDidntChange method is updateValueAndStateIfStateDidntChange be atomic and will return true only if it was able to update the value. Thus, if another thread changes the value after you get the state, and before you update the value, the method will return false, and the loop will try again.
Assuming that you can implement this method in a way that does not use synchronized (and you can, using classes in java.util.concurrent), avoid conflicts (this means that threads waiting to receive a lock are held by other threads), and you can see the overall performance improvement.
I use a lot of this in a distributed task system that I wrote. All tasks must be performed exactly once, and I have many machines that perform tasks. All tasks are set in one MySQL table. How to do it? You must have a column whose purpose is to implement CAS. Name it executing . Before starting the task, you should do something like: get the following task, "update tasks set executing = 1 where id = :id AND executing = 0" and count the number of updated lines . If you updated 0 lines, this is due to the fact that another thread / process / machine has already completed this task (and successfully executed this "update" request); in this case, you will forget it and try the next task, because you know that this one is already running. If you updated 1 line, then it’s good to go, you can execute it.
Another place where I use this idea of CAS a lot is in a very dynamic (by its configuration) resource pool that I wrote (I use it mainly to manage "connections", ie sockets, but it is quite general for storage any kind of resources). Basically, it counts how many resources it holds. When you try to get a resource, it reads the counter, decreases it, tries to update it (if nothing has changed the counter between them), and if it succeeds, you can simply take the resource from the pool and borrow it (as soon as the counter reaches 0, it will not provide a resource). If I ever publish this code, I will definitely add a link to it here.