Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java	(revision 7058)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java	(revision 7059)
@@ -30,4 +30,9 @@
 import java.util.Iterator;
 import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 
 import javax.swing.AbstractButton;
@@ -38,4 +43,5 @@
 import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.osm.BBox;
+import org.openstreetmap.josm.data.osm.Changeset;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
@@ -46,4 +52,5 @@
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.WaySegment;
+import org.openstreetmap.josm.data.osm.visitor.Visitor;
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData;
@@ -72,4 +79,12 @@
 public class StyledMapRenderer extends AbstractMapRenderer {
 
+    final public static int noThreads;
+    final public static ExecutorService styleCreatorPool;
+    
+    static {
+        noThreads = Runtime.getRuntime().availableProcessors();
+        styleCreatorPool = Executors.newFixedThreadPool(noThreads);
+    }
+
     /**
      * Iterates over a list of Way Nodes and returns screen coordinates that
@@ -169,60 +184,4 @@
         public void remove() {
             throw new UnsupportedOperationException();
-        }
-    }
-
-    private class StyleCollector {
-        private final boolean drawArea;
-        private final boolean drawMultipolygon;
-        private final boolean drawRestriction;
-
-        private final List<StyleRecord> styleElems;
-
-        public StyleCollector(boolean drawArea, boolean drawMultipolygon, boolean drawRestriction) {
-            this.drawArea = drawArea;
-            this.drawMultipolygon = drawMultipolygon;
-            this.drawRestriction = drawRestriction;
-            styleElems = new ArrayList<>();
-        }
-
-        public void add(Node osm, int flags) {
-            StyleList sl = styles.get(osm, circum, nc);
-            for (ElemStyle s : sl) {
-                styleElems.add(new StyleRecord(s, osm, flags));
-            }
-        }
-
-        public void add(Relation osm, int flags) {
-            StyleList sl = styles.get(osm, circum, nc);
-            for (ElemStyle s : sl) {
-                if (drawMultipolygon && drawArea && s instanceof AreaElemStyle && (flags & FLAG_DISABLED) == 0) {
-                    styleElems.add(new StyleRecord(s, osm, flags));
-                } else if (drawRestriction && s instanceof NodeElemStyle) {
-                    styleElems.add(new StyleRecord(s, osm, flags));
-                }
-            }
-        }
-
-        public void add(Way osm, int flags) {
-            StyleList sl = styles.get(osm, circum, nc);
-            for (ElemStyle s : sl) {
-                if (!(drawArea && (flags & FLAG_DISABLED) == 0) && s instanceof AreaElemStyle) {
-                    continue;
-                }
-                styleElems.add(new StyleRecord(s, osm, flags));
-            }
-        }
-
-        public void drawAll() {
-            Collections.sort(styleElems);
-            for (StyleRecord r : styleElems) {
-                r.style.paintPrimitive(
-                        r.osm,
-                        paintSettings,
-                        StyledMapRenderer.this,
-                        (r.flags & FLAG_SELECTED) != 0,
-                        (r.flags & FLAG_MEMBER_OF_SELECTED) != 0
-                );
-            }
         }
     }
@@ -369,50 +328,4 @@
     }
 
-    private void collectNodeStyles(DataSet data, StyleCollector sc, BBox bbox) {
-        for (final Node n: data.searchNodes(bbox)) {
-            if (n.isDrawable()) {
-                if (n.isDisabled()) {
-                    sc.add(n, FLAG_DISABLED);
-                } else if (data.isSelected(n)) {
-                    sc.add(n, FLAG_SELECTED);
-                } else if (n.isMemberOfSelected()) {
-                    sc.add(n, FLAG_MEMBER_OF_SELECTED);
-                } else {
-                    sc.add(n, FLAG_NORMAL);
-                }
-            }
-        }
-    }
-
-    private void collectWayStyles(DataSet data, StyleCollector sc, BBox bbox) {
-        for (final Way w : data.searchWays(bbox)) {
-            if (w.isDrawable()) {
-                if (w.isDisabled()) {
-                    sc.add(w, FLAG_DISABLED);
-                } else if (data.isSelected(w)) {
-                    sc.add(w, FLAG_SELECTED);
-                } else if (w.isMemberOfSelected()) {
-                    sc.add(w, FLAG_MEMBER_OF_SELECTED);
-                } else {
-                    sc.add(w, FLAG_NORMAL);
-                }
-            }
-        }
-    }
-
-    private void collectRelationStyles(DataSet data, StyleCollector sc, BBox bbox) {
-        for (Relation r: data.searchRelations(bbox)) {
-            if (r.isDrawable()) {
-                if (r.isDisabled()) {
-                    sc.add(r, FLAG_DISABLED);
-                } else if (data.isSelected(r)) {
-                    sc.add(r, FLAG_SELECTED);
-                } else {
-                    sc.add(r, FLAG_NORMAL);
-                }
-            }
-        }
-    }
-
     private void displaySegments(GeneralPath path, GeneralPath orientationArrows, GeneralPath onewayArrows, GeneralPath onewayArrowsCasing,
             Color color, BasicStroke line, BasicStroke dashes, Color dashedColor) {
@@ -1390,5 +1303,5 @@
         return null;
     }
-
+    
     @Override
     public void render(final DataSet data, boolean renderVirtualNodes, Bounds bounds) {
@@ -1396,7 +1309,7 @@
         getSettings(renderVirtualNodes);
 
-        boolean drawArea = circum <= Main.pref.getInteger("mappaint.fillareas", 10000000);
-        boolean drawMultipolygon = drawArea && Main.pref.getBoolean("mappaint.multipolygon", true);
-        boolean drawRestriction = Main.pref.getBoolean("mappaint.restriction", true);
+        final boolean drawArea = circum <= Main.pref.getInteger("mappaint.fillareas", 10000000);
+        final boolean drawMultipolygon = drawArea && Main.pref.getBoolean("mappaint.multipolygon", true);
+        final boolean drawRestriction = Main.pref.getBoolean("mappaint.restriction", true);
 
         styles = MapPaintStyles.getStyles();
@@ -1412,8 +1325,149 @@
         }
 
-        StyleCollector sc = new StyleCollector(drawArea, drawMultipolygon, drawRestriction);
-        collectNodeStyles(data, sc, bbox);
-        collectWayStyles(data, sc, bbox);
-        collectRelationStyles(data, sc, bbox);
+        class ComputeStyleListWorker implements Callable<List<StyleRecord>>, Visitor {
+            private final List<StyleRecord> styleList;
+            private final List<? extends OsmPrimitive> input;
+            private final int from;
+            private final int to;
+
+            /**
+             * Constructor for CreateStyleRecordsWorker.
+             * @param input the primitives to process
+             * @param from first index of <code>input</code> to use
+             * @param to last index + 1
+             */
+            public ComputeStyleListWorker(List<? extends OsmPrimitive> input, int from, int to) {
+                this.styleList = new ArrayList<>(to - from);
+                this.input = input;
+                this.from = from;
+                this.to = to;
+            }
+            
+            @Override
+            public List<StyleRecord> call() throws Exception {
+                for (int i = from; i<to; i++) {
+                    OsmPrimitive osm = input.get(i);
+                    if (osm.isDrawable()) {
+                        osm.accept(this);
+                    }
+                }
+                return styleList;
+            }
+            
+            @Override
+            public void visit(Node n) {
+                if (n.isDisabled()) {
+                    add(n, FLAG_DISABLED);
+                } else if (data.isSelected(n)) {
+                    add(n, FLAG_SELECTED);
+                } else if (n.isMemberOfSelected()) {
+                    add(n, FLAG_MEMBER_OF_SELECTED);
+                } else {
+                    add(n, FLAG_NORMAL);
+                }
+            }
+
+            @Override
+            public void visit(Way w) {
+                if (w.isDisabled()) {
+                    add(w, FLAG_DISABLED);
+                } else if (data.isSelected(w)) {
+                    add(w, FLAG_SELECTED);
+                } else if (w.isMemberOfSelected()) {
+                    add(w, FLAG_MEMBER_OF_SELECTED);
+                } else {
+                    add(w, FLAG_NORMAL);
+                }
+            }
+
+            @Override
+            public void visit(Relation r) {
+                if (r.isDisabled()) {
+                    add(r, FLAG_DISABLED);
+                } else if (data.isSelected(r)) {
+                    add(r, FLAG_SELECTED);
+                } else {
+                    add(r, FLAG_NORMAL);
+                }
+            }
+
+            @Override
+            public void visit(Changeset cs) {
+                throw new UnsupportedOperationException();
+            }
+
+            public void add(Node osm, int flags) {
+                StyleList sl = styles.get(osm, circum, nc);
+                for (ElemStyle s : sl) {
+                    styleList.add(new StyleRecord(s, osm, flags));
+                }
+            }
+
+            public void add(Relation osm, int flags) {
+                StyleList sl = styles.get(osm, circum, nc);
+                for (ElemStyle s : sl) {
+                    if (drawMultipolygon && drawArea && s instanceof AreaElemStyle && (flags & FLAG_DISABLED) == 0) {
+                        styleList.add(new StyleRecord(s, osm, flags));
+                    } else if (drawRestriction && s instanceof NodeElemStyle) {
+                        styleList.add(new StyleRecord(s, osm, flags));
+                    }
+                }
+            }
+
+            public void add(Way osm, int flags) {
+                StyleList sl = styles.get(osm, circum, nc);
+                for (ElemStyle s : sl) {
+                    if (!(drawArea && (flags & FLAG_DISABLED) == 0) && s instanceof AreaElemStyle) {
+                        continue;
+                    }
+                    styleList.add(new StyleRecord(s, osm, flags));
+                }
+            }
+        }
+
+        final List<ComputeStyleListWorker> tasks = new ArrayList<>();
+        final List<StyleRecord> allStyleElems = new ArrayList<>();
+        
+        class ConcurrentTasksHelper {
+            void createTasks(List<? extends OsmPrimitive> prims) {
+                int bucketsize = Math.max(100, prims.size()/noThreads/3);
+                for (int i=0; i*bucketsize < prims.size(); i++) {
+                    tasks.add(new ComputeStyleListWorker(prims, i*bucketsize, Math.min((i+1)*bucketsize, prims.size())));
+                }
+            }
+            
+            void runIt() {
+                if (tasks.size() == 1) {
+                    try {
+                        allStyleElems.addAll(tasks.get(0).call());
+                    } catch (Exception ex) {
+                        throw new RuntimeException(ex);
+                    }
+                } else if (tasks.size() > 1) {
+                    try {
+                        for (Future<List<StyleRecord>> future : styleCreatorPool.invokeAll(tasks)) {
+                                allStyleElems.addAll(future.get());
+                        }
+                    } catch (InterruptedException | ExecutionException ex) {
+                        throw new RuntimeException(ex);
+                    }
+                }
+            }
+        }
+        ConcurrentTasksHelper helper = new ConcurrentTasksHelper();
+        
+        // Need to process all relations first.
+        // Reason: Make sure, ElemStyles.getStyleCacheWithRange is
+        // not called for the same primtive in parallel threads.
+        // (Could be synchronized, but try to avoid this for
+        // performance reasons.)
+        helper.createTasks(data.searchRelations(bbox));
+        helper.runIt();
+        
+        tasks.clear();
+        helper.createTasks(data.searchNodes(bbox));
+        helper.createTasks(data.searchWays(bbox));
+        helper.runIt();
+        
         
         if (Main.isTraceEnabled()) {
@@ -1422,6 +1476,15 @@
         }
         
-        sc.drawAll();
-        sc = null;
+        Collections.sort(allStyleElems);
+        
+        for (StyleRecord r : allStyleElems) {
+            r.style.paintPrimitive(
+                    r.osm,
+                    paintSettings,
+                    StyledMapRenderer.this,
+                    (r.flags & FLAG_SELECTED) != 0,
+                    (r.flags & FLAG_MEMBER_OF_SELECTED) != 0
+            );
+        }
 
         if (Main.isTraceEnabled()) {
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java	(revision 7058)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java	(revision 7059)
@@ -86,15 +86,37 @@
      * Two preference values and the set of created fonts are cached in order to avoid
      * expensive lookups and to avoid too many font objects
-     * (in analogy to flyweight pattern).
      *
      * FIXME: cached preference values are not updated if the user changes them during
      * a JOSM session. Should have a listener listening to preference changes.
      */
-    private static String DEFAULT_FONT_NAME = null;
-    private static Float DEFAULT_FONT_SIZE = null;
-    private static void initDefaultFontParameters() {
-        if (DEFAULT_FONT_NAME != null) return; // already initialized - skip initialization
-        DEFAULT_FONT_NAME = Main.pref.get("mappaint.font", "Helvetica");
-        DEFAULT_FONT_SIZE = (float) Main.pref.getInteger("mappaint.fontsize", 8);
+    private static volatile String DEFAULT_FONT_NAME = null;
+    private static volatile Float DEFAULT_FONT_SIZE = null;
+    private static final Object lock = new Object();
+    
+    // thread save access (double-checked locking)
+    private static Float getDefaultFontSize() {
+        Float s = DEFAULT_FONT_SIZE;
+        if (s == null) {
+            synchronized (lock) {
+                s = DEFAULT_FONT_SIZE;
+                if (s == null) {
+                    DEFAULT_FONT_SIZE = s = (float) Main.pref.getInteger("mappaint.fontsize", 8);
+                }
+            }
+        }
+        return s;
+    }
+
+    private static String getDefaultFontName() {
+        String n = DEFAULT_FONT_NAME;
+        if (n == null) {
+            synchronized (lock) {
+                n = DEFAULT_FONT_NAME;
+                if (n == null) {
+                    DEFAULT_FONT_NAME = n = Main.pref.get("mappaint.font", "Helvetica");
+                }
+            }
+        }
+        return n;
     }
 
@@ -155,7 +177,6 @@
 
     protected static Font getFont(Cascade c) {
-        initDefaultFontParameters(); // populated cached preferences, if necessary
-        String name = c.get("font-family", DEFAULT_FONT_NAME, String.class);
-        float size = c.get("font-size", DEFAULT_FONT_SIZE, Float.class);
+        String name = c.get("font-family", getDefaultFontName(), String.class);
+        float size = c.get("font-size", getDefaultFontSize(), Float.class);
         int weight = Font.PLAIN;
         if ("bold".equalsIgnoreCase(c.get("font-weight", null, String.class))) {
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 7058)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 7059)
@@ -192,5 +192,8 @@
 
                     if (!hasIndependentLineStyle) {
-                        Pair<StyleList, Range> mpElemStyles = getStyleCacheWithRange(r, scale, nc);
+                        Pair<StyleList, Range> mpElemStyles;
+                        synchronized(r) {
+                            mpElemStyles = getStyleCacheWithRange(r, scale, nc);
+                        }
                         ElemStyle mpLine = null;
                         for (ElemStyle s : mpElemStyles.a) {
@@ -249,6 +252,9 @@
                     }
                     if (!hasIndependentElemStyle && !multipolygon.getOuterWays().isEmpty()) {
-                        StyleList mpElemStyles = get(ref, scale, nc);
                         Color mpColor = null;
+                        StyleList mpElemStyles = null;
+                        synchronized (ref) {
+                            mpElemStyles = get(ref, scale, nc);
+                        }
                         for (ElemStyle mpS : mpElemStyles) {
                             if (mpS instanceof AreaElemStyle) {
