diff --git a/src/main/java/org/opensourcephysics/cabrillo/tracker/video/FrameCache.java b/src/main/java/org/opensourcephysics/cabrillo/tracker/video/FrameCache.java index 111e35f6..76844380 100644 --- a/src/main/java/org/opensourcephysics/cabrillo/tracker/video/FrameCache.java +++ b/src/main/java/org/opensourcephysics/cabrillo/tracker/video/FrameCache.java @@ -30,10 +30,10 @@ public class FrameCache { private final ReentrantReadWriteLock lock; /** Total frames loaded across all cache accesses */ - private long totalLoads; + private final java.util.concurrent.atomic.LongAdder totalLoads; /** Total frame cache hits */ - private long totalHits; + private final java.util.concurrent.atomic.LongAdder totalHits; /** * Creates a FrameCache with default maximum capacity of 100 frames. @@ -63,8 +63,8 @@ protected boolean removeEldestEntry(Map.Entry eldest) { } }; this.lock = new ReentrantReadWriteLock(); - this.totalLoads = 0; - this.totalHits = 0; + this.totalLoads = new java.util.concurrent.atomic.LongAdder(); + this.totalHits = new java.util.concurrent.atomic.LongAdder(); } /** @@ -74,7 +74,7 @@ protected boolean removeEldestEntry(Map.Entry eldest) { * This method does not load a new frame - call loadFrame() for that.

* * @param frameIndex the frame index to retrieve - * @return the cached Bufferedlmage, or null if not found or index is invalid + * @return the cached BufferedImage, or null if not found * @throws IllegalStateException if frameIndex is invalid */ public BufferedImage get(int frameIndex) { @@ -82,15 +82,15 @@ public BufferedImage get(int frameIndex) { throw new IllegalStateException("frameIndex cannot be negative: " + frameIndex); } - lock.writeLock().lock(); + lock.readLock().lock(); try { BufferedImage frame = cache.get(frameIndex); if (frame != null) { - totalHits++; + totalHits.increment(); } return frame; } finally { - lock.writeLock().unlock(); + lock.readLock().unlock(); } } @@ -112,12 +112,11 @@ public void put(int frameIndex, BufferedImage frame) { throw new IllegalArgumentException("frame cannot be null"); } - totalLoads++; - lock.writeLock().lock(); try { // Only update if not already present (hit means no load needed) if (!cache.containsKey(frameIndex)) { + totalLoads.increment(); cache.put(frameIndex, frame); } } finally { @@ -181,7 +180,7 @@ public int getMaxSize() { * @return total loads count */ public long getTotalLoads() { - return totalLoads; + return totalLoads.sum(); } /** @@ -190,7 +189,7 @@ public long getTotalLoads() { * @return total hits count */ public long getTotalHits() { - return totalHits; + return totalHits.sum(); } /** @@ -199,10 +198,11 @@ public long getTotalHits() { * @return hit ratio as a double between 0 and 1, or 0.0 if no loads have occurred */ public double getHitRatio() { - if (totalLoads == 0) { + long loads = totalLoads.sum(); + if (loads == 0) { return 0.0; } - return (double) totalHits / totalLoads; + return (double) totalHits.sum() / loads; } /** @@ -212,8 +212,16 @@ public double getHitRatio() { */ @Override public String toString() { - return String.format("FrameCache[size=%d/%d, hits=%d, loads=%d, ratio=%.2f%%]", - size(), maxSize, totalHits, totalLoads, getHitRatio() * 100); + lock.readLock().lock(); + try { + long loads = totalLoads.sum(); + long hits = totalHits.sum(); + double ratio = loads == 0 ? 0.0 : (double) hits / loads; + return String.format("FrameCache[size=%d/%d, hits=%d, loads=%d, ratio=%.2f%%]", + cache.size(), maxSize, hits, loads, ratio * 100); + } finally { + lock.readLock().unlock(); + } } /**