I have a multi-threaded Java application that adds to a lot of files on dynamically generated paths (large numbers - more than 100 thousand). I want to protect against simultaneous recording. Since this is a contradiction in the JVM, I cannot use FileLock s.
Instead, I try to synchronize Path objects as follows ( PathLocker is a singleton).
public class PathLocker { private final ConcurrentMap<Path, ReentrantLock> pathLockMap = new ConcurrentHashMap<>(); public void lock(Path path) { pathLockMap.computeIfAbsent(path, p -> new ReentrantLock()).lock(); } public void unlock(Path path) { ReentrantLock reentrantLock = pathLockMap.get(path); if (!reentrantLock.hasQueuedThreads()) {
The only client code is as follows:
Path path = findPath(directory, dataType, bucketEnd, referenceId); pathLocker.lock(path); try { try (FileWriter fileWriter = new FileWriter(path.toFile(), true)) { fileWriter.write(string); } } finally { pathLocker.unlock(path); }
However, this code pretty quickly throws a null pointer when it searches for reentrantLock inside PathLocker::unlock .
I do not understand how this NPE can happen. Obviously, some other thread deleted the value at the same time, but as I understand it, the only possible threads that could remove the lock were those that were queued and waiting for the lock in the first place. What am I missing?
source share