diff --git a/router/java/src/net/i2p/router/InNetMessagePool.java b/router/java/src/net/i2p/router/InNetMessagePool.java
index 579ae8f398aca2fe1bb5d696ac4c20d9a1547171..d576ea9fdc5c9e2aa03829208fee0f5b962e17a0 100644
--- a/router/java/src/net/i2p/router/InNetMessagePool.java
+++ b/router/java/src/net/i2p/router/InNetMessagePool.java
@@ -324,14 +324,14 @@ public class InNetMessagePool implements Service {
     public void renderStatusHTML(Writer out) {}
 
     /** does nothing since we aren't threaded */
-    public void restart() { 
+    public synchronized void restart() { 
         shutdown(); 
         try { Thread.sleep(100); } catch (InterruptedException ie) {}
         startup(); 
     }
 
     /** does nothing since we aren't threaded */
-    public void shutdown() {
+    public synchronized void shutdown() {
         _alive = false;
         if (!DISPATCH_DIRECT) {
             synchronized (_pendingDataMessages) {
@@ -343,7 +343,7 @@ public class InNetMessagePool implements Service {
     }
     
     /** does nothing since we aren't threaded */
-    public void startup() {
+    public synchronized void startup() {
         _alive = true;
         _dispatchThreaded = DEFAULT_DISPATCH_THREADED;
         String threadedStr = _context.getProperty(PROP_DISPATCH_THREADED);
diff --git a/router/java/src/net/i2p/router/MessageHistory.java b/router/java/src/net/i2p/router/MessageHistory.java
index 7931514da149917f9a675189297d5fe3e2060fb8..e566462d12ea553f5dcc59a76ac97d4d57cda47e 100644
--- a/router/java/src/net/i2p/router/MessageHistory.java
+++ b/router/java/src/net/i2p/router/MessageHistory.java
@@ -65,7 +65,7 @@ public class MessageHistory {
     }
     
     /** @since 0.8.12 */
-    public void shutdown() {
+    public synchronized void shutdown() {
         if (_doLog)
             addEntry(getPrefix() + "** Router shutdown");
         _doPause = false;
@@ -89,7 +89,7 @@ public class MessageHistory {
      * Call this whenever the router identity changes.
      *
      */
-    public void initialize(boolean forceReinitialize) {
+    public synchronized void initialize(boolean forceReinitialize) {
         if (!forceReinitialize) return;
 
         if (_context.router().getRouterInfo() == null) {
diff --git a/router/java/src/net/i2p/router/MessageValidator.java b/router/java/src/net/i2p/router/MessageValidator.java
index e5b1a120aeaf484ce6c3c2342bb4687b3f43ad3a..6a6a432d90de84c981bf9ed4cd555184d0893d13 100644
--- a/router/java/src/net/i2p/router/MessageValidator.java
+++ b/router/java/src/net/i2p/router/MessageValidator.java
@@ -94,11 +94,11 @@ public class MessageValidator {
         return dup;
     }
     
-    public void startup() {
+    public synchronized void startup() {
         _filter = new DecayingHashSet(_context, (int)Router.CLOCK_FUDGE_FACTOR * 2, 8, "RouterMV");
     }
     
-    void shutdown() {
+    synchronized void shutdown() {
         _filter.stopDecaying();
     }
 }
diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java
index 236fe0be7417a3ad9915d89cb7970c242c25818b..d19006843d4d7a6153f24f8350a7c28c713f631a 100644
--- a/router/java/src/net/i2p/router/Router.java
+++ b/router/java/src/net/i2p/router/Router.java
@@ -66,6 +66,7 @@ public class Router implements RouterClock.ClockShiftListener {
     private String _configFilename;
     private RouterInfo _routerInfo;
     public final Object routerInfoFileLock = new Object();
+    private final Object _configFileLock = new Object();
     private long _started;
     private boolean _higherVersionSeen;
     //private SessionKeyPersistenceHelper _sessionKeyPersistenceHelper;
@@ -413,7 +414,7 @@ public class Router implements RouterClock.ClockShiftListener {
      *  Most users will just call main() instead.
      *  @since public as of 0.9 for Android and other embedded uses
      */
-    public void runRouter() {
+    public synchronized void runRouter() {
         if (_isAlive)
             throw new IllegalStateException();
         String last = _config.get("router.previousFullVersion");
@@ -468,16 +469,19 @@ public class Router implements RouterClock.ClockShiftListener {
      *
      * This is synchronized with saveConfig()
      */
-    public synchronized void readConfig() {
-        String f = getConfigFilename();
-        Properties config = getConfig(_context, f);
-        // to avoid compiler errror
-        Map foo = _config;
-        foo.putAll(config);
+    public void readConfig() {
+        synchronized(_configFileLock) {
+            String f = getConfigFilename();
+            Properties config = getConfig(_context, f);
+            // to avoid compiler errror
+            Map foo = _config;
+            foo.putAll(config);
+        }
     }
     
     /**
      *  this does not use ctx.getConfigDir(), must provide a full path in filename
+     *  Caller must synchronize
      *
      *  @param ctx will be null at startup when called from constructor
      */
@@ -518,6 +522,7 @@ public class Router implements RouterClock.ClockShiftListener {
      * has changed.
      */
     public void rebuildRouterInfo() { rebuildRouterInfo(false); }
+
     public void rebuildRouterInfo(boolean blockingRebuild) {
         if (_log.shouldLog(Log.INFO))
             _log.info("Rebuilding new routerInfo");
@@ -698,7 +703,7 @@ public class Router implements RouterClock.ClockShiftListener {
      * files, then reboot the router.
      *
      */
-    public void rebuildNewIdentity() {
+    public synchronized void rebuildNewIdentity() {
         if (_shutdownHook != null) {
             try {
                 Runtime.getRuntime().removeShutdownHook(_shutdownHook);
@@ -747,7 +752,7 @@ public class Router implements RouterClock.ClockShiftListener {
     /**
      *  Shutdown with no chance of cancellation
      */
-    public void shutdown(int exitCode) {
+    public synchronized void shutdown(int exitCode) {
         if (_shutdownInProgress)
             return;
         _shutdownInProgress = true;
@@ -765,7 +770,7 @@ public class Router implements RouterClock.ClockShiftListener {
      *  Called by the ShutdownHook.
      *  NOT to be called by others, use shutdown().
      */
-    public void shutdown2(int exitCode) {
+    public synchronized void shutdown2(int exitCode) {
         // help us shut down esp. after OOM
         int priority = (exitCode == EXIT_OOM) ? Thread.MAX_PRIORITY - 1 : Thread.NORM_PRIORITY + 2;
         Thread.currentThread().setPriority(priority);
@@ -862,7 +867,7 @@ public class Router implements RouterClock.ClockShiftListener {
     /**
      *  Cancel the JVM runtime hook before calling this.
      */
-    private void finalShutdown(int exitCode) {
+    private synchronized void finalShutdown(int exitCode) {
         clearCaches();
         _log.log(Log.CRIT, "Shutdown(" + exitCode + ") complete"  /* , new Exception("Shutdown") */ );
         try { _context.logManager().shutdown(); } catch (Throwable t) { }
@@ -977,36 +982,38 @@ public class Router implements RouterClock.ClockShiftListener {
      *
      * Synchronized with file read in getConfig()
      */
-    public synchronized boolean saveConfig() {
-        FileOutputStream fos = null;
-        try {
-            fos = new SecureFileOutputStream(_configFilename);
-            StringBuilder buf = new StringBuilder(8*1024);
-            buf.append("# NOTE: This I2P config file must use UTF-8 encoding\n");
-            TreeSet ordered = new TreeSet(_config.keySet());
-            for (Iterator iter = ordered.iterator() ; iter.hasNext(); ) {
-                String key = (String)iter.next();
-                String val = _config.get(key);
-                    // Escape line breaks before saving.
-                    // Remember: "\" needs escaping both for regex and string.
-                    // NOOO - see comments in DataHelper
-                    //val = val.replaceAll("\\r","\\\\r");
-                    //val = val.replaceAll("\\n","\\\\n");
-                buf.append(key).append('=').append(val).append('\n');
+    public boolean saveConfig() {
+        synchronized(_configFileLock) {
+            FileOutputStream fos = null;
+            try {
+                fos = new SecureFileOutputStream(_configFilename);
+                StringBuilder buf = new StringBuilder(8*1024);
+                buf.append("# NOTE: This I2P config file must use UTF-8 encoding\n");
+                TreeSet ordered = new TreeSet(_config.keySet());
+                for (Iterator iter = ordered.iterator() ; iter.hasNext(); ) {
+                    String key = (String)iter.next();
+                    String val = _config.get(key);
+                        // Escape line breaks before saving.
+                        // Remember: "\" needs escaping both for regex and string.
+                        // NOOO - see comments in DataHelper
+                        //val = val.replaceAll("\\r","\\\\r");
+                        //val = val.replaceAll("\\n","\\\\n");
+                    buf.append(key).append('=').append(val).append('\n');
+                }
+                fos.write(buf.toString().getBytes("UTF-8"));
+            } catch (IOException ioe) {
+                // warning, _log will be null when called from constructor
+                if (_log != null)
+                    _log.error("Error saving the config to " + _configFilename, ioe);
+                else
+                    System.err.println("Error saving the config to " + _configFilename + ": " + ioe);
+                return false;
+            } finally {
+                if (fos != null) try { fos.close(); } catch (IOException ioe) {}
             }
-            fos.write(buf.toString().getBytes("UTF-8"));
-        } catch (IOException ioe) {
-            // warning, _log will be null when called from constructor
-            if (_log != null)
-                _log.error("Error saving the config to " + _configFilename, ioe);
-            else
-                System.err.println("Error saving the config to " + _configFilename + ": " + ioe);
-            return false;
-        } finally {
-            if (fos != null) try { fos.close(); } catch (IOException ioe) {}
+            
+            return true;
         }
-        
-        return true;
     }
     
     /**
@@ -1019,12 +1026,14 @@ public class Router implements RouterClock.ClockShiftListener {
      * @return success
      * @since 0.8.13
      */
-    public synchronized boolean saveConfig(String name, String value) {
-        if (value != null)
-            _config.put(name, value);
-        else
-            removeConfigSetting(name);
-        return saveConfig();
+    public boolean saveConfig(String name, String value) {
+        synchronized(_configFileLock) {
+            if (value != null)
+                _config.put(name, value);
+            else
+                removeConfigSetting(name);
+            return saveConfig();
+        }
     }
 
     /**
@@ -1037,15 +1046,17 @@ public class Router implements RouterClock.ClockShiftListener {
      * @return success
      * @since 0.8.13
      */
-    public synchronized boolean saveConfig(Map toAdd, Collection<String> toRemove) {
-        if (toAdd != null)
-            _config.putAll(toAdd);
-        if (toRemove != null) {
-            for (String s : toRemove) {
-                removeConfigSetting(s);
+    public boolean saveConfig(Map toAdd, Collection<String> toRemove) {
+        synchronized(_configFileLock) {
+            if (toAdd != null)
+                _config.putAll(toAdd);
+            if (toRemove != null) {
+                for (String s : toRemove) {
+                    removeConfigSetting(s);
+                }
             }
+            return saveConfig();
         }
-        return saveConfig();
     }
 
     /**
diff --git a/router/java/src/net/i2p/router/client/ClientManager.java b/router/java/src/net/i2p/router/client/ClientManager.java
index 7e444f8e2ea2d9150f8652b6c7d9818d209573a7..71f2fc597e324a80aca0249a2f93e750a337d6d8 100644
--- a/router/java/src/net/i2p/router/client/ClientManager.java
+++ b/router/java/src/net/i2p/router/client/ClientManager.java
@@ -89,7 +89,7 @@ class ClientManager {
         _isStarted = true;
     }
     
-    public void restart() {
+    public synchronized void restart() {
         shutdown("Router restart");
         
         // to let the old listener die
@@ -103,7 +103,7 @@ class ClientManager {
     /**
      *  @param msg message to send to the clients
      */
-    public void shutdown(String msg) {
+    public synchronized void shutdown(String msg) {
         _isStarted = false;
         _log.info("Shutting down the ClientManager");
         if (_listener != null)
diff --git a/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java b/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java
index 5045c6c8b3dd2745fb70585260832ae9806c7ec0..e422e99177965f23120316e3c0c7df10dcf947dc 100644
--- a/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java
+++ b/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java
@@ -52,13 +52,13 @@ public class ClientManagerFacadeImpl extends ClientManagerFacade implements Inte
         //_log.debug("Client manager facade created");
     }
     
-    public void startup() {
+    public synchronized void startup() {
         _log.info("Starting up the client subsystem");
         int port = _context.getProperty(PROP_CLIENT_PORT, DEFAULT_PORT);
         _manager = new ClientManager(_context, port);
     }    
     
-    public void shutdown() {
+    public synchronized void shutdown() {
         shutdown("Router shutdown");
     }
 
@@ -66,12 +66,12 @@ public class ClientManagerFacadeImpl extends ClientManagerFacade implements Inte
      *  @param msg message to send to the clients
      *  @since 0.8.8
      */
-    public void shutdown(String msg) {
+    public synchronized void shutdown(String msg) {
         if (_manager != null)
             _manager.shutdown(msg);
     }
     
-    public void restart() {
+    public synchronized void restart() {
         if (_manager != null)
             _manager.restart();
         else
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java
index 562a4ac82155c6f1b8aa25aed1ad3efb0ebd69e4..a9380b917a8bd5f86066a8997c9c6df641ef448b 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java
@@ -65,7 +65,7 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad
     }
 
     @Override
-    public void startup() {
+    public synchronized void startup() {
         super.startup();
         _context.jobQueue().addJob(new FloodfillMonitorJob(_context, this));
         _lookupThrottler = new LookupThrottler();
@@ -87,7 +87,7 @@ public class FloodfillNetworkDatabaseFacade extends KademliaNetworkDatabaseFacad
      *  @since 0.8.9
      */
     @Override
-    public void shutdown() {
+    public synchronized void shutdown() {
         if (_floodfillEnabled) {
             // turn off to build a new RI...
             _floodfillEnabled = false;
diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java
index 3da3b819b6a89b3c77cfe69e3f6581aa324c0210..b246c3afbdda31fab10dfa82c252151511febaa0 100644
--- a/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java
+++ b/router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java
@@ -198,7 +198,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
         _context.statManager().addRateData("netDb.exploreKeySet", _exploreKeys.size(), 0);
     }
     
-    public void shutdown() {
+    public synchronized void shutdown() {
         _initialized = false;
         if (_kb != null)
             _kb.clear();
@@ -212,7 +212,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
         // _exploreKeys = null;
     }
     
-    public void restart() {
+    public synchronized void restart() {
         _dbDir = _context.router().getConfigSetting(PROP_DB_DIR);
         if (_dbDir == null) {
             _log.info("No DB dir specified [" + PROP_DB_DIR + "], using [" + DEFAULT_DB_DIR + "]");
@@ -240,7 +240,7 @@ public class KademliaNetworkDatabaseFacade extends NetworkDatabaseFacade {
 
     String getDbDir() { return _dbDir; }
     
-    public void startup() {
+    public synchronized void startup() {
         _log.info("Starting up the kademlia network database");
         RouterInfo ri = _context.router().getRouterInfo();
         String dbDir = _context.getProperty(PROP_DB_DIR, DEFAULT_DB_DIR);
diff --git a/router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java b/router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java
index c1ab66931ed35f90605822d82de7f6f831bb42bd..433067e83879adbb96ea3fa5840839e10230730e 100644
--- a/router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java
+++ b/router/java/src/net/i2p/router/peermanager/PeerManagerFacadeImpl.java
@@ -38,14 +38,14 @@ public class PeerManagerFacadeImpl implements PeerManagerFacade {
         _testJob = new PeerTestJob(_context);
     }
     
-    public void startup() {
+    public synchronized void startup() {
         _log.info("Starting up the peer manager");
         _manager = new PeerManager(_context);
         _persistenceHelper.setUs(_context.routerHash());
         _testJob.startTesting(_manager);
     }
     
-    public void shutdown() {
+    public synchronized void shutdown() {
         _log.info("Shutting down the peer manager");
         _testJob.stopTesting();
         if (_manager != null) {
@@ -54,7 +54,7 @@ public class PeerManagerFacadeImpl implements PeerManagerFacade {
         }
     }
     
-    public void restart() {
+    public synchronized void restart() {
         _manager.storeProfiles();
         _persistenceHelper.setUs(_context.routerHash());
         _manager.loadProfiles();
diff --git a/router/java/src/net/i2p/router/peermanager/PeerTestJob.java b/router/java/src/net/i2p/router/peermanager/PeerTestJob.java
index 1cbd035a44eecc00691699af92ccb4de2c36853d..bd2140091fa394278d9ec653df315e2c3408239f 100644
--- a/router/java/src/net/i2p/router/peermanager/PeerTestJob.java
+++ b/router/java/src/net/i2p/router/peermanager/PeerTestJob.java
@@ -50,7 +50,7 @@ public class PeerTestJob extends JobImpl {
     private int getTestConcurrency() { return 1; }
     
     // FIXME Exporting non-public type through public API FIXME
-    public void startTesting(PeerManager manager) {
+    public synchronized void startTesting(PeerManager manager) {
         _manager = manager;
         _keepTesting = true;
         this.getTiming().setStartAfter(getContext().clock().now() + DEFAULT_PEER_TEST_DELAY);
@@ -58,7 +58,8 @@ public class PeerTestJob extends JobImpl {
         if (_log.shouldLog(Log.INFO))
             _log.info("Start testing peers");
     }
-    public void stopTesting() { 
+
+    public synchronized void stopTesting() { 
         _keepTesting = false;
         if (_log.shouldLog(Log.INFO))
             _log.info("Stop testing peers");
diff --git a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
index e139cfb2d2ddb6a8893d951af68e40eb2ce8d326..e6a24e2eac3bdcf925056edee5699ff6669a786b 100644
--- a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
+++ b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java
@@ -49,7 +49,7 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
         startGeoIP();
     }
     
-    public void startup() {
+    public synchronized void startup() {
         _log.info("Starting up the comm system");
         _manager = new TransportManager(_context);
         _manager.startListening();
@@ -59,13 +59,13 @@ public class CommSystemFacadeImpl extends CommSystemFacade {
     /**
      *  Cannot be restarted.
      */
-    public void shutdown() {
+    public synchronized void shutdown() {
         if (_manager != null)
             _manager.shutdown();
         _geoIP.shutdown();
     }
     
-    public void restart() {
+    public synchronized void restart() {
         if (_manager == null)
             startup();
         else
diff --git a/router/java/src/net/i2p/router/transport/FIFOBandwidthLimiter.java b/router/java/src/net/i2p/router/transport/FIFOBandwidthLimiter.java
index b7834fe181671a905832659c29e792d64d0f6cfc..15ccd18fee5007d4088985cea34280dbeea22aaf 100644
--- a/router/java/src/net/i2p/router/transport/FIFOBandwidthLimiter.java
+++ b/router/java/src/net/i2p/router/transport/FIFOBandwidthLimiter.java
@@ -140,13 +140,13 @@ public class FIFOBandwidthLimiter {
     /** The configured maximum, not the current rate */
     public int getInboundBurstKBytesPerSecond() { return _refiller.getInboundBurstKBytesPerSecond(); } 
     
-    public void reinitialize() {
+    public synchronized void reinitialize() {
         clear();
         _refiller.reinitialize();
     }
 
     /** @since 0.8.8 */
-    public void shutdown() {
+    public synchronized void shutdown() {
         _refiller.shutdown();
         _refillerThread.interrupt();
         clear();
diff --git a/router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java b/router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java
index a6da603ca6d17ef8558561a1a59dff691136aa37..ddcea3576087cbd6a3299ca7415e529932712a1e 100644
--- a/router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java
+++ b/router/java/src/net/i2p/router/transport/FIFOBandwidthRefiller.java
@@ -85,7 +85,7 @@ public class FIFOBandwidthRefiller implements Runnable {
     }
 
     /** @since 0.8.8 */
-    void shutdown() {
+    synchronized void shutdown() {
         _isRunning = false;
     }
 
@@ -111,7 +111,7 @@ public class FIFOBandwidthRefiller implements Runnable {
         }
     }
     
-    void reinitialize() {
+    synchronized void reinitialize() {
         _lastRefillTime = _limiter.now();
         checkConfig();
         _lastCheckConfigTime = _lastRefillTime;
diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java
index d4587e60ea1293ff22a9360cf053e840e07f7e6d..79e03112090f555b6c76a1bcf4906be18049bc64 100644
--- a/router/java/src/net/i2p/router/transport/TransportManager.java
+++ b/router/java/src/net/i2p/router/transport/TransportManager.java
@@ -136,7 +136,7 @@ public class TransportManager implements TransportEventListener {
             t.forwardPortStatus(port, externalPort, success, reason);
     }
 
-    public void startListening() {
+    public synchronized void startListening() {
         if (_dhThread.getState() == Thread.State.NEW)
             _dhThread.start();
         // For now, only start UPnP if we have no publicly-routable addresses
@@ -159,7 +159,7 @@ public class TransportManager implements TransportEventListener {
         _context.router().rebuildRouterInfo();
     }
     
-    public void restart() {
+    public synchronized void restart() {
         stopListening();
         try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
         startListening();
@@ -168,7 +168,7 @@ public class TransportManager implements TransportEventListener {
     /**
      *  Can be restarted.
      */
-    public void stopListening() {
+    public synchronized void stopListening() {
         if (_upnpManager != null)
             _upnpManager.stop();
         for (Transport t : _transports.values()) {
@@ -182,7 +182,7 @@ public class TransportManager implements TransportEventListener {
      *  Cannot be restarted.
      *  @since 0.9
      */
-    public void shutdown() {
+    public synchronized void shutdown() {
         stopListening();
         _dhThread.shutdown();
         Addresses.clearCaches();
diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPSendFinisher.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPSendFinisher.java
index ee2fdffa54534f907f9e5d8f354c2a417e8acad4..e6bea5c2e466c3cdd0512dfcb5921c5e8c5fc602 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/NTCPSendFinisher.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPSendFinisher.java
@@ -46,12 +46,12 @@ class NTCPSendFinisher {
         //_context.statManager().createRateStat("ntcp.sendFinishTime", "How long to queue and excecute msg.afterSend()", "ntcp", new long[] {5*1000});
     }
     
-    public void start() {
+    public synchronized void start() {
         _count = 0;
         _executor = new CustomThreadPoolExecutor(THREADS);
     }
 
-    public void stop() {
+    public synchronized void stop() {
         if (_executor != null)
             _executor.shutdownNow();
     }
diff --git a/router/java/src/net/i2p/router/transport/ntcp/Reader.java b/router/java/src/net/i2p/router/transport/ntcp/Reader.java
index 13a4632df846553d18f7214cff6bcf8ddd6b0675..11dcd07b6d191ca1f7d23ee8a5b2963d1302bfb4 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/Reader.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/Reader.java
@@ -36,7 +36,7 @@ class Reader {
         _readAfterLive = new HashSet(8);
     }
     
-    public void startReading(int numReaders) {
+    public synchronized void startReading(int numReaders) {
         for (int i = 1; i <= numReaders; i++) {
             Runner r = new Runner();
             I2PThread t = new I2PThread(r, "NTCP reader " + i + '/' + numReaders, true);
@@ -45,7 +45,7 @@ class Reader {
         }
     }
 
-    public void stopReading() {
+    public synchronized void stopReading() {
         while (!_runners.isEmpty()) {
             Runner r = _runners.remove(0);
             r.stop();
diff --git a/router/java/src/net/i2p/router/transport/ntcp/Writer.java b/router/java/src/net/i2p/router/transport/ntcp/Writer.java
index 1ed1e7c2199730a17fbf3d6d1b189188f03f040d..cba28fbcf454b88a1266805d9d9e1894c5172135 100644
--- a/router/java/src/net/i2p/router/transport/ntcp/Writer.java
+++ b/router/java/src/net/i2p/router/transport/ntcp/Writer.java
@@ -32,7 +32,7 @@ class Writer {
         _writeAfterLive = new HashSet(5);
     }
     
-    public void startWriting(int numWriters) {
+    public synchronized void startWriting(int numWriters) {
         for (int i = 1; i <=numWriters; i++) {
             Runner r = new Runner();
             I2PThread t = new I2PThread(r, "NTCP writer " + i + '/' + numWriters, true);
@@ -40,7 +40,7 @@ class Writer {
             t.start();
         }
     }
-    public void stopWriting() {
+    public synchronized void stopWriting() {
         while (!_runners.isEmpty()) {
             Runner r = _runners.remove(0);
             r.stop();
diff --git a/router/java/src/net/i2p/router/transport/udp/ACKSender.java b/router/java/src/net/i2p/router/transport/udp/ACKSender.java
index 8cb4f2f47dd437f45b6bde29d72bbb4382d65d0f..312f8d348e764aa9f555b837054610559760ff3b 100644
--- a/router/java/src/net/i2p/router/transport/udp/ACKSender.java
+++ b/router/java/src/net/i2p/router/transport/udp/ACKSender.java
@@ -53,14 +53,14 @@ class ACKSender implements Runnable {
             _peersToACK.offer(peer);
     }
     
-    public void startup() {
+    public synchronized void startup() {
         _alive = true;
         _peersToACK.clear();
         I2PThread t = new I2PThread(this, "UDP ACK sender", true);
         t.start();
     }
     
-    public void shutdown() { 
+    public synchronized void shutdown() { 
         _alive = false;
         PeerState poison = new PeerState(_context, _transport, null, 0, null, false);
         poison.setTheyRelayToUsAs(POISON_PS);
diff --git a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
index 03c7754092514562f3992531ae254c168cb1cb87..1e597ab078575e192581b8c392d1938432b13536 100644
--- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
+++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
@@ -157,13 +157,13 @@ class EstablishmentManager {
         //_context.statManager().createRateStat("udp.queueAllowTotalLifetime", "When a peer is retransmitting and we probabalistically allow a new message, what is the sum of the pending message lifetimes? (period is the new message's lifetime)?", "udp", UDPTransport.RATES);
     }
     
-    public void startup() {
+    public synchronized void startup() {
         _alive = true;
         I2PThread t = new I2PThread(new Establisher(), "UDP Establisher", true);
         t.start();
     }
 
-    public void shutdown() { 
+    public synchronized void shutdown() { 
         _alive = false;
         notifyActivity();
     }
diff --git a/router/java/src/net/i2p/router/transport/udp/InboundMessageFragments.java b/router/java/src/net/i2p/router/transport/udp/InboundMessageFragments.java
index 80493f987a74578d2031b2fdf123ce9c72971e65..2d551fda987caaba105a8ef074b02542210b5e80 100644
--- a/router/java/src/net/i2p/router/transport/udp/InboundMessageFragments.java
+++ b/router/java/src/net/i2p/router/transport/udp/InboundMessageFragments.java
@@ -48,7 +48,7 @@ class InboundMessageFragments /*implements UDPTransport.PartialACKSource */{
         _context.statManager().createRateStat("udp.receivePiggyback", "How many acks were included in a packet with data fragments (time == # data fragments)", "udp", UDPTransport.RATES);
     }
     
-    public void startup() { 
+    public synchronized void startup() { 
         _alive = true; 
         // may want to extend the DecayingBloomFilter so we can use a smaller 
         // array size (currently its tuned for 10 minute rates for the 
@@ -57,7 +57,8 @@ class InboundMessageFragments /*implements UDPTransport.PartialACKSource */{
         _ackSender.startup();
         _messageReceiver.startup();
     }
-    public void shutdown() {
+
+    public synchronized void shutdown() {
         _alive = false;
         if (_recentlyCompletedMessages != null)
             _recentlyCompletedMessages.stopDecaying();
diff --git a/router/java/src/net/i2p/router/transport/udp/MessageReceiver.java b/router/java/src/net/i2p/router/transport/udp/MessageReceiver.java
index 61061e7cb676ef02da465114b73a17e621b6005f..382cab6cbd291ef21ce01bcec1a3a8c606da293c 100644
--- a/router/java/src/net/i2p/router/transport/udp/MessageReceiver.java
+++ b/router/java/src/net/i2p/router/transport/udp/MessageReceiver.java
@@ -69,7 +69,7 @@ class MessageReceiver {
         _alive = true;
     }
     
-    public void startup() {
+    public synchronized void startup() {
         _alive = true;
         for (int i = 0; i < _threadCount; i++) {
             I2PThread t = new I2PThread(new Runner(), "UDP message receiver " + (i+1) + '/' + _threadCount, true);
@@ -83,7 +83,7 @@ class MessageReceiver {
         public void run() { loop(_handler); }
     }
     
-    public void shutdown() {
+    public synchronized void shutdown() {
         _alive = false;
         _completeMessages.clear();
         for (int i = 0; i < _threadCount; i++) {
diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java b/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java
index 9ce77b336418e2b1a4c5e17567d6efb9fa7205ba..d90c24cf1247839aaca5323e394ff630b38948b0 100644
--- a/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java
+++ b/router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java
@@ -92,9 +92,9 @@ class OutboundMessageFragments {
         _context.statManager().createRateStat("udp.sendCycleTimeSlow", "How long it takes to cycle through all of the active messages, when its going slowly?", "udp", UDPTransport.RATES);
     }
 
-    public void startup() { _alive = true; }
+    public synchronized void startup() { _alive = true; }
 
-    public void shutdown() {
+    public synchronized void shutdown() {
         _alive = false;
         _activePeers.clear();
         synchronized (_activePeers) {
diff --git a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java
index 572d26152ebe56bb64e519dda542ce92f0efcc5e..ff707407bffbcccc92e61ec760406804bf35e3df 100644
--- a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java
+++ b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java
@@ -91,7 +91,7 @@ class PacketHandler {
         //_context.statManager().createRateStat("udp.receivePacketSize.relayResponse", "Packet size of the given inbound packet type (period is the packet's lifetime)", "udp", UDPTransport.RATES);
     }
     
-    public void startup() { 
+    public synchronized void startup() { 
         _keepReading = true;
         for (int i = 0; i < _handlers.length; i++) {
             I2PThread t = new I2PThread(_handlers[i], "UDP Packet handler " + (i+1) + '/' + _handlers.length, true);
@@ -99,7 +99,7 @@ class PacketHandler {
         }
     }
     
-    public void shutdown() { 
+    public synchronized void shutdown() { 
         _keepReading = false; 
     }
 
diff --git a/router/java/src/net/i2p/router/transport/udp/PacketPusher.java b/router/java/src/net/i2p/router/transport/udp/PacketPusher.java
index 959c7a07c5f0d7b7ecb03469bc9080b3e7b9cebf..cf7ce21928117f399eb8fcacdec8c8a12d137227 100644
--- a/router/java/src/net/i2p/router/transport/udp/PacketPusher.java
+++ b/router/java/src/net/i2p/router/transport/udp/PacketPusher.java
@@ -23,13 +23,13 @@ class PacketPusher implements Runnable {
         _sender = sender;
     }
     
-    public void startup() {
+    public synchronized void startup() {
         _alive = true;
         I2PThread t = new I2PThread(this, "UDP packet pusher", true);
         t.start();
     }
     
-    public void shutdown() { _alive = false; }
+    public synchronized void shutdown() { _alive = false; }
      
     public void run() {
         while (_alive) {
diff --git a/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java b/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java
index 4daed3dfd197053476c905bf867809b7c409dd11..9f6f625a78e5597e63527c16889e6631c51723ca 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java
@@ -59,14 +59,14 @@ class UDPReceiver {
         _context.statManager().createRateStat("udp.ignorePacketFromDroplist", "Packet lifetime for those dropped on the drop list", "udp", UDPTransport.RATES);
     }
     
-    public void startup() {
+    public synchronized void startup() {
         //adjustDropProbability();
         _keepRunning = true;
         I2PThread t = new I2PThread(_runner, _name + '.' + _id, true);
         t.start();
     }
     
-    public void shutdown() {
+    public synchronized void shutdown() {
         _keepRunning = false;
         _inboundQueue.clear();
         for (int i = 0; i < _transport.getPacketHandlerCount(); i++) {
diff --git a/router/java/src/net/i2p/router/transport/udp/UDPSender.java b/router/java/src/net/i2p/router/transport/udp/UDPSender.java
index 88bdfb5b9857c2676712345682815957eece4e80..e169d3a8cff75d29ca67f385304b4d2a51e2c7a8 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPSender.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPSender.java
@@ -64,7 +64,7 @@ class UDPSender {
         _context.statManager().createRateStat("udp.sendPacketSize." + PacketBuilder.TYPE_CREAT, "session created packet size", "udp", UDPTransport.RATES);
     }
     
-    public void startup() {
+    public synchronized void startup() {
         if (_log.shouldLog(Log.DEBUG))
             _log.debug("Starting the runner: " + _name);
         _keepRunning = true;
@@ -72,7 +72,7 @@ class UDPSender {
         t.start();
     }
     
-    public void shutdown() {
+    public synchronized void shutdown() {
         _keepRunning = false;
         _outboundQueue.clear();
         UDPPacket poison = UDPPacket.acquire(_context, false);
diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
index f738c210404ade0d3271c5bf197e9b655d2af953..d3408db858b6db643f52c95dafaa3f96c110496c 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
@@ -245,7 +245,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
         _context.simpleScheduler().addPeriodicEvent(new PingIntroducers(), MIN_EXPIRE_TIMEOUT * 3 / 4);
     }
     
-    public void startup() {
+    public synchronized void startup() {
         _fragments.shutdown();
         if (_pusher != null)
             _pusher.shutdown();
@@ -373,7 +373,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
         _testEvent.reschedule(10*1000); // lets requeue it for Real Soon
     }
     
-    public void shutdown() {
+    public synchronized void shutdown() {
         destroyAll();
         if (_endpoint != null)
             _endpoint.shutdown();
diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java b/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java
index 774d4763cd53716662751bccc96246bec42bb0e5..34eaee9efab37ed4355633f3b94ea9f56e6afb26 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/BuildExecutor.java
@@ -86,7 +86,7 @@ class BuildExecutor implements Runnable {
     /**
      *  @since 0.9
      */
-    public void restart() {
+    public synchronized void restart() {
         synchronized (_recentBuildIds) { 
             _recentBuildIds.clear();
         }
@@ -98,7 +98,7 @@ class BuildExecutor implements Runnable {
      *  Cannot be restarted.
      *  @since 0.9
      */
-    public void shutdown() {
+    public synchronized void shutdown() {
         _isRunning = false;
         restart();
     }
diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java
index 5c4693fd2c2ac3abee822a3e15ffae5c6e4f76b0..c3f1c92b01aec69e6426fa4aab9c948bd68410f5 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java
@@ -134,7 +134,7 @@ class BuildHandler implements Runnable {
      *  @param numThreads the number of threads to be shut down
      *  @since 0.9
      */
-    public void shutdown(int numThreads) {
+    public synchronized void shutdown(int numThreads) {
         _isRunning = false;
         _inboundBuildMessages.clear();
         BuildMessageState poison = new BuildMessageState(null, null, null);
diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java
index 8b082b09f8ea54fde11eb756b52dd541fc869d4b..bda1fe727fd3a075aa36580136492185d85adffd 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java
@@ -390,7 +390,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
         }
     }
     
-    public void restart() { 
+    public synchronized void restart() { 
         _handler.restart();
         _executor.restart();
         shutdownExploratory();
@@ -504,7 +504,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
         }
     }
 
-    public void startup() { 
+    public synchronized void startup() { 
         _isShutdown = false;
         if (!_executor.isRunning()) {
             I2PThread t = new I2PThread(_executor, "BuildExecutor");
@@ -546,7 +546,7 @@ public class TunnelPoolManager implements TunnelManagerFacade {
     /**
      *  Cannot be restarted
      */
-    public void shutdown() { 
+    public synchronized void shutdown() { 
         _handler.shutdown(_numHandlerThreads);
         _executor.shutdown();
         shutdownExploratory();