Index: src/org/openstreetmap/josm/tools/ImageProvider.java
===================================================================
--- src/org/openstreetmap/josm/tools/ImageProvider.java	(revision 4823)
+++ src/org/openstreetmap/josm/tools/ImageProvider.java	(working copy)
@@ -30,6 +30,8 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.zip.ZipEntry;
@@ -107,6 +109,15 @@
      */
     private static Map<String, ImageResource> cache = new HashMap<String, ImageResource>();
 
+    private final static ExecutorService imageFetcher = Executors.newSingleThreadExecutor();
+
+    public final static int STATUS_IN_BACKGROUND = 0;
+    public final static int STATUS_FINISHED_EARLY = 1;
+
+    public interface ImageCallback {
+        void finished(ImageIcon result, int status);
+    }
+
     /**
      * @param subdir    Subdirectory the image lies in.
      * @param name      The name of the image. If it does not end with '.png' or '.svg',
@@ -243,6 +254,34 @@
     }
 
     /**
+     * Load the image in a background thread.
+     *
+     * There are 2 possible return values:
+     *  - STATUS_FINISHED_EARLY
+     *      This means that image is returned directly: The callback will have been called
+     *      before this method returns.
+     *  - STATUS_IN_BACKGROUND
+     *      Image is fetched in the background and callback will be executed at any time.
+     */
+    public int getInBackground(final ImageCallback callback) {
+        if (name.startsWith("http://") || name.startsWith("wiki://")) {
+            Runnable fetch = new Runnable() {
+                @Override
+                public void run() {
+                    ImageIcon result = get();
+                    callback.finished(result, STATUS_IN_BACKGROUND);
+                }
+            };
+            imageFetcher.submit(fetch);
+            return STATUS_IN_BACKGROUND;
+        } else {
+            ImageIcon result = get();
+            callback.finished(result, STATUS_FINISHED_EARLY);
+            return STATUS_FINISHED_EARLY;
+        }
+    }
+
+    /**
      * Return an image from the specified location. Throws a RuntimeException if
      * the image cannot be located.
      *
Index: src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java	(revision 4823)
+++ src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java	(working copy)
@@ -19,6 +19,8 @@
 import org.openstreetmap.josm.data.osm.visitor.paint.MapPainter;
 import org.openstreetmap.josm.gui.mappaint.MapPaintStyles.IconReference;
 import org.openstreetmap.josm.gui.mappaint.StyleCache.StyleList;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.ImageProvider.ImageCallback;
 import org.openstreetmap.josm.tools.Pair;
 import org.openstreetmap.josm.tools.Utils;
 
@@ -29,8 +31,6 @@
     public MapImage<Image> mapImage;
     public Symbol symbol;
 
-    private ImageIcon disabledIcon;
-
     public enum SymbolShape { SQUARE, CIRCLE, TRIANGLE, PENTAGON, HEXAGON, HEPTAGON, OCTAGON, NONAGON, DECAGON }
 
     public static class Symbol {
@@ -125,7 +125,7 @@
         Cascade c = env.mc.getCascade(env.layer);
         Cascade c_def = env.mc.getCascade("default");
 
-        IconReference iconRef = c.get("icon-image", null, IconReference.class);
+        final IconReference iconRef = c.get("icon-image", null, IconReference.class);
         if (iconRef == null)
             return null;
 
@@ -144,20 +144,53 @@
         int width = widthF == null ? -1 : Math.round(widthF);
         int height = heightF == null ? -1 : Math.round(heightF);
 
-        MapImage<Image> mapImage = new MapImage<Image>(iconRef.iconName, iconRef.source);
+        final MapImage<Image> mapImage = new MapImage<Image>(iconRef.iconName, iconRef.source);
 
-        ImageIcon icon = MapPaintStyles.getIcon(iconRef, width, height);
-        if (icon == null) {
-            mapImage.img = MapPaintStyles.getNoIcon_Icon(iconRef.source).getImage();
-        } else {
-            mapImage.img = icon.getImage();
-            mapImage.alpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.icon-image-alpha", 255))));
-            Integer pAlpha = Utils.color_float2int(c.get("icon-opacity", null, float.class));
-            if (pAlpha != null) {
-                mapImage.alpha = pAlpha;
+        synchronized (mapImage) {
+            int result = new ImageProvider(iconRef.iconName)
+                    .setDirs(MapPaintStyles.getIconSourceDirs(iconRef.source))
+                    .setId("mappaint."+iconRef.source.getPrefName())
+                    .setArchive(iconRef.source.zipIcons)
+                    .setWidth(width)
+                    .setHeight(height)
+                    .setOptional(true)
+                    .getInBackground(new ImageCallback() {
+                        @Override
+                        public void finished(ImageIcon result, int status) {
+                                if (status == ImageProvider.STATUS_FINISHED_EARLY) {
+                                    mapImage.img = result.getImage();
+                                } else if (status == ImageProvider.STATUS_IN_BACKGROUND) {
+                                    synchronized (mapImage) {
+                                        if (result == null) {
+                                            mapImage.img = MapPaintStyles.getNoIcon_Icon(iconRef.source).getImage();
+                                            mapImage.alpha = 255;
+                                        } else {
+                                            mapImage.img = result.getImage();
+                                        }
+                                    }
+                                    Main.map.mapView.preferenceChanged(null); // otherwise repaint is ignored, because layer hasn't changed
+                                    Main.map.mapView.repaint();
+                                }
+                            }
+                        }
+            );
+            
+            if (result == ImageProvider.STATUS_FINISHED_EARLY && mapImage.img == null) {
+                mapImage.img = MapPaintStyles.getNoIcon_Icon(iconRef.source).getImage();
+                mapImage.alpha = 255;
+            } else {
+                mapImage.width = width;
+                mapImage.height = height;
+
+                mapImage.alpha = Math.min(255, Math.max(0, Integer.valueOf(Main.pref.getInteger("mappaint.icon-image-alpha", 255))));
+                Integer pAlpha = Utils.color_float2int(c.get("icon-opacity", null, float.class));
+                if (pAlpha != null) {
+                    mapImage.alpha = pAlpha;
+                }
             }
-            mapImage.width = width;
-            mapImage.height = height;
+            if (result == ImageProvider.STATUS_IN_BACKGROUND) {
+                mapImage.img = ImageProvider.get("clock").getImage();
+            }
         }
         return mapImage;
     }
Index: src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java
===================================================================
--- src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java	(revision 4823)
+++ src/org/openstreetmap/josm/gui/mappaint/MapPaintStyles.java	(working copy)
@@ -130,7 +130,7 @@
                 .setOptional(true).get();
     }
 
-    private static List<String> getIconSourceDirs(StyleSource source) {
+    public static List<String> getIconSourceDirs(StyleSource source) {
         List<String> dirs = new LinkedList<String>();
 
         String sourceDir = source.getLocalSourceDir();
