Index: /trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java	(revision 17493)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java	(revision 17494)
@@ -1570,47 +1570,15 @@
             ts.overloadTiles();
         }
-        int[] otherZooms = {1, 2, -1, -2, -3, -4, -5};
-        for (int zoomOffset : otherZooms) {
-            if (!getDisplaySettings().isAutoZoom()) {
-                break;
-            }
-            int newzoom = displayZoomLevel + zoomOffset;
-            if (newzoom < getMinZoomLvl() || newzoom > getMaxZoomLvl()) {
-                continue;
-            }
-            if (missedTiles.isEmpty()) {
-                break;
-            }
-            List<Tile> newlyMissedTiles = new LinkedList<>();
-            for (Tile missed : missedTiles) {
-                if (zoomOffset > 0 && "no-tile".equals(missed.getValue("tile-info"))) {
-                    // Don't try to paint from higher zoom levels when tile is overzoomed
-                    newlyMissedTiles.add(missed);
-                    continue;
-                }
-                TileSet ts2 = new TileSet(tileSource.getCoveringTileRange(missed, newzoom));
-                // Instantiating large TileSets is expensive. If there are no loaded tiles, don't bother even trying.
-                if (ts2.allLoadedTiles().isEmpty()) {
-                    if (zoomOffset > 0) {
-                        newlyMissedTiles.add(missed);
-                        continue;
-                    } else {
-                        /*
-                         *  We have negative zoom offset. Try to load tiles from lower zoom levels, as they may be not present
-                         *  in tile cache (e.g. when user panned the map or opened layer above zoom level, for which tiles are present.
-                         *  This will ensure, that tileCache is populated with tiles from lower zoom levels so it will be possible to
-                         *  use them to paint overzoomed tiles.
-                         *  See: #14562
-                         */
-                        ts2.loadAllTiles(false);
-                    }
-                }
-                if (ts2.tooLarge()) {
-                    continue;
-                }
-                newlyMissedTiles.addAll(this.paintTileImages(g, ts2, newzoom, missed));
-            }
-            missedTiles = newlyMissedTiles;
-        }
+        if (getDisplaySettings().isAutoZoom()) {
+            int[] otherZooms = {1, 2, -1, -2, -3, -4, -5};
+
+            for(int otherZoom: otherZooms) {
+                missedTiles = tryLoadFromDifferentZoom(g, displayZoomLevel, missedTiles, otherZoom);
+                if (missedTiles.isEmpty()) {
+                    break;
+                }
+            }
+        }
+
         if (Logging.isDebugEnabled() && !missedTiles.isEmpty()) {
             Logging.debug("still missed {0} in the end", missedTiles.size());
@@ -1655,4 +1623,44 @@
             }
         }
+    }
+
+    private List<Tile> tryLoadFromDifferentZoom(Graphics2D g, int displayZoomLevel, List<Tile> missedTiles,
+            int zoomOffset) {
+
+        int newzoom = displayZoomLevel + zoomOffset;
+        if (newzoom < getMinZoomLvl() || newzoom > getMaxZoomLvl()) {
+            return missedTiles;
+        }
+
+        List<Tile> newlyMissedTiles = new LinkedList<>();
+        for (Tile missed : missedTiles) {
+            if (zoomOffset > 0 && "no-tile".equals(missed.getValue("tile-info"))) {
+                // Don't try to paint from higher zoom levels when tile is overzoomed
+                newlyMissedTiles.add(missed);
+                continue;
+            }
+            TileSet ts2 = new TileSet(tileSource.getCoveringTileRange(missed, newzoom));
+            // Instantiating large TileSets is expensive. If there are no loaded tiles, don't bother even trying.
+            if (ts2.allLoadedTiles().isEmpty()) {
+                if (zoomOffset > 0) {
+                    newlyMissedTiles.add(missed);
+                    continue;
+                } else {
+                    /*
+                     *  We have negative zoom offset. Try to load tiles from lower zoom levels, as they may be not present
+                     *  in tile cache (e.g. when user panned the map or opened layer above zoom level, for which tiles are present.
+                     *  This will ensure, that tileCache is populated with tiles from lower zoom levels so it will be possible to
+                     *  use them to paint overzoomed tiles.
+                     *  See: #14562
+                     */
+                    ts2.loadAllTiles(false);
+                }
+            }
+            if (ts2.tooLarge()) {
+                continue;
+            }
+            newlyMissedTiles.addAll(this.paintTileImages(g, ts2, newzoom, missed));
+        }
+        return newlyMissedTiles;
     }
 
@@ -1863,5 +1871,7 @@
         public void cancel() {
             if (tileLoader instanceof TMSCachedTileLoader) {
-                ((TMSCachedTileLoader) tileLoader).cancelOutstandingTasks();
+                TMSCachedTileLoader cachedTileLoader = (TMSCachedTileLoader) tileLoader;
+                cachedTileLoader.cancelOutstandingTasks();
+                cachedTileLoader.getDownloadExecutor().shutdown();
             }
         }
@@ -1879,4 +1889,9 @@
             } else {
                 Logging.warn("Tile loading failure: " + tile + " - " + tile.getErrorMessage());
+            }
+            if (tileLoader instanceof TMSCachedTileLoader) {
+                TMSCachedTileLoader cachedTileLoader = (TMSCachedTileLoader) tileLoader;
+                cachedTileLoader.cancelOutstandingTasks();
+                cachedTileLoader.getDownloadExecutor().shutdown();
             }
         }
@@ -1936,4 +1951,8 @@
         MapView.removeZoomChangeListener(this);
         adjustAction.destroy();
+        if (tileLoader instanceof TMSCachedTileLoader) {
+            TMSCachedTileLoader cachedTileLoader = (TMSCachedTileLoader) tileLoader;
+            cachedTileLoader.getDownloadExecutor().shutdown();
+        }
     }
 
