Summary
Both ReferentialIntegrityUtil and CrossLabelFileAreaReferenceChecker maintain static mutable HashMap/ArrayList/HashSet fields accessed from public methods that are not synchronized. In a multi-threaded validation run, concurrent access to these collections can produce ConcurrentModificationException, lost updates, or silently corrupted results.
ReferentialIntegrityUtil
All thirteen private static collection fields (lines ~54–145) use HashMap, ArrayList, or HashSet:
lidOrLidVidReferencesCumulative (ArrayList)
lidAndFilenameCombo (HashSet)
contextReferencesCumulative, bundleOrCollectionReferenceMap, bundleReferenceMap, collectionReferenceMap, bundleURLMap, labelIdentifierCache (all HashMap)
- etc.
None of the methods that mutate or iterate these fields are synchronized. The catch (Exception e) blocks in performReporting() (~lines 345, 470) swallow all exceptions including ConcurrentModificationException, so concurrency failures produce only a stack trace on stderr and continue with corrupted state.
CrossLabelFileAreaReferenceChecker
final private static HashMap<String,Boolean> isObservational = new HashMap<>();
final private static HashMap<String,List<String>> knownRefs = new HashMap<>();
add(), getOtherId(), and getOtherFilename() are all unsynchronized. The final modifier only prevents reference reassignment — the map contents remain fully mutable.
Recommended fix
- Replace
HashMap with ConcurrentHashMap and use atomic operations (computeIfAbsent, merge, putIfAbsent) where check-then-act patterns exist.
- Replace
ArrayList with CopyOnWriteArrayList or a synchronized wrapper.
- Replace
HashSet with ConcurrentHashMap.newKeySet().
- Change
catch (Exception e) in performReporting() to catch specific exception types and let unexpected runtime exceptions propagate (or rethrow as RuntimeException after logging).
Related
Identified during immutability/synchronization audit triggered by PR #1607 review feedback.
🤖 Generated with Claude Code
Summary
Both
ReferentialIntegrityUtilandCrossLabelFileAreaReferenceCheckermaintain static mutableHashMap/ArrayList/HashSetfields accessed from public methods that are notsynchronized. In a multi-threaded validation run, concurrent access to these collections can produceConcurrentModificationException, lost updates, or silently corrupted results.ReferentialIntegrityUtil
All thirteen
private staticcollection fields (lines ~54–145) useHashMap,ArrayList, orHashSet:lidOrLidVidReferencesCumulative(ArrayList)lidAndFilenameCombo(HashSet)contextReferencesCumulative,bundleOrCollectionReferenceMap,bundleReferenceMap,collectionReferenceMap,bundleURLMap,labelIdentifierCache(allHashMap)None of the methods that mutate or iterate these fields are
synchronized. Thecatch (Exception e)blocks inperformReporting()(~lines 345, 470) swallow all exceptions includingConcurrentModificationException, so concurrency failures produce only a stack trace on stderr and continue with corrupted state.CrossLabelFileAreaReferenceChecker
add(),getOtherId(), andgetOtherFilename()are all unsynchronized. Thefinalmodifier only prevents reference reassignment — the map contents remain fully mutable.Recommended fix
HashMapwithConcurrentHashMapand use atomic operations (computeIfAbsent,merge,putIfAbsent) where check-then-act patterns exist.ArrayListwithCopyOnWriteArrayListor asynchronizedwrapper.HashSetwithConcurrentHashMap.newKeySet().catch (Exception e)inperformReporting()to catch specific exception types and let unexpected runtime exceptions propagate (or rethrow asRuntimeExceptionafter logging).Related
Identified during immutability/synchronization audit triggered by PR #1607 review feedback.
🤖 Generated with Claude Code