I'm trying to create a generic class to make some synchronized buffered writing operation.
I'm trying to minimize lock time, so i used a non final lock object that im my mind would be enough to keep the class synchronized and avoid racing condition... but while testing it i'm still getting racing condition and the final result is that some entities are flushed multiple times
can anyone try to explain me what is causing racing condition, what scenario is the cause of sync problem?
PLEASE DO NOT TELL ME TO MAKE THE METHOD flushCache SYNCHRONIZED... I KNOW HOW TO SOLVE THIS PROBLEM, im just trying to understand why it is happening
public abstract class SynchronizedBufferedSaver<E> {
private final int MAX_BUFFER_SIZE;
private Set<E> savingBuffer;
public SynchronizedBufferedSaver(final int max_buffer_size) {
MAX_BUFFER_SIZE = max_buffer_size;
savingBuffer = ConcurrentHashMap.newKeySet((int) (max_buffer_size * 1.5));
}
public void save(@NonNull final E entity) {
copyToCache(entity);
flushCache(false);
}
abstract protected void persist(@NonNull final Set<E> cache);
public void flushCache(final boolean force) {
synchronized (savingBuffer) {
if (!savingBuffer.isEmpty() && (force || savingBuffer.size() >= MAX_BUFFER_SIZE)) {
final Set<E> tmp = savingBuffer;
savingBuffer = ConcurrentHashMap.newKeySet((int) (MAX_BUFFER_SIZE * 1.5));
persist(tmp);
}
}
}
private void copyToCache(@NonNull final E entity) {
savingBuffer.add(entity);
}
}
Ended up just giving up to try to reduce the synchronization blocks, it was too much effort for a small task.
I tried
volatileandatomicreferencewithout successthe following code will solve the problem with the extra synchronization block... although if anyone has an article or description of how that could be achieved with 1 synchronization block please send me i would love to learn
package br.com.fisgar.utils;