From a2ec8f10cb83229e6478a2bccdc98d33184f6373 Mon Sep 17 00:00:00 2001 From: Markus Rathgeb Date: Tue, 7 May 2019 21:26:04 +0200 Subject: [PATCH] [audio] audio servlet: don't change map while used by interation (#801) We should not remove entries (so keys) from the map while we are using the key set (a view) of that map (see JavaDoc: otherwise "results of the iteration undefined"). Signed-off-by: Markus Rathgeb GitOrigin-RevId: d19ee33be9c4f69f90be4d2fb3551b487af05ca0 --- .../core/audio/internal/AudioServlet.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/bundles/org.opensmarthouse.core.audio/src/main/java/org/eclipse/smarthome/core/audio/internal/AudioServlet.java b/bundles/org.opensmarthouse.core.audio/src/main/java/org/eclipse/smarthome/core/audio/internal/AudioServlet.java index ffec167181c..17ac2c87d01 100644 --- a/bundles/org.opensmarthouse.core.audio/src/main/java/org/eclipse/smarthome/core/audio/internal/AudioServlet.java +++ b/bundles/org.opensmarthouse.core.audio/src/main/java/org/eclipse/smarthome/core/audio/internal/AudioServlet.java @@ -15,7 +15,10 @@ import java.io.IOException; import java.io.InputStream; import java.util.Collections; +import java.util.LinkedList; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; @@ -143,16 +146,20 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Se } private synchronized void removeTimedOutStreams() { - for (String streamId : multiTimeStreams.keySet()) { - if (streamTimeouts.get(streamId) < System.nanoTime()) { - // the stream has expired, we need to remove it! - FixedLengthAudioStream stream = multiTimeStreams.remove(streamId); - streamTimeouts.remove(streamId); - IOUtils.closeQuietly(stream); - stream = null; - logger.debug("Removed timed out stream {}", streamId); + // Build list of expired streams. + final List toRemove = new LinkedList<>(); + for (Entry entry : streamTimeouts.entrySet()) { + if (entry.getValue() < System.nanoTime()) { + toRemove.add(entry.getKey()); } } + toRemove.forEach(streamId -> { + // the stream has expired, we need to remove it! + final FixedLengthAudioStream stream = multiTimeStreams.remove(streamId); + streamTimeouts.remove(streamId); + IOUtils.closeQuietly(stream); + logger.debug("Removed timed out stream {}", streamId); + }); } @Override