commit 92b0ab2fbc7d40e53681d489fca98419a3547f56
Author: Wiktor Niesiobędzki <github@vink.pl>
Date:   Fri Sep 14 23:39:03 2018 +0200

    Remove setCorePoolSize hack and instead use
    ThreadPool.DiscardOldestPolicy

diff --git src/org/openstreetmap/josm/data/cache/HostLimitQueue.java src/org/openstreetmap/josm/data/cache/HostLimitQueue.java
index 9f38c1d7b..aa4a397b3 100644
--- src/org/openstreetmap/josm/data/cache/HostLimitQueue.java
+++ src/org/openstreetmap/josm/data/cache/HostLimitQueue.java
@@ -8,7 +8,6 @@ import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.LinkedBlockingDeque;
 import java.util.concurrent.Semaphore;
-import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 
 import org.openstreetmap.josm.tools.Logging;
@@ -33,12 +32,6 @@ public class HostLimitQueue extends LinkedBlockingDeque<Runnable> {
     private final Map<String, Semaphore> hostSemaphores = new ConcurrentHashMap<>();
     private final int hostLimit;
 
-    private ThreadPoolExecutor executor;
-
-    private int corePoolSize;
-
-    private int maximumPoolSize;
-
     /**
      * Creates an unbounded queue
      * @param hostLimit how many parallel calls to host to allow
@@ -48,6 +41,11 @@ public class HostLimitQueue extends LinkedBlockingDeque<Runnable> {
         this.hostLimit = hostLimit;
     }
 
+    public HostLimitQueue(int hostLimit, int queueLimit) {
+        super(queueLimit); // create unbounded queue
+        this.hostLimit = hostLimit;
+    }
+
     private JCSCachedTileLoaderJob<?, ?> findJob() {
         for (Iterator<Runnable> it = iterator(); it.hasNext();) {
             Runnable r = it.next();
@@ -116,37 +114,6 @@ public class HostLimitQueue extends LinkedBlockingDeque<Runnable> {
         return job;
     }
 
-    /**
-     * Set the executor for which this queue works. It's needed to spawn new threads.
-     * See: http://stackoverflow.com/questions/9622599/java-threadpoolexecutor-strategy-direct-handoff-with-queue#
-     *
-     * @param executor executor for which this queue works
-     */
-    public void setExecutor(ThreadPoolExecutor executor) {
-        this.executor = executor;
-        this.maximumPoolSize = executor.getMaximumPoolSize();
-        this.corePoolSize = executor.getCorePoolSize();
-    }
-
-    @Override
-    public boolean offer(Runnable e) {
-        if (!super.offer(e)) {
-            return false;
-        }
-
-        if (executor != null) {
-            // See: http://stackoverflow.com/questions/9622599/java-threadpoolexecutor-strategy-direct-handoff-with-queue#
-            // force spawn of a thread if not reached maximum
-            int currentPoolSize = executor.getPoolSize();
-            if (currentPoolSize < maximumPoolSize
-                    && currentPoolSize >= corePoolSize) {
-                executor.setCorePoolSize(currentPoolSize + 1);
-                executor.setCorePoolSize(corePoolSize);
-            }
-        }
-        return true;
-    }
-
     private Semaphore getSemaphore(JCSCachedTileLoaderJob<?, ?> job) {
         String host;
         try {
diff --git src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoader.java src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoader.java
index a1e566aa4..03aec0dc4 100644
--- src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoader.java
+++ src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoader.java
@@ -67,16 +67,15 @@ public class TMSCachedTileLoader implements TileLoader, CachedTileLoader {
      * @return new ThreadPoolExecutor that will use a @see HostLimitQueue based queue
      */
     public static ThreadPoolExecutor getNewThreadPoolExecutor(String nameFormat, int workers) {
-        HostLimitQueue workQueue = new HostLimitQueue(HOST_LIMIT.get().intValue());
         ThreadPoolExecutor executor = new ThreadPoolExecutor(
-                0, // 0 so for unused thread pools threads will eventually die, freeing also the threadpool
-                workers, // do not this number of threads
+                0, // keep core pool the same size as max
+                workers, // do not exceed this number of threads
                 300, // keepalive for thread
                 TimeUnit.SECONDS,
-                workQueue,
+                new HostLimitQueue(HOST_LIMIT.get().intValue(), workers),
                 Utils.newThreadFactory(nameFormat, Thread.NORM_PRIORITY)
                 );
-        workQueue.setExecutor(executor);
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
         return executor;
     }
 
diff --git test/unit/org/openstreetmap/josm/data/cache/HostLimitQueueTest.java test/unit/org/openstreetmap/josm/data/cache/HostLimitQueueTest.java
index 36e7cde59..f3c6615e4 100644
--- test/unit/org/openstreetmap/josm/data/cache/HostLimitQueueTest.java
+++ test/unit/org/openstreetmap/josm/data/cache/HostLimitQueueTest.java
@@ -33,16 +33,14 @@ public class HostLimitQueueTest {
     public JOSMTestRules test = new JOSMTestRules().preferences().timeout(20 * 1000);
 
     private static ThreadPoolExecutor getNewThreadPoolExecutor(String nameFormat, int workers, int queueLimit) {
-        HostLimitQueue workQueue = new HostLimitQueue(queueLimit);
         ThreadPoolExecutor executor = new ThreadPoolExecutor(
-                0, // 0 so for unused thread pools threads will eventually die, freeing also the threadpool
-                workers, // do not this number of threads
+                0, // keep core pool the same size as max
+                workers, // do not exceed this number of threads
                 300, // keepalive for thread
                 TimeUnit.SECONDS,
-                workQueue,
+                new HostLimitQueue(queueLimit, workers),
                 Utils.newThreadFactory(nameFormat, Thread.NORM_PRIORITY)
                 );
-        workQueue.setExecutor(executor);
         return executor;
     }
 
@@ -63,7 +61,8 @@ public class HostLimitQueueTest {
         public void run() {
             try {
                 Thread.sleep(1000);
-            } catch (InterruptedException e) {
+                System.out.println("downloaded: " + getUrl().toString());
+            } catch (InterruptedException | IOException e) {
                 Logging.trace(e);
             } finally {
                 this.counter.incrementAndGet();
@@ -98,6 +97,7 @@ public class HostLimitQueueTest {
         AtomicInteger counter = new AtomicInteger(0);
         long start = System.currentTimeMillis();
         for (int i = 0; i < 10; i++) {
+            System.out.println("exec: " + i);
             tpe.execute(new Task(cache, new URL("http://localhost/"+i), counter));
         }
         tpe.shutdown();
