ICU-20588 UMutex, add cleanup of underlying mutexes, and simplify usage model
diff --git a/icu4c/source/common/brkeng.cpp b/icu4c/source/common/brkeng.cpp
index 80e1158..78492db 100644
--- a/icu4c/source/common/brkeng.cpp
+++ b/icu4c/source/common/brkeng.cpp
@@ -129,8 +129,8 @@
     const LanguageBreakEngine *lbe = NULL;
     UErrorCode  status = U_ZERO_ERROR;
 
-    static UMutex *gBreakEngineMutex = STATIC_NEW(UMutex);
-    Mutex m(gBreakEngineMutex);
+    static UMutex gBreakEngineMutex;
+    Mutex m(&gBreakEngineMutex);
 
     if (fEngines == NULL) {
         UStack  *engines = new UStack(_deleteEngine, NULL, status);
diff --git a/icu4c/source/common/characterproperties.cpp b/icu4c/source/common/characterproperties.cpp
index 5ce8cac..7b50a4e 100644
--- a/icu4c/source/common/characterproperties.cpp
+++ b/icu4c/source/common/characterproperties.cpp
@@ -47,10 +47,7 @@
 
 UCPMap *maps[UCHAR_INT_LIMIT - UCHAR_INT_START] = {};
 
-icu::UMutex *cpMutex() {
-    static icu::UMutex *m = STATIC_NEW(icu::UMutex);
-    return m;
-}
+icu::UMutex cpMutex;
 
 //----------------------------------------------------------------
 // Inclusions list
@@ -361,7 +358,7 @@
         *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
         return nullptr;
     }
-    Mutex m(cpMutex());
+    Mutex m(&cpMutex);
     UnicodeSet *set = sets[property];
     if (set == nullptr) {
         sets[property] = set = makeSet(property, *pErrorCode);
@@ -377,7 +374,7 @@
         *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
         return nullptr;
     }
-    Mutex m(cpMutex());
+    Mutex m(&cpMutex);
     UCPMap *map = maps[property - UCHAR_INT_START];
     if (map == nullptr) {
         maps[property - UCHAR_INT_START] = map = makeMap(property, *pErrorCode);
diff --git a/icu4c/source/common/cmemory.h b/icu4c/source/common/cmemory.h
index 814e39d..274acc5 100644
--- a/icu4c/source/common/cmemory.h
+++ b/icu4c/source/common/cmemory.h
@@ -101,12 +101,18 @@
  * Create & return an instance of "type" in statically allocated storage.
  * e.g.
  *    static std::mutex *myMutex = STATIC_NEW(std::mutex);
- * This is intended for use when
+ * To destroy an object created in this way, invoke the destructor explicitly, e.g.
+ *    myMutex->~mutex();
+ * DO NOT use delete.
+ * DO NOT use with class UMutex, which has specific support for static instances.
+ *
+ * STATIC_NEW is intended for use when
  *   - We want a static (or global) object.
- *   - We don't want it to ever be destructed, to avoid order-of-destruction
- *     or use-after-destruction problems.
- *   - We want to avoid an ordinary heap allocated object, to avoid triggering
- *     memory leak reports, from valgrind, for example.
+ *   - We don't want it to ever be destructed, or to explicitly control destruction,
+ *     to avoid use-after-destruction problems.
+ *   - We want to avoid an ordinary heap allocated object,
+ *     to avoid the possibility of memory allocation failures, and
+ *     to avoid memory leak reports, from valgrind, for example.
  * This is defined as a macro rather than a template function because each invocation
  * must define distinct static storage for the object being returned.
  */
diff --git a/icu4c/source/common/locdspnm.cpp b/icu4c/source/common/locdspnm.cpp
index 923fed9..d590a88 100644
--- a/icu4c/source/common/locdspnm.cpp
+++ b/icu4c/source/common/locdspnm.cpp
@@ -557,8 +557,8 @@
     if ( result.length() > 0 && u_islower(result.char32At(0)) && capitalizationBrkIter!= NULL &&
           ( capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE || fCapitalization[usage] ) ) {
         // note fCapitalization[usage] won't be set unless capitalizationContext is UI_LIST_OR_MENU or STANDALONE
-        static UMutex *capitalizationBrkIterLock = STATIC_NEW(UMutex);
-        Mutex lock(capitalizationBrkIterLock);
+        static UMutex capitalizationBrkIterLock;
+        Mutex lock(&capitalizationBrkIterLock);
         result.toTitle(capitalizationBrkIter, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
     }
 #endif
diff --git a/icu4c/source/common/locid.cpp b/icu4c/source/common/locid.cpp
index eecebf4..5868b5e 100644
--- a/icu4c/source/common/locid.cpp
+++ b/icu4c/source/common/locid.cpp
@@ -62,10 +62,7 @@
 static UInitOnce gLocaleCacheInitOnce = U_INITONCE_INITIALIZER;
 
 // gDefaultLocaleMutex protects all access to gDefaultLocalesHashT and gDefaultLocale.
-static UMutex *gDefaultLocaleMutex() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
+static UMutex gDefaultLocaleMutex;
 static UHashtable *gDefaultLocalesHashT = NULL;
 static Locale *gDefaultLocale = NULL;
 
@@ -174,7 +171,7 @@
 
 Locale *locale_set_default_internal(const char *id, UErrorCode& status) {
     // Synchronize this entire function.
-    Mutex lock(gDefaultLocaleMutex());
+    Mutex lock(&gDefaultLocaleMutex);
 
     UBool canonicalize = FALSE;
 
@@ -711,7 +708,7 @@
 Locale::getDefault()
 {
     {
-        Mutex lock(gDefaultLocaleMutex());
+        Mutex lock(&gDefaultLocaleMutex);
         if (gDefaultLocale != NULL) {
             return *gDefaultLocale;
         }
diff --git a/icu4c/source/common/mutex.h b/icu4c/source/common/mutex.h
index 55768fb..d8fdf28 100644
--- a/icu4c/source/common/mutex.h
+++ b/icu4c/source/common/mutex.h
@@ -38,15 +38,12 @@
   *
   *  For example:
   *
-  *  UMutex *myMutex() {
-  *    static UMutex *m = STATIC_NEW(UMutex);
-  *    return m;
-  *  }
+  *  static UMutex myMutex;
   *
   *  void Function(int arg1, int arg2)
   *  {
   *     static Object* foo;      // Shared read-write object
-  *     Mutex mutex(myMutex());  // or no args for the global lock
+  *     Mutex mutex(&myMutex);   // or no args for the global lock
   *     foo->Method();
   *     // When 'mutex' goes out of scope and gets destroyed here, the lock is released
   *  }
diff --git a/icu4c/source/common/putil.cpp b/icu4c/source/common/putil.cpp
index 2f9f2bb..aa36f95 100644
--- a/icu4c/source/common/putil.cpp
+++ b/icu4c/source/common/putil.cpp
@@ -249,8 +249,8 @@
 }
 
 static UDate getUTCtime_fake() {
-    static UMutex *fakeClockMutex = STATIC_NEW(UMutex);
-    umtx_lock(fakeClockMutex);
+    static UMutex fakeClockMutex;
+    umtx_lock(&fakeClockMutex);
     if(!fakeClock_set) {
         UDate real = getUTCtime_real();
         const char *fake_start = getenv("U_FAKETIME_START");
@@ -267,7 +267,7 @@
         }
         fakeClock_set = TRUE;
     }
-    umtx_unlock(fakeClockMutex);
+    umtx_unlock(&fakeClockMutex);
 
     return getUTCtime_real() + fakeClock_dt;
 }
diff --git a/icu4c/source/common/resbund.cpp b/icu4c/source/common/resbund.cpp
index 4d4909c..7c5063b 100644
--- a/icu4c/source/common/resbund.cpp
+++ b/icu4c/source/common/resbund.cpp
@@ -378,8 +378,8 @@
 }
 
 const Locale &ResourceBundle::getLocale(void) const {
-    static UMutex *gLocaleLock = STATIC_NEW(UMutex);
-    Mutex lock(gLocaleLock);
+    static UMutex gLocaleLock;
+    Mutex lock(&gLocaleLock);
     if (fLocale != NULL) {
         return *fLocale;
     }
diff --git a/icu4c/source/common/serv.cpp b/icu4c/source/common/serv.cpp
index b92e4e4..ce545b9 100644
--- a/icu4c/source/common/serv.cpp
+++ b/icu4c/source/common/serv.cpp
@@ -333,10 +333,7 @@
 ******************************************************************
 */
 
-static UMutex *lock() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
+static UMutex lock;
 
 ICUService::ICUService()
 : name()
@@ -361,7 +358,7 @@
 ICUService::~ICUService()
 {
     {
-        Mutex mutex(lock());
+        Mutex mutex(&lock);
         clearCaches();
         delete factories;
         factories = NULL;
@@ -452,7 +449,7 @@
         // if factory is not null, we're calling from within the mutex,
         // and since some unix machines don't have reentrant mutexes we
         // need to make sure not to try to lock it again.
-        XMutex mutex(lock(), factory != NULL);
+        XMutex mutex(&lock, factory != NULL);
 
         if (serviceCache == NULL) {
             ncthis->serviceCache = new Hashtable(status);
@@ -618,7 +615,7 @@
     }
 
     {
-        Mutex mutex(lock());
+        Mutex mutex(&lock);
         const Hashtable* map = getVisibleIDMap(status);
         if (map != NULL) {
             ICUServiceKey* fallbackKey = createKey(matchID, status);
@@ -695,7 +692,7 @@
 {
     {
         UErrorCode status = U_ZERO_ERROR;
-        Mutex mutex(lock());
+        Mutex mutex(&lock);
         const Hashtable* map = getVisibleIDMap(status);
         if (map != NULL) {
             ICUServiceFactory* f = (ICUServiceFactory*)map->get(id);
@@ -747,7 +744,7 @@
     result.setDeleter(userv_deleteStringPair);
     if (U_SUCCESS(status)) {
         ICUService* ncthis = (ICUService*)this; // cast away semantic const
-        Mutex mutex(lock());
+        Mutex mutex(&lock);
 
         if (dnCache != NULL && dnCache->locale != locale) {
             delete dnCache;
@@ -852,7 +849,7 @@
 ICUService::registerFactory(ICUServiceFactory* factoryToAdopt, UErrorCode& status) 
 {
     if (U_SUCCESS(status) && factoryToAdopt != NULL) {
-        Mutex mutex(lock());
+        Mutex mutex(&lock);
 
         if (factories == NULL) {
             factories = new UVector(deleteUObject, NULL, status);
@@ -883,7 +880,7 @@
     ICUServiceFactory *factory = (ICUServiceFactory*)rkey;
     UBool result = FALSE;
     if (factory != NULL && factories != NULL) {
-        Mutex mutex(lock());
+        Mutex mutex(&lock);
 
         if (factories->removeElement(factory)) {
             clearCaches();
@@ -903,7 +900,7 @@
 ICUService::reset() 
 {
     {
-        Mutex mutex(lock());
+        Mutex mutex(&lock);
         reInitializeFactories();
         clearCaches();
     }
diff --git a/icu4c/source/common/servls.cpp b/icu4c/source/common/servls.cpp
index 1af6b4a..81dc4f7 100644
--- a/icu4c/source/common/servls.cpp
+++ b/icu4c/source/common/servls.cpp
@@ -263,9 +263,9 @@
 {
     const Locale&     loc    = Locale::getDefault();
     ICULocaleService* ncThis = (ICULocaleService*)this;
-    static UMutex *llock = STATIC_NEW(UMutex);
+    static UMutex llock;
     {
-        Mutex mutex(llock);
+        Mutex mutex(&llock);
         if (loc != fallbackLocale) {
             ncThis->fallbackLocale = loc;
             LocaleUtility::initNameFromLocale(loc, ncThis->fallbackLocaleName);
diff --git a/icu4c/source/common/servnotf.cpp b/icu4c/source/common/servnotf.cpp
index e7a7ca5..f577795 100644
--- a/icu4c/source/common/servnotf.cpp
+++ b/icu4c/source/common/servnotf.cpp
@@ -21,10 +21,7 @@
 EventListener::~EventListener() {}
 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(EventListener)
 
-static UMutex *notifyLock() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
+static UMutex notifyLock;
 
 ICUNotifier::ICUNotifier(void) 
 : listeners(NULL) 
@@ -33,7 +30,7 @@
 
 ICUNotifier::~ICUNotifier(void) {
     {
-        Mutex lmx(notifyLock());
+        Mutex lmx(&notifyLock);
         delete listeners;
         listeners = NULL;
     }
@@ -50,7 +47,7 @@
         }
 
         if (acceptsListener(*l)) {
-            Mutex lmx(notifyLock());
+            Mutex lmx(&notifyLock);
             if (listeners == NULL) {
                 listeners = new UVector(5, status);
             } else {
@@ -83,7 +80,7 @@
         }
 
         {
-            Mutex lmx(notifyLock());
+            Mutex lmx(&notifyLock);
             if (listeners != NULL) {
                 // identity equality check
                 for (int i = 0, e = listeners->size(); i < e; ++i) {
@@ -106,7 +103,7 @@
 ICUNotifier::notifyChanged(void) 
 {
     if (listeners != NULL) {
-        Mutex lmx(notifyLock());
+        Mutex lmx(&notifyLock);
         if (listeners != NULL) {
             for (int i = 0, e = listeners->size(); i < e; ++i) {
                 EventListener* el = (EventListener*)listeners->elementAt(i);
diff --git a/icu4c/source/common/ucln_cmn.cpp b/icu4c/source/common/ucln_cmn.cpp
index bfbf53a..f3e07c6 100644
--- a/icu4c/source/common/ucln_cmn.cpp
+++ b/icu4c/source/common/ucln_cmn.cpp
@@ -65,9 +65,20 @@
 ucln_common_registerCleanup(ECleanupCommonType type,
                             cleanupFunc *func)
 {
+    // Thread safety messiness: From ticket 10295, calls to registerCleanup() may occur
+    // concurrently. Although such cases should be storing the same value, they raise errors
+    // from the thread sanity checker. Doing the store within a mutex avoids those.
+    // BUT that can trigger a recursive entry into std::call_once() in umutex.cpp when this code,
+    // running from the call_once function, tries to grab the ICU global mutex, which
+    // re-enters the mutex init path. So, work-around by special casing UCLN_COMMON_MUTEX, not
+    // using the ICU global mutex for it.
+    //
+    // No other point in ICU uses std::call_once().
+
     U_ASSERT(UCLN_COMMON_START < type && type < UCLN_COMMON_COUNT);
-    if (UCLN_COMMON_START < type && type < UCLN_COMMON_COUNT)
-    {
+    if (type == UCLN_COMMON_MUTEX) {
+        gCommonCleanupFunctions[type] = func;
+    } else if (UCLN_COMMON_START < type && type < UCLN_COMMON_COUNT)  {
         icu::Mutex m;     // See ticket 10295 for discussion.
         gCommonCleanupFunctions[type] = func;
     }
diff --git a/icu4c/source/common/ucln_cmn.h b/icu4c/source/common/ucln_cmn.h
index 0ca911b..d281810 100644
--- a/icu4c/source/common/ucln_cmn.h
+++ b/icu4c/source/common/ucln_cmn.h
@@ -22,8 +22,6 @@
 
 /* These are the cleanup functions for various APIs. */
 /* @return true if cleanup complete successfully.*/
-U_CFUNC UBool umtx_cleanup(void);
-
 U_CFUNC UBool utrace_cleanup(void);
 
 U_CFUNC UBool ucln_lib_cleanup(void);
@@ -62,6 +60,7 @@
     */
     UCLN_COMMON_UNIFIED_CACHE,
     UCLN_COMMON_URES,
+    UCLN_COMMON_MUTEX,    // Mutexes should be the last to be cleaned up.
     UCLN_COMMON_COUNT /* This must be last */
 } ECleanupCommonType;
 
diff --git a/icu4c/source/common/ucnv_bld.cpp b/icu4c/source/common/ucnv_bld.cpp
index 42ddbd3..56fc3d6 100644
--- a/icu4c/source/common/ucnv_bld.cpp
+++ b/icu4c/source/common/ucnv_bld.cpp
@@ -194,10 +194,7 @@
 
 /*initializes some global variables */
 static UHashtable *SHARED_DATA_HASHTABLE = NULL;
-static icu::UMutex *cnvCacheMutex() {                 /* Mutex for synchronizing cnv cache access. */
-    static icu::UMutex *m = STATIC_NEW(icu::UMutex);
-    return m;
-}
+static icu::UMutex cnvCacheMutex;
 /*  Note:  the global mutex is used for      */
 /*         reference count updates.          */
 
@@ -602,9 +599,9 @@
 ucnv_unloadSharedDataIfReady(UConverterSharedData *sharedData)
 {
     if(sharedData != NULL && sharedData->isReferenceCounted) {
-        umtx_lock(cnvCacheMutex());
+        umtx_lock(&cnvCacheMutex);
         ucnv_unload(sharedData);
-        umtx_unlock(cnvCacheMutex());
+        umtx_unlock(&cnvCacheMutex);
     }
 }
 
@@ -612,9 +609,9 @@
 ucnv_incrementRefCount(UConverterSharedData *sharedData)
 {
     if(sharedData != NULL && sharedData->isReferenceCounted) {
-        umtx_lock(cnvCacheMutex());
+        umtx_lock(&cnvCacheMutex);
         sharedData->referenceCounter++;
-        umtx_unlock(cnvCacheMutex());
+        umtx_unlock(&cnvCacheMutex);
     }
 }
 
@@ -815,9 +812,9 @@
         pArgs->nestedLoads=1;
         pArgs->pkg=NULL;
 
-        umtx_lock(cnvCacheMutex());
+        umtx_lock(&cnvCacheMutex);
         mySharedConverterData = ucnv_load(pArgs, err);
-        umtx_unlock(cnvCacheMutex());
+        umtx_unlock(&cnvCacheMutex);
         if (U_FAILURE (*err) || (mySharedConverterData == NULL))
         {
             return NULL;
@@ -1064,7 +1061,7 @@
     *                   because the sequence of looking up in the cache + incrementing
     *                   is protected by cnvCacheMutex.
     */
-    umtx_lock(cnvCacheMutex());
+    umtx_lock(&cnvCacheMutex);
     /*
      * double loop: A delta/extension-only converter has a pointer to its base table's
      * shared data; the first iteration of the outer loop may see the delta converter
@@ -1093,7 +1090,7 @@
             }
         }
     } while(++i == 1 && remaining > 0);
-    umtx_unlock(cnvCacheMutex());
+    umtx_unlock(&cnvCacheMutex);
 
     UTRACE_DATA1(UTRACE_INFO, "ucnv_flushCache() exits with %d converters remaining", remaining);
 
@@ -1199,7 +1196,7 @@
     }
     algorithmicSharedData = getAlgorithmicTypeFromName(stackArgs.name);
 
-    umtx_lock(cnvCacheMutex());
+    umtx_lock(&cnvCacheMutex);
 
     gDefaultAlgorithmicSharedData = algorithmicSharedData;
     gDefaultConverterContainsOption = containsOption;
@@ -1215,7 +1212,7 @@
 
     ucnv_enableCleanup();
 
-    umtx_unlock(cnvCacheMutex());
+    umtx_unlock(&cnvCacheMutex);
 }
 #endif
 
@@ -1240,7 +1237,7 @@
     but ucnv_setDefaultName is not thread safe.
     */
     {
-        icu::Mutex lock(cnvCacheMutex());
+        icu::Mutex lock(&cnvCacheMutex);
         name = gDefaultConverterName;
     }
     if(name==NULL) {
diff --git a/icu4c/source/common/ucurr.cpp b/icu4c/source/common/ucurr.cpp
index 105b11d..8117645 100644
--- a/icu4c/source/common/ucurr.cpp
+++ b/icu4c/source/common/ucurr.cpp
@@ -365,10 +365,7 @@
 #if !UCONFIG_NO_SERVICE
 struct CReg;
 
-static UMutex *gCRegLock() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
+static UMutex gCRegLock;
 static CReg* gCRegHead = 0;
 
 struct CReg : public icu::UMemory {
@@ -394,14 +391,14 @@
         if (status && U_SUCCESS(*status) && _iso && _id) {
             CReg* n = new CReg(_iso, _id);
             if (n) {
-                umtx_lock(gCRegLock());
+                umtx_lock(&gCRegLock);
                 if (!gCRegHead) {
                     /* register for the first time */
                     ucln_common_registerCleanup(UCLN_COMMON_CURRENCY, currency_cleanup);
                 }
                 n->next = gCRegHead;
                 gCRegHead = n;
-                umtx_unlock(gCRegLock());
+                umtx_unlock(&gCRegLock);
                 return n;
             }
             *status = U_MEMORY_ALLOCATION_ERROR;
@@ -411,7 +408,7 @@
 
     static UBool unreg(UCurrRegistryKey key) {
         UBool found = FALSE;
-        umtx_lock(gCRegLock());
+        umtx_lock(&gCRegLock);
 
         CReg** p = &gCRegHead;
         while (*p) {
@@ -424,13 +421,13 @@
             p = &((*p)->next);
         }
 
-        umtx_unlock(gCRegLock());
+        umtx_unlock(&gCRegLock);
         return found;
     }
 
     static const UChar* get(const char* id) {
         const UChar* result = NULL;
-        umtx_lock(gCRegLock());
+        umtx_lock(&gCRegLock);
         CReg* p = gCRegHead;
 
         /* register cleanup of the mutex */
@@ -442,7 +439,7 @@
             }
             p = p->next;
         }
-        umtx_unlock(gCRegLock());
+        umtx_unlock(&gCRegLock);
         return result;
     }
 
@@ -1356,10 +1353,7 @@
 // It is a simple round-robin replacement strategy.
 static int8_t currentCacheEntryIndex = 0;
 
-static UMutex *gCurrencyCacheMutex() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
+static UMutex gCurrencyCacheMutex;
 
 // Cache deletion
 static void
@@ -1408,7 +1402,7 @@
     CurrencyNameStruct* currencySymbols = NULL;
     CurrencyNameCacheEntry* cacheEntry = NULL;
 
-    umtx_lock(gCurrencyCacheMutex());
+    umtx_lock(&gCurrencyCacheMutex);
     // in order to handle racing correctly,
     // not putting 'search' in a separate function.
     int8_t found = -1;
@@ -1423,13 +1417,13 @@
         cacheEntry = currCache[found];
         ++(cacheEntry->refCount);
     }
-    umtx_unlock(gCurrencyCacheMutex());
+    umtx_unlock(&gCurrencyCacheMutex);
     if (found == -1) {
         collectCurrencyNames(locale, &currencyNames, &total_currency_name_count, &currencySymbols, &total_currency_symbol_count, ec);
         if (U_FAILURE(ec)) {
             return NULL;
         }
-        umtx_lock(gCurrencyCacheMutex());
+        umtx_lock(&gCurrencyCacheMutex);
         // check again.
         for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
             if (currCache[i]!= NULL &&
@@ -1468,19 +1462,19 @@
             cacheEntry = currCache[found];
             ++(cacheEntry->refCount);
         }
-        umtx_unlock(gCurrencyCacheMutex());
+        umtx_unlock(&gCurrencyCacheMutex);
     }
 
     return cacheEntry;
 }
 
 static void releaseCacheEntry(CurrencyNameCacheEntry* cacheEntry) {
-    umtx_lock(gCurrencyCacheMutex());
+    umtx_lock(&gCurrencyCacheMutex);
     --(cacheEntry->refCount);
     if (cacheEntry->refCount == 0) {  // remove
         deleteCacheEntry(cacheEntry);
     }
-    umtx_unlock(gCurrencyCacheMutex());
+    umtx_unlock(&gCurrencyCacheMutex);
 }
 
 U_CAPI void
diff --git a/icu4c/source/common/udata.cpp b/icu4c/source/common/udata.cpp
index 853a32f..bf7025a 100644
--- a/icu4c/source/common/udata.cpp
+++ b/icu4c/source/common/udata.cpp
@@ -831,8 +831,8 @@
      * Use a specific mutex to avoid nested locks of the global mutex.
      */
 #if MAP_IMPLEMENTATION==MAP_STDIO
-    static UMutex *extendICUDataMutex = STATIC_NEW(UMutex);
-    umtx_lock(extendICUDataMutex);
+    static UMutex extendICUDataMutex;
+    umtx_lock(&extendICUDataMutex);
 #endif
     if(!umtx_loadAcquire(gHaveTriedToLoadCommonData)) {
         /* See if we can explicitly open a .dat file for the ICUData. */
@@ -868,7 +868,7 @@
                                                           /* Also handles a race through here before gHaveTriedToLoadCommonData is set. */
 
 #if MAP_IMPLEMENTATION==MAP_STDIO
-    umtx_unlock(extendICUDataMutex);
+    umtx_unlock(&extendICUDataMutex);
 #endif
     return didUpdate;               /* Return true if ICUData pointer was updated.   */
                                     /*   (Could potentially have been done by another thread racing */
diff --git a/icu4c/source/common/umutex.cpp b/icu4c/source/common/umutex.cpp
index 774071e..d31753f 100644
--- a/icu4c/source/common/umutex.cpp
+++ b/icu4c/source/common/umutex.cpp
@@ -24,6 +24,7 @@
 
 #include "unicode/utypes.h"
 #include "uassert.h"
+#include "ucln_cmn.h"
 #include "cmemory.h"
 
 U_NAMESPACE_BEGIN
@@ -35,24 +36,90 @@
 #error U_USER_MUTEX_CPP not supported
 #endif
 
+// Check that UMutex is trivially constructable & destructable, which ensures that
+// static instances are not running static constructors or destructors.
+#if (defined(__GNUG__) && __GNUC__ < 5) || (defined(__clang__) && __clang_major__ < 5)
+// skip
+#else
+static_assert(std::is_trivially_constructible<UMutex>::value, "UMutex not trivially constructable.");
+static_assert(std::is_trivially_destructible<UMutex>::value, "UMutex not trivially destructable.");
+#endif
+
+
 /*************************************************************************************************
  *
  *  ICU Mutex wrappers.
  *
  *************************************************************************************************/
 
+namespace {
+std::mutex *initMutex;
+std::condition_variable *initCondition;
+
 // The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
-static UMutex *globalMutex() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
+UMutex globalMutex;
+
+std::once_flag initFlag;
+std::once_flag *pInitFlag = &initFlag;
+
+}  // Anonymous namespace
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV umtx_cleanup() {
+    initMutex->~mutex();
+    initCondition->~condition_variable();
+    UMutex::cleanup();
+
+    // Reset the once_flag, by destructing it and creating a fresh one in its place.
+    // Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once().
+    pInitFlag->~once_flag();
+    pInitFlag = new(&initFlag) std::once_flag();
+    return true;
 }
 
+static void U_CALLCONV umtx_init() {
+    initMutex = STATIC_NEW(std::mutex);
+    initCondition = STATIC_NEW(std::condition_variable);
+    ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup);
+}
+U_CDECL_END
+
+
+std::mutex *UMutex::getMutex() {
+    std::mutex *retPtr = fMutex.load(std::memory_order_acquire);
+    if (retPtr == nullptr) {
+        std::call_once(*pInitFlag, umtx_init);
+        std::lock_guard<std::mutex> guard(*initMutex);
+        if (fMutex.load() == nullptr) {
+            fMutex = new(fStorage) std::mutex();
+            retPtr = fMutex;
+            fListLink = gListHead;
+            gListHead = this;
+        }
+    }
+    return retPtr;
+}
+
+UMutex *UMutex::gListHead = nullptr;
+
+void UMutex::cleanup() {
+    UMutex *next = nullptr;
+    for (UMutex *m = gListHead; m != nullptr; m = next) {
+        (*m->fMutex).~mutex();
+        m->fMutex = nullptr;
+        next = m->fListLink;
+        m->fListLink = nullptr;
+    }
+    gListHead = nullptr;
+}
+
+
 U_CAPI void  U_EXPORT2
 umtx_lock(UMutex *mutex) {
     if (mutex == nullptr) {
-        mutex = globalMutex();
+        mutex = &globalMutex;
     }
-    mutex->fMutex.lock();
+    mutex->lock();
 }
 
 
@@ -60,9 +127,9 @@
 umtx_unlock(UMutex* mutex)
 {
     if (mutex == nullptr) {
-        mutex = globalMutex();
+        mutex = &globalMutex;
     }
-    mutex->fMutex.unlock();
+    mutex->unlock();
 }
 
 
@@ -72,17 +139,6 @@
  *
  *************************************************************************************************/
 
-static std::mutex &initMutex() {
-    static std::mutex *m = STATIC_NEW(std::mutex);
-    return *m;
-}
-
-static std::condition_variable &initCondition() {
-    static std::condition_variable *cv = STATIC_NEW(std::condition_variable);
-    return *cv;
-}
-
-
 // This function is called when a test of a UInitOnce::fState reveals that
 //   initialization has not completed, that we either need to call the init
 //   function on this thread, or wait for some other thread to complete.
@@ -93,8 +149,8 @@
 //
 U_COMMON_API UBool U_EXPORT2
 umtx_initImplPreInit(UInitOnce &uio) {
-    std::unique_lock<std::mutex> lock(initMutex());
-
+    std::call_once(*pInitFlag, umtx_init);
+    std::unique_lock<std::mutex> lock(*initMutex);
     if (umtx_loadAcquire(uio.fState) == 0) {
         umtx_storeRelease(uio.fState, 1);
         return true;      // Caller will next call the init function.
@@ -102,7 +158,7 @@
         while (umtx_loadAcquire(uio.fState) == 1) {
             // Another thread is currently running the initialization.
             // Wait until it completes.
-            initCondition().wait(lock);
+            initCondition->wait(lock);
         }
         U_ASSERT(uio.fState == 2);
         return false;
@@ -119,10 +175,10 @@
 U_COMMON_API void U_EXPORT2
 umtx_initImplPostInit(UInitOnce &uio) {
     {
-        std::unique_lock<std::mutex> lock(initMutex());
+        std::unique_lock<std::mutex> lock(*initMutex);
         umtx_storeRelease(uio.fState, 2);
     }
-    initCondition().notify_all();
+    initCondition->notify_all();
 }
 
 U_NAMESPACE_END
diff --git a/icu4c/source/common/umutex.h b/icu4c/source/common/umutex.h
index 476fcef..d6164f9 100755
--- a/icu4c/source/common/umutex.h
+++ b/icu4c/source/common/umutex.h
@@ -23,6 +23,7 @@
 #include <atomic>
 #include <condition_variable>
 #include <mutex>
+#include <type_traits>
 
 #include "unicode/utypes.h"
 #include "unicode/uclean.h"
@@ -36,10 +37,11 @@
 #error U_USER_ATOMICS and U_USER_MUTEX_H are not supported
 #endif
 
-
 // Export an explicit template instantiation of std::atomic<int32_t>. 
 // When building DLLs for Windows this is required as it is used as a data member of the exported SharedObject class.
 // See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
+//
+// Similar story for std::atomic<std::mutex *>, and the exported UMutex class.
 #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN && !defined(U_IN_DOXYGEN)
 #if defined(__clang__) || defined(_MSC_VER)
   #if defined(__clang__)
@@ -48,12 +50,14 @@
     #pragma clang diagnostic ignored "-Winstantiation-after-specialization"
   #endif
 template struct U_COMMON_API std::atomic<int32_t>;
+template struct U_COMMON_API std::atomic<std::mutex *>;
   #if defined(__clang__)
     #pragma clang diagnostic pop
   #endif
 #elif defined(__GNUC__)
 // For GCC this class is already exported/visible, so no need for U_COMMON_API.
 template struct std::atomic<int32_t>;
+template struct std::atomic<std::mutex *>;
 #endif
 #endif
 
@@ -182,34 +186,66 @@
 
 
 /**
- * ICU Mutex wrappers.  Originally wrapped operating system mutexes, giving the rest of ICU a
- * platform independent set of mutex operations.  Now vestigial, wrapping std::mutex only.
- * For internal ICU use only.
+ * UMutex - ICU Mutex class.
  *
- * Caution: do not directly declare static or global instances of UMutex. Doing so can introduce
- * static initializers, which are disallowed in ICU library code. Instead, use the following
- * idiom, which avoids static init and also avoids ordering issues on destruction
- * (use after delete) by avoiding destruction altogether.
+ * This is the preferred Mutex class for use within ICU implementation code.
+ * It is a thin wrapper over C++ std::mutex, with these additions:
+ *    - Static instances are safe, not triggering static construction or destruction,
+ *      and the associated order of construction or destruction issues.
+ *    - Plumbed into u_cleanup() for destructing the underlying std::mutex,
+ *      which frees any OS level resources they may be holding.
  *
- *  UMutex *myMutex() {
- *      static UMutex *m = STATIC_NEW(UMutex);
- *      return m;
- *  }
- *  ...
+ * Limitations:
+ *    - Static or global instances only. Cannot be heap allocated. Cannot appear as a
+ *      member of another class.
+ *    - No condition variables or other advanced features. If needed, you will need to use
+ *      std::mutex and std::condition_variable directly. For an example, see unifiedcache.cpp
  *
- *  Mutex lock(myMutex());   // hold myMutex until the variable "lock" goes out of scope.
+ * Typical Usage:
+ *    static UMutex myMutex;
+ *
+ *    {
+ *       Mutex lock(myMutex);
+ *       ...    // Do stuff that is protected by myMutex;
+ *    }         // myMutex is released when lock goes out of scope.
  */
 
-struct UMutex : public icu::UMemory {
+class U_COMMON_API UMutex {
+public:
     UMutex() = default;
     ~UMutex() = default;
+
     UMutex(const UMutex &other) = delete;
     UMutex &operator =(const UMutex &other) = delete;
+    void *operator new(size_t) = delete;
 
-    std::mutex   fMutex = {};    // Note: struct - pubic members - because most access is from
-    //                           //       plain C style functions (umtx_lock(), etc.)
+    // requirements for C++ BasicLockable, allows UMutex to work with std::lock_guard
+    void lock() {
+        std::mutex *m = fMutex.load(std::memory_order_acquire);
+        if (m == nullptr) { m = getMutex(); }
+        m->lock();
+    }
+    void unlock() { fMutex.load(std::memory_order_relaxed)->unlock(); };
+
+    static void cleanup();
+
+private:
+    alignas(std::mutex) char fStorage[sizeof(std::mutex)];
+    std::atomic<std::mutex *> fMutex;
+
+    /** All initialized UMutexes are kept in a linked list, so that they can be found,
+     * and the underlying std::mutex destructed, by u_cleanup().
+     */
+    UMutex *fListLink;
+    static UMutex *gListHead;
+
+    /** Out-of-line function to lazily initialize a UMutex on first use.
+     * Initial fast check is inline, in lock().
+     */
+    std::mutex *getMutex();
 };
 
+
 /* Lock a mutex.
  * @param mutex The given mutex to be locked.  Pass NULL to specify
  *              the global ICU mutex.  Recursive locks are an error
diff --git a/icu4c/source/common/unifiedcache.cpp b/icu4c/source/common/unifiedcache.cpp
index ed7cf57..f2dd916 100644
--- a/icu4c/source/common/unifiedcache.cpp
+++ b/icu4c/source/common/unifiedcache.cpp
@@ -20,14 +20,8 @@
 #include "ucln_cmn.h"
 
 static icu::UnifiedCache *gCache = NULL;
-static std::mutex &gCacheMutex() {
-    static std::mutex *m = STATIC_NEW(std::mutex);
-    return *m;
-}
-static std::condition_variable &gInProgressValueAddedCond() {
-    static std::condition_variable *cv = STATIC_NEW(std::condition_variable);
-    return *cv;
-}
+static std::mutex *gCacheMutex = nullptr;
+static std::condition_variable *gInProgressValueAddedCond;
 static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER;
 
 static const int32_t MAX_EVICT_ITERATIONS = 10;
@@ -38,10 +32,12 @@
 U_CDECL_BEGIN
 static UBool U_CALLCONV unifiedcache_cleanup() {
     gCacheInitOnce.reset();
-    if (gCache) {
-        delete gCache;
-        gCache = NULL;
-    }
+    delete gCache;
+    gCache = nullptr;
+    gCacheMutex->~mutex();
+    gCacheMutex = nullptr;
+    gInProgressValueAddedCond->~condition_variable();
+    gInProgressValueAddedCond = nullptr;
     return TRUE;
 }
 U_CDECL_END
@@ -76,6 +72,8 @@
     ucln_common_registerCleanup(
             UCLN_COMMON_UNIFIED_CACHE, unifiedcache_cleanup);
 
+    gCacheMutex = STATIC_NEW(std::mutex);
+    gInProgressValueAddedCond = STATIC_NEW(std::condition_variable);
     gCache = new UnifiedCache(status);
     if (gCache == NULL) {
         status = U_MEMORY_ALLOCATION_ERROR;
@@ -137,28 +135,28 @@
         status = U_ILLEGAL_ARGUMENT_ERROR;
         return;
     }
-    std::lock_guard<std::mutex> lock(gCacheMutex());
+    std::lock_guard<std::mutex> lock(*gCacheMutex);
     fMaxUnused = count;
     fMaxPercentageOfInUse = percentageOfInUseItems;
 }
 
 int32_t UnifiedCache::unusedCount() const {
-    std::lock_guard<std::mutex> lock(gCacheMutex());
+    std::lock_guard<std::mutex> lock(*gCacheMutex);
     return uhash_count(fHashtable) - fNumValuesInUse;
 }
 
 int64_t UnifiedCache::autoEvictedCount() const {
-    std::lock_guard<std::mutex> lock(gCacheMutex());
+    std::lock_guard<std::mutex> lock(*gCacheMutex);
     return fAutoEvictedCount;
 }
 
 int32_t UnifiedCache::keyCount() const {
-    std::lock_guard<std::mutex> lock(gCacheMutex());
+    std::lock_guard<std::mutex> lock(*gCacheMutex);
     return uhash_count(fHashtable);
 }
 
 void UnifiedCache::flush() const {
-    std::lock_guard<std::mutex> lock(gCacheMutex());
+    std::lock_guard<std::mutex> lock(*gCacheMutex);
 
     // Use a loop in case cache items that are flushed held hard references to
     // other cache items making those additional cache items eligible for
@@ -167,7 +165,7 @@
 }
 
 void UnifiedCache::handleUnreferencedObject() const {
-    std::lock_guard<std::mutex> lock(gCacheMutex());
+    std::lock_guard<std::mutex> lock(*gCacheMutex);
     --fNumValuesInUse;
     _runEvictionSlice();
 }
@@ -186,7 +184,7 @@
 }
 
 void UnifiedCache::dumpContents() const {
-    std::lock_guard<std::mutex> lock(gCacheMutex());
+    std::lock_guard<std::mutex> lock(*gCacheMutex);
     _dumpContents();
 }
 
@@ -226,7 +224,7 @@
         // Now all that should be left in the cache are entries that refer to
         // each other and entries with hard references from outside the cache.
         // Nothing we can do about these so proceed to wipe out the cache.
-        std::lock_guard<std::mutex> lock(gCacheMutex());
+        std::lock_guard<std::mutex> lock(*gCacheMutex);
         _flush(TRUE);
     }
     uhash_close(fHashtable);
@@ -327,7 +325,7 @@
         const CacheKeyBase &key,
         const SharedObject *&value,
         UErrorCode &status) const {
-    std::lock_guard<std::mutex> lock(gCacheMutex());
+    std::lock_guard<std::mutex> lock(*gCacheMutex);
     const UHashElement *element = uhash_find(fHashtable, &key);
     if (element != NULL && !_inProgress(element)) {
         _fetch(element, value, status);
@@ -352,14 +350,14 @@
         UErrorCode &status) const {
     U_ASSERT(value == NULL);
     U_ASSERT(status == U_ZERO_ERROR);
-    std::unique_lock<std::mutex> lock(gCacheMutex());
+    std::unique_lock<std::mutex> lock(*gCacheMutex);
     const UHashElement *element = uhash_find(fHashtable, &key);
 
     // If the hash table contains an inProgress placeholder entry for this key,
     // this means that another thread is currently constructing the value object.
     // Loop, waiting for that construction to complete.
      while (element != NULL && _inProgress(element)) {
-         gInProgressValueAddedCond().wait(lock);
+         gInProgressValueAddedCond->wait(lock);
          element = uhash_find(fHashtable, &key);
     }
 
@@ -432,7 +430,7 @@
 
     // Tell waiting threads that we replace in-progress status with
     // an error.
-    gInProgressValueAddedCond().notify_all();
+    gInProgressValueAddedCond->notify_all();
 }
 
 void UnifiedCache::_fetch(
diff --git a/icu4c/source/common/uresbund.cpp b/icu4c/source/common/uresbund.cpp
index 7f99211..57d133e 100644
--- a/icu4c/source/common/uresbund.cpp
+++ b/icu4c/source/common/uresbund.cpp
@@ -31,6 +31,7 @@
 #include "ucln_cmn.h"
 #include "cmemory.h"
 #include "cstring.h"
+#include "mutex.h"
 #include "uhash.h"
 #include "unicode/uenum.h"
 #include "uenumimp.h"
@@ -49,10 +50,7 @@
 static UHashtable *cache = NULL;
 static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER;
 
-static UMutex *resbMutex() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
+static UMutex resbMutex;
 
 /* INTERNAL: hashes an entry  */
 static int32_t U_CALLCONV hashEntry(const UHashTok parm) {
@@ -96,13 +94,12 @@
  *  Internal function
  */
 static void entryIncrease(UResourceDataEntry *entry) {
-    umtx_lock(resbMutex());
+    Mutex lock(&resbMutex);
     entry->fCountExisting++;
     while(entry->fParent != NULL) {
       entry = entry->fParent;
       entry->fCountExisting++;
     }
-    umtx_unlock(resbMutex());
 }
 
 /**
@@ -184,9 +181,8 @@
     /*if shared data hasn't even been lazy evaluated yet
     * return 0
     */
-    umtx_lock(resbMutex());
+    Mutex lock(&resbMutex);
     if (cache == NULL) {
-        umtx_unlock(resbMutex());
         return 0;
     }
 
@@ -218,7 +214,6 @@
          * got decremented by free_entry().
          */
     } while(deletedMore);
-    umtx_unlock(resbMutex());
 
     return rbDeletedNum;
 }
@@ -232,9 +227,8 @@
   const UHashElement *e;
   UResourceDataEntry *resB;
   
-    umtx_lock(resbMutex());
+    Mutex lock(&resbMutex);
     if (cache == NULL) {
-      umtx_unlock(resbMutex());
       fprintf(stderr,"%s:%d: RB Cache is NULL.\n", __FILE__, __LINE__);
       return FALSE;
     }
@@ -253,9 +247,6 @@
     }
     
     fprintf(stderr,"%s:%d: RB Cache still contains %d items.\n", __FILE__, __LINE__, uhash_count(cache));
-
-    umtx_unlock(resbMutex());
-    
     return cacheNotEmpty;
 }
 
@@ -666,107 +657,105 @@
         }
     }
  
-    umtx_lock(resbMutex());
-    { /* umtx_lock */
-        /* We're going to skip all the locales that do not have any data */
-        r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
+    Mutex lock(&resbMutex);    // Lock resbMutex until the end of this function.
 
+    /* We're going to skip all the locales that do not have any data */
+    r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
+
+    // If we failed due to out-of-memory, report the failure and exit early.
+    if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
+        *status = intStatus;
+        goto finish;
+    }
+
+    if(r != NULL) { /* if there is one real locale, we can look for parents. */
+        t1 = r;
+        hasRealData = TRUE;
+        if ( usingUSRData ) {  /* This code inserts user override data into the inheritance chain */
+            UErrorCode usrStatus = U_ZERO_ERROR;
+            UResourceDataEntry *u1 = init_entry(t1->fName, usrDataPath, &usrStatus);
+            // If we failed due to out-of-memory, report the failure and exit early.
+            if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
+                *status = intStatus;
+                goto finish;
+            }
+            if ( u1 != NULL ) {
+                if(u1->fBogus == U_ZERO_ERROR) {
+                    u1->fParent = t1;
+                    r = u1;
+                } else {
+                    /* the USR override data wasn't found, set it to be deleted */
+                    u1->fCountExisting = 0;
+                }
+            }
+        }
+        if (hasChopped && !isRoot) {
+            if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) {
+                goto finish;
+            }
+        }
+    }
+
+    /* we could have reached this point without having any real data */
+    /* if that is the case, we need to chain in the default locale   */
+    if(r==NULL && openType == URES_OPEN_LOCALE_DEFAULT_ROOT && !isDefault && !isRoot) {
+        /* insert default locale */
+        uprv_strcpy(name, uloc_getDefault());
+        r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
         // If we failed due to out-of-memory, report the failure and exit early.
         if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
             *status = intStatus;
-            goto finishUnlock;
+            goto finish;
         }
-
-        if(r != NULL) { /* if there is one real locale, we can look for parents. */
+        intStatus = U_USING_DEFAULT_WARNING;
+        if(r != NULL) { /* the default locale exists */
             t1 = r;
             hasRealData = TRUE;
-            if ( usingUSRData ) {  /* This code inserts user override data into the inheritance chain */
-                UErrorCode usrStatus = U_ZERO_ERROR;
-                UResourceDataEntry *u1 = init_entry(t1->fName, usrDataPath, &usrStatus);
-                // If we failed due to out-of-memory, report the failure and exit early.
-                if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
-                    *status = intStatus;
-                    goto finishUnlock;
-                }
-                if ( u1 != NULL ) {
-                    if(u1->fBogus == U_ZERO_ERROR) {
-                        u1->fParent = t1;
-                        r = u1;
-                    } else {
-                        /* the USR override data wasn't found, set it to be deleted */
-                        u1->fCountExisting = 0;
-                    }
-                }
-            }
+            isDefault = TRUE;
+            // TODO: Why not if (usingUSRData) { ... } like in the non-default-locale code path?
             if (hasChopped && !isRoot) {
                 if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) {
-                    goto finishUnlock;
+                    goto finish;
                 }
             }
         }
+    }
 
-        /* we could have reached this point without having any real data */
-        /* if that is the case, we need to chain in the default locale   */
-        if(r==NULL && openType == URES_OPEN_LOCALE_DEFAULT_ROOT && !isDefault && !isRoot) {
-            /* insert default locale */
-            uprv_strcpy(name, uloc_getDefault());
-            r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
-            // If we failed due to out-of-memory, report the failure and exit early.
-            if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
-                *status = intStatus;
-                goto finishUnlock;
-            }
+    /* we could still have r == NULL at this point - maybe even default locale is not */
+    /* present */
+    if(r == NULL) {
+        uprv_strcpy(name, kRootLocaleName);
+        r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
+        // If we failed due to out-of-memory, report the failure and exit early.
+        if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
+            *status = intStatus;
+            goto finish;
+        }
+        if(r != NULL) {
+            t1 = r;
             intStatus = U_USING_DEFAULT_WARNING;
-            if(r != NULL) { /* the default locale exists */
-                t1 = r;
-                hasRealData = TRUE;
-                isDefault = TRUE;
-                // TODO: Why not if (usingUSRData) { ... } like in the non-default-locale code path?
-                if (hasChopped && !isRoot) {
-                    if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) {
-                        goto finishUnlock;
-                    }
-                }
-            } 
+            hasRealData = TRUE;
+        } else { /* we don't even have the root locale */
+            *status = U_MISSING_RESOURCE_ERROR;
+            goto finish;
         }
-
-        /* we could still have r == NULL at this point - maybe even default locale is not */
-        /* present */
-        if(r == NULL) {
-            uprv_strcpy(name, kRootLocaleName);
-            r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
-            // If we failed due to out-of-memory, report the failure and exit early.
-            if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
-                *status = intStatus;
-                goto finishUnlock;
-            }
-            if(r != NULL) {
-                t1 = r;
-                intStatus = U_USING_DEFAULT_WARNING;
-                hasRealData = TRUE;
-            } else { /* we don't even have the root locale */
-                *status = U_MISSING_RESOURCE_ERROR;
-                goto finishUnlock;
-            }
-        } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 &&
-                t1->fParent == NULL && !r->fData.noFallback) {
-            if (!insertRootBundle(t1, status)) {
-                goto finishUnlock;
-            }
-            if(!hasRealData) {
-                r->fBogus = U_USING_DEFAULT_WARNING;
-            }
+    } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 &&
+            t1->fParent == NULL && !r->fData.noFallback) {
+        if (!insertRootBundle(t1, status)) {
+            goto finish;
         }
-
-        // TODO: Does this ever loop?
-        while(r != NULL && !isRoot && t1->fParent != NULL) {
-            t1->fParent->fCountExisting++;
-            t1 = t1->fParent;
+        if(!hasRealData) {
+            r->fBogus = U_USING_DEFAULT_WARNING;
         }
-    } /* umtx_lock */
-finishUnlock:
-    umtx_unlock(resbMutex());
+    }
 
+    // TODO: Does this ever loop?
+    while(r != NULL && !isRoot && t1->fParent != NULL) {
+        t1->fParent->fCountExisting++;
+        t1 = t1->fParent;
+    }
+
+finish:
     if(U_SUCCESS(*status)) {
         if(intStatus != U_ZERO_ERROR) {
             *status = intStatus;  
@@ -790,7 +779,7 @@
         return NULL;
     }
 
-    umtx_lock(resbMutex());
+    Mutex lock(&resbMutex);
     // findFirstExisting() without fallbacks.
     UResourceDataEntry *r = init_entry(localeID, path, status);
     if(U_SUCCESS(*status)) {
@@ -828,7 +817,6 @@
             t1 = t1->fParent;
         }
     }
-    umtx_unlock(resbMutex());
     return r;
 }
 
@@ -871,9 +859,8 @@
  */
 
 static void entryClose(UResourceDataEntry *resB) {
-  umtx_lock(resbMutex());
+  Mutex lock(&resbMutex);
   entryCloseInt(resB);
-  umtx_unlock(resbMutex());
 }
 
 /*
diff --git a/icu4c/source/common/usprep.cpp b/icu4c/source/common/usprep.cpp
index 5d72cc7..8351a77 100644
--- a/icu4c/source/common/usprep.cpp
+++ b/icu4c/source/common/usprep.cpp
@@ -47,11 +47,7 @@
 static UHashtable *SHARED_DATA_HASHTABLE = NULL;
 static icu::UInitOnce gSharedDataInitOnce = U_INITONCE_INITIALIZER;
 
-static UMutex *usprepMutex() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
-
+static UMutex usprepMutex;
 /* format version of spp file */
 //static uint8_t formatVersion[4]={ 0, 0, 0, 0 };
 
@@ -151,9 +147,9 @@
      * if shared data hasn't even been lazy evaluated yet
      * return 0
      */
-    umtx_lock(usprepMutex());
+    umtx_lock(&usprepMutex);
     if (SHARED_DATA_HASHTABLE == NULL) {
-        umtx_unlock(usprepMutex());
+        umtx_unlock(&usprepMutex);
         return 0;
     }
 
@@ -184,7 +180,7 @@
         }
        
     }
-    umtx_unlock(usprepMutex());
+    umtx_unlock(&usprepMutex);
 
     return deletedNum;
 }
@@ -262,7 +258,7 @@
     }
 
     /* in the mutex block, set the data for this process */
-    umtx_lock(usprepMutex());
+    umtx_lock(&usprepMutex);
     if(profile->sprepData==NULL) {
         profile->sprepData=dataMemory;
         dataMemory=NULL;
@@ -271,7 +267,7 @@
     } else {
         p=(const int32_t *)udata_getMemory(profile->sprepData);
     }
-    umtx_unlock(usprepMutex());
+    umtx_unlock(&usprepMutex);
     /* initialize some variables */
     profile->mappingData=(uint16_t *)((uint8_t *)(p+_SPREP_INDEX_TOP)+profile->indexes[_SPREP_INDEX_TRIE_SIZE]);
     
@@ -328,12 +324,12 @@
     stackKey.path = (char*) path;
 
     /* fetch the data from the cache */
-    umtx_lock(usprepMutex());
+    umtx_lock(&usprepMutex);
     profile = (UStringPrepProfile*) (uhash_get(SHARED_DATA_HASHTABLE,&stackKey));
     if(profile != NULL) {
         profile->refCount++;
     }
-    umtx_unlock(usprepMutex());
+    umtx_unlock(&usprepMutex);
     
     if(profile == NULL) {
         /* else load the data and put the data in the cache */
@@ -365,7 +361,7 @@
             return NULL;
         }
 
-        umtx_lock(usprepMutex());
+        umtx_lock(&usprepMutex);
         // If another thread already inserted the same key/value, refcount and cleanup our thread data
         profile = (UStringPrepProfile*) (uhash_get(SHARED_DATA_HASHTABLE,&stackKey));
         if(profile != NULL) {
@@ -386,7 +382,7 @@
             profile->refCount = 1;
             uhash_put(SHARED_DATA_HASHTABLE, key.orphan(), profile, status);
         }
-        umtx_unlock(usprepMutex());
+        umtx_unlock(&usprepMutex);
     }
 
     return profile;
@@ -425,12 +421,12 @@
         return;
     }
 
-    umtx_lock(usprepMutex());
+    umtx_lock(&usprepMutex);
     /* decrement the ref count*/
     if(profile->refCount > 0){
         profile->refCount--;
     }
-    umtx_unlock(usprepMutex());
+    umtx_unlock(&usprepMutex);
     
 }
 
diff --git a/icu4c/source/i18n/astro.cpp b/icu4c/source/i18n/astro.cpp
index d2973d3..f17b6db 100644
--- a/icu4c/source/i18n/astro.cpp
+++ b/icu4c/source/i18n/astro.cpp
@@ -65,10 +65,7 @@
   return(uprv_isNaN(d));
 }
 
-static icu::UMutex *ccLock() {
-    static icu::UMutex *m = STATIC_NEW(icu::UMutex);
-    return m;
-}
+static icu::UMutex ccLock;
 
 U_CDECL_BEGIN
 static UBool calendar_astro_cleanup(void) {
@@ -1552,12 +1549,12 @@
     if(U_FAILURE(status)) {
         return 0;
     }
-    umtx_lock(ccLock());
+    umtx_lock(&ccLock);
 
     if(*cache == NULL) {
         createCache(cache, status);
         if(U_FAILURE(status)) {
-            umtx_unlock(ccLock());
+            umtx_unlock(&ccLock);
             return 0;
         }
     }
@@ -1565,7 +1562,7 @@
     res = uhash_igeti((*cache)->fTable, key);
     U_DEBUG_ASTRO_MSG(("%p: GET: [%d] == %d\n", (*cache)->fTable, key, res));
 
-    umtx_unlock(ccLock());
+    umtx_unlock(&ccLock);
     return res;
 }
 
@@ -1573,12 +1570,12 @@
     if(U_FAILURE(status)) {
         return;
     }
-    umtx_lock(ccLock());
+    umtx_lock(&ccLock);
 
     if(*cache == NULL) {
         createCache(cache, status);
         if(U_FAILURE(status)) {
-            umtx_unlock(ccLock());
+            umtx_unlock(&ccLock);
             return;
         }
     }
@@ -1586,7 +1583,7 @@
     uhash_iputi((*cache)->fTable, key, value, &status);
     U_DEBUG_ASTRO_MSG(("%p: PUT: [%d] := %d\n", (*cache)->fTable, key, value));
 
-    umtx_unlock(ccLock());
+    umtx_unlock(&ccLock);
 }
 
 CalendarCache::CalendarCache(int32_t size, UErrorCode &status) {
diff --git a/icu4c/source/i18n/chnsecal.cpp b/icu4c/source/i18n/chnsecal.cpp
index f6a687e..bd85db1 100644
--- a/icu4c/source/i18n/chnsecal.cpp
+++ b/icu4c/source/i18n/chnsecal.cpp
@@ -51,10 +51,7 @@
 
 
 // --- The cache --
-static icu::UMutex *astroLock() {  // Protects access to gChineseCalendarAstro.
-    static icu::UMutex *m = STATIC_NEW(icu::UMutex);
-    return m;
-}
+static icu::UMutex astroLock;
 static icu::CalendarAstronomer *gChineseCalendarAstro = NULL;
 
 // Lazy Creation & Access synchronized by class CalendarCache with a mutex.
@@ -538,14 +535,14 @@
         // PST 1298 with a final result of Dec 14 10:31:59 PST 1299.
         double ms = daysToMillis(Grego::fieldsToDay(gyear, UCAL_DECEMBER, 1));
 
-        umtx_lock(astroLock());
+        umtx_lock(&astroLock);
         if(gChineseCalendarAstro == NULL) {
             gChineseCalendarAstro = new CalendarAstronomer();
             ucln_i18n_registerCleanup(UCLN_I18N_CHINESE_CALENDAR, calendar_chinese_cleanup);
         }
         gChineseCalendarAstro->setTime(ms);
         UDate solarLong = gChineseCalendarAstro->getSunTime(CalendarAstronomer::WINTER_SOLSTICE(), TRUE);
-        umtx_unlock(astroLock());
+        umtx_unlock(&astroLock);
 
         // Winter solstice is 270 degrees solar longitude aka Dongzhi
         cacheValue = (int32_t)millisToDays(solarLong);
@@ -568,14 +565,14 @@
  */
 int32_t ChineseCalendar::newMoonNear(double days, UBool after) const {
     
-    umtx_lock(astroLock());
+    umtx_lock(&astroLock);
     if(gChineseCalendarAstro == NULL) {
         gChineseCalendarAstro = new CalendarAstronomer();
         ucln_i18n_registerCleanup(UCLN_I18N_CHINESE_CALENDAR, calendar_chinese_cleanup);
     }
     gChineseCalendarAstro->setTime(daysToMillis(days));
     UDate newMoon = gChineseCalendarAstro->getMoonTime(CalendarAstronomer::NEW_MOON(), after);
-    umtx_unlock(astroLock());
+    umtx_unlock(&astroLock);
     
     return (int32_t) millisToDays(newMoon);
 }
@@ -600,14 +597,14 @@
  */
 int32_t ChineseCalendar::majorSolarTerm(int32_t days) const {
     
-    umtx_lock(astroLock());
+    umtx_lock(&astroLock);
     if(gChineseCalendarAstro == NULL) {
         gChineseCalendarAstro = new CalendarAstronomer();
         ucln_i18n_registerCleanup(UCLN_I18N_CHINESE_CALENDAR, calendar_chinese_cleanup);
     }
     gChineseCalendarAstro->setTime(daysToMillis(days));
     UDate solarLongitude = gChineseCalendarAstro->getSunLongitude();
-    umtx_unlock(astroLock());
+    umtx_unlock(&astroLock);
 
     // Compute (floor(solarLongitude / (pi/6)) + 2) % 12
     int32_t term = ( ((int32_t)(6 * solarLongitude / CalendarAstronomer::PI)) + 2 ) % 12;
diff --git a/icu4c/source/i18n/dtfmtsym.cpp b/icu4c/source/i18n/dtfmtsym.cpp
index 93105e0..c86d9eb 100644
--- a/icu4c/source/i18n/dtfmtsym.cpp
+++ b/icu4c/source/i18n/dtfmtsym.cpp
@@ -1246,9 +1246,9 @@
 DateFormatSymbols::getZoneStrings(int32_t& rowCount, int32_t& columnCount) const
 {
     const UnicodeString **result = NULL;
-    static UMutex *LOCK = STATIC_NEW(UMutex);
+    static UMutex LOCK;
 
-    umtx_lock(LOCK);
+    umtx_lock(&LOCK);
     if (fZoneStrings == NULL) {
         if (fLocaleZoneStrings == NULL) {
             ((DateFormatSymbols*)this)->initZoneStringsArray();
@@ -1259,7 +1259,7 @@
     }
     rowCount = fZoneStringsRowCount;
     columnCount = fZoneStringsColCount;
-    umtx_unlock(LOCK);
+    umtx_unlock(&LOCK);
 
     return result;
 }
diff --git a/icu4c/source/i18n/dtitvfmt.cpp b/icu4c/source/i18n/dtitvfmt.cpp
index 0976dd5..f5d8694 100644
--- a/icu4c/source/i18n/dtitvfmt.cpp
+++ b/icu4c/source/i18n/dtitvfmt.cpp
@@ -82,10 +82,7 @@
 // Mutex, protects access to fDateFormat, fFromCalendar and fToCalendar.
 //        Needed because these data members are modified by const methods of DateIntervalFormat.
 
-static UMutex *gFormatterMutex() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
+static UMutex gFormatterMutex;
 
 DateIntervalFormat* U_EXPORT2
 DateIntervalFormat::createInstance(const UnicodeString& skeleton,
@@ -171,7 +168,7 @@
         delete fTimePattern;
         delete fDateTimeFormat;
         {
-            Mutex lock(gFormatterMutex());
+            Mutex lock(&gFormatterMutex);
             if ( itvfmt.fDateFormat ) {
                 fDateFormat = (SimpleDateFormat*)itvfmt.fDateFormat->clone();
             } else {
@@ -233,7 +230,7 @@
     if ((fInfo != fmt->fInfo) && (fInfo == NULL || fmt->fInfo == NULL)) {return FALSE;}
     if (fInfo && fmt->fInfo && (*fInfo != *fmt->fInfo )) {return FALSE;}
     {
-        Mutex lock(gFormatterMutex());
+        Mutex lock(&gFormatterMutex);
         if (fDateFormat != fmt->fDateFormat && (fDateFormat == NULL || fmt->fDateFormat == NULL)) {return FALSE;}
         if (fDateFormat && fmt->fDateFormat && (*fDateFormat != *fmt->fDateFormat)) {return FALSE;}
     }
@@ -295,7 +292,7 @@
     handler.setAcceptFirstOnly(TRUE);
     int8_t ignore;
 
-    Mutex lock(gFormatterMutex());
+    Mutex lock(&gFormatterMutex);
     return formatIntervalImpl(*dtInterval, appendTo, ignore, handler, status);
 }
 
@@ -312,7 +309,7 @@
     auto handler = result->getHandler(status);
     handler.setCategory(UFIELD_CATEGORY_DATE);
     {
-        Mutex lock(gFormatterMutex());
+        Mutex lock(&gFormatterMutex);
         formatIntervalImpl(dtInterval, string, firstIndex, handler, status);
     }
     handler.getError(status);
@@ -344,7 +341,7 @@
     handler.setAcceptFirstOnly(TRUE);
     int8_t ignore;
 
-    Mutex lock(gFormatterMutex());
+    Mutex lock(&gFormatterMutex);
     return formatImpl(fromCalendar, toCalendar, appendTo, ignore, handler, status);
 }
 
@@ -362,7 +359,7 @@
     auto handler = result->getHandler(status);
     handler.setCategory(UFIELD_CATEGORY_DATE);
     {
-        Mutex lock(gFormatterMutex());
+        Mutex lock(&gFormatterMutex);
         formatImpl(fromCalendar, toCalendar, string, firstIndex, handler, status);
     }
     handler.getError(status);
@@ -600,7 +597,7 @@
 DateIntervalFormat::getTimeZone() const
 {
     if (fDateFormat != NULL) {
-        Mutex lock(gFormatterMutex());
+        Mutex lock(&gFormatterMutex);
         return fDateFormat->getTimeZone();
     }
     // If fDateFormat is NULL (unexpected), create default timezone.
diff --git a/icu4c/source/i18n/gender.cpp b/icu4c/source/i18n/gender.cpp
index b57f009..32ddbf9 100644
--- a/icu4c/source/i18n/gender.cpp
+++ b/icu4c/source/i18n/gender.cpp
@@ -98,11 +98,11 @@
     return NULL;
   }
 
-  static UMutex *gGenderMetaLock = STATIC_NEW(UMutex);
+  static UMutex gGenderMetaLock;
   const GenderInfo* result = NULL;
   const char* key = locale.getName();
   {
-    Mutex lock(gGenderMetaLock);
+    Mutex lock(&gGenderMetaLock);
     result = (const GenderInfo*) uhash_get(gGenderInfoCache, key);
   }
   if (result) {
@@ -118,7 +118,7 @@
   // Try to put our GenderInfo object in cache. If there is a race condition,
   // favor the GenderInfo object that is already in the cache.
   {
-    Mutex lock(gGenderMetaLock);
+    Mutex lock(&gGenderMetaLock);
     GenderInfo* temp = (GenderInfo*) uhash_get(gGenderInfoCache, key);
     if (temp) {
       result = temp;
diff --git a/icu4c/source/i18n/islamcal.cpp b/icu4c/source/i18n/islamcal.cpp
index b44b60c..6e91d6e 100644
--- a/icu4c/source/i18n/islamcal.cpp
+++ b/icu4c/source/i18n/islamcal.cpp
@@ -470,8 +470,8 @@
 {
     double age = 0;
 
-    static UMutex *astroLock = STATIC_NEW(UMutex);      // pod bay door lock
-    umtx_lock(astroLock);
+    static UMutex astroLock;      // pod bay door lock
+    umtx_lock(&astroLock);
     if(gIslamicCalendarAstro == NULL) {
         gIslamicCalendarAstro = new CalendarAstronomer();
         if (gIslamicCalendarAstro == NULL) {
@@ -482,7 +482,7 @@
     }
     gIslamicCalendarAstro->setTime(time);
     age = gIslamicCalendarAstro->getMoonAge();
-    umtx_unlock(astroLock);
+    umtx_unlock(&astroLock);
 
     // Convert to degrees and normalize...
     age = age * 180 / CalendarAstronomer::PI;
diff --git a/icu4c/source/i18n/listformatter.cpp b/icu4c/source/i18n/listformatter.cpp
index 0260546..fa518fe 100644
--- a/icu4c/source/i18n/listformatter.cpp
+++ b/icu4c/source/i18n/listformatter.cpp
@@ -144,9 +144,9 @@
     keyBuffer.append(':', errorCode).append(style, errorCode);
     UnicodeString key(keyBuffer.data(), -1, US_INV);
     ListFormatInternal* result = nullptr;
-    static UMutex *listFormatterMutex = STATIC_NEW(UMutex);
+    static UMutex listFormatterMutex;
     {
-        Mutex m(listFormatterMutex);
+        Mutex m(&listFormatterMutex);
         if (listPatternHash == nullptr) {
             initializeHash(errorCode);
             if (U_FAILURE(errorCode)) {
@@ -164,7 +164,7 @@
     }
 
     {
-        Mutex m(listFormatterMutex);
+        Mutex m(&listFormatterMutex);
         ListFormatInternal* temp = static_cast<ListFormatInternal*>(listPatternHash->get(key));
         if (temp != nullptr) {
             delete result;
diff --git a/icu4c/source/i18n/measfmt.cpp b/icu4c/source/i18n/measfmt.cpp
index cb51038..610d298 100644
--- a/icu4c/source/i18n/measfmt.cpp
+++ b/icu4c/source/i18n/measfmt.cpp
@@ -801,10 +801,10 @@
     // #13606: DateFormat is not thread-safe, but MeasureFormat advertises itself as thread-safe.
     FieldPosition smallestFieldPosition(smallestField);
     UnicodeString draft;
-    static UMutex *dateFmtMutex = STATIC_NEW(UMutex);
-    umtx_lock(dateFmtMutex);
+    static UMutex dateFmtMutex;
+    umtx_lock(&dateFmtMutex);
     dateFmt.format(date, draft, smallestFieldPosition, status);
-    umtx_unlock(dateFmtMutex);
+    umtx_unlock(&dateFmtMutex);
 
     // If we find field for smallest amount replace it with the formatted
     // smallest amount from above taking care to replace the integer part
diff --git a/icu4c/source/i18n/numfmt.cpp b/icu4c/source/i18n/numfmt.cpp
index d0c96b6..8dcc8fa 100644
--- a/icu4c/source/i18n/numfmt.cpp
+++ b/icu4c/source/i18n/numfmt.cpp
@@ -1362,8 +1362,8 @@
         // TODO: Bad hash key usage, see ticket #8504.
         int32_t hashKey = desiredLocale.hashCode();
 
-        static UMutex *nscacheMutex = STATIC_NEW(UMutex);
-        Mutex lock(nscacheMutex);
+        static UMutex nscacheMutex;
+        Mutex lock(&nscacheMutex);
         ns = (NumberingSystem *)uhash_iget(NumberingSystem_cache, hashKey);
         if (ns == NULL) {
             ns = NumberingSystem::createInstance(desiredLocale,status);
diff --git a/icu4c/source/i18n/rbt.cpp b/icu4c/source/i18n/rbt.cpp
index d56d46b..50bffb3 100644
--- a/icu4c/source/i18n/rbt.cpp
+++ b/icu4c/source/i18n/rbt.cpp
@@ -253,14 +253,14 @@
     //
     // TODO(andy): Need a better scheme for handling this.
 
-    static UMutex *transliteratorDataMutex = STATIC_NEW(UMutex);
+    static UMutex transliteratorDataMutex;
     UBool needToLock;
     {
         Mutex m;
         needToLock = (&text != gLockedText);
     }
     if (needToLock) {
-        umtx_lock(transliteratorDataMutex);  // Contention, longish waits possible here.
+        umtx_lock(&transliteratorDataMutex);  // Contention, longish waits possible here.
         Mutex m;
         gLockedText = &text;
         lockedMutexAtThisLevel = TRUE;
@@ -279,7 +279,7 @@
             Mutex m;
             gLockedText = NULL;
         }
-        umtx_unlock(transliteratorDataMutex);
+        umtx_unlock(&transliteratorDataMutex);
     }
 }
 
diff --git a/icu4c/source/i18n/rbtz.cpp b/icu4c/source/i18n/rbtz.cpp
index d950831..4864555 100644
--- a/icu4c/source/i18n/rbtz.cpp
+++ b/icu4c/source/i18n/rbtz.cpp
@@ -149,16 +149,16 @@
 
 void
 RuleBasedTimeZone::completeConst(UErrorCode& status) const {
-    static UMutex *gLock = STATIC_NEW(UMutex);
+    static UMutex gLock;
     if (U_FAILURE(status)) {
         return;
     }
-    umtx_lock(gLock);
+    umtx_lock(&gLock);
     if (!fUpToDate) {
         RuleBasedTimeZone *ncThis = const_cast<RuleBasedTimeZone*>(this);
         ncThis->complete(status);
     }
-    umtx_unlock(gLock);
+    umtx_unlock(&gLock);
 }
 
 void
diff --git a/icu4c/source/i18n/reldatefmt.cpp b/icu4c/source/i18n/reldatefmt.cpp
index 59732cd..3c41436 100644
--- a/icu4c/source/i18n/reldatefmt.cpp
+++ b/icu4c/source/i18n/reldatefmt.cpp
@@ -1184,8 +1184,8 @@
 
     // Must guarantee that one thread at a time accesses the shared break
     // iterator.
-    static UMutex *gBrkIterMutex = STATIC_NEW(UMutex);
-    Mutex lock(gBrkIterMutex);
+    static UMutex gBrkIterMutex;
+    Mutex lock(&gBrkIterMutex);
     str.toTitle(
             fOptBreakIterator->get(),
             fLocale,
diff --git a/icu4c/source/i18n/simpletz.cpp b/icu4c/source/i18n/simpletz.cpp
index 9321fda..cbf1f9d 100644
--- a/icu4c/source/i18n/simpletz.cpp
+++ b/icu4c/source/i18n/simpletz.cpp
@@ -1084,13 +1084,13 @@
     if (U_FAILURE(status)) {
         return;
     }
-    static UMutex *gLock = STATIC_NEW(UMutex);
-    umtx_lock(gLock);
+    static UMutex gLock;
+    umtx_lock(&gLock);
     if (!transitionRulesInitialized) {
         SimpleTimeZone *ncThis = const_cast<SimpleTimeZone*>(this);
         ncThis->initTransitionRules(status);
     }
-    umtx_unlock(gLock);
+    umtx_unlock(&gLock);
 }
 
 void
diff --git a/icu4c/source/i18n/smpdtfmt.cpp b/icu4c/source/i18n/smpdtfmt.cpp
index 5e6f40b..678baad 100644
--- a/icu4c/source/i18n/smpdtfmt.cpp
+++ b/icu4c/source/i18n/smpdtfmt.cpp
@@ -230,10 +230,7 @@
 static const int32_t HEBREW_CAL_CUR_MILLENIUM_START_YEAR = 5000;
 static const int32_t HEBREW_CAL_CUR_MILLENIUM_END_YEAR = 6000;
 
-static UMutex *LOCK() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
+static UMutex LOCK;
 
 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)
 
@@ -1266,14 +1263,14 @@
     if ( fDateOverride.isBogus() && fTimeOverride.isBogus() ) {
         return;
     }
-    umtx_lock(LOCK());
+    umtx_lock(&LOCK);
     if (fSharedNumberFormatters == NULL) {
         fSharedNumberFormatters = allocSharedNumberFormatters();
         if (fSharedNumberFormatters == NULL) {
             status = U_MEMORY_ALLOCATION_ERROR;
         }
     }
-    umtx_unlock(LOCK());
+    umtx_unlock(&LOCK);
 
     if (U_FAILURE(status)) {
         return;
@@ -3901,11 +3898,11 @@
         } else if (fDateOverride.isBogus() && fHasHanYearChar) {
             // No current override (=> no Gannen numbering) but new pattern needs it;
             // use procedures from initNUmberFormatters / adoptNumberFormat
-            umtx_lock(LOCK());
+            umtx_lock(&LOCK);
             if (fSharedNumberFormatters == NULL) {
                 fSharedNumberFormatters = allocSharedNumberFormatters();
             }
-            umtx_unlock(LOCK());
+            umtx_unlock(&LOCK);
             if (fSharedNumberFormatters != NULL) {
                 Locale ovrLoc(fLocale.getLanguage(),fLocale.getCountry(),fLocale.getVariant(),"numbers=jpanyear");
                 UErrorCode status = U_ZERO_ERROR;
@@ -4237,7 +4234,7 @@
 TimeZoneFormat *
 SimpleDateFormat::tzFormat(UErrorCode &status) const {
     if (fTimeZoneFormat == NULL) {
-        umtx_lock(LOCK());
+        umtx_lock(&LOCK);
         {
             if (fTimeZoneFormat == NULL) {
                 TimeZoneFormat *tzfmt = TimeZoneFormat::createInstance(fLocale, status);
@@ -4248,7 +4245,7 @@
                 const_cast<SimpleDateFormat *>(this)->fTimeZoneFormat = tzfmt;
             }
         }
-        umtx_unlock(LOCK());
+        umtx_unlock(&LOCK);
     }
     return fTimeZoneFormat;
 }
diff --git a/icu4c/source/i18n/timezone.cpp b/icu4c/source/i18n/timezone.cpp
index 38e6d64..284334e 100644
--- a/icu4c/source/i18n/timezone.cpp
+++ b/icu4c/source/i18n/timezone.cpp
@@ -527,10 +527,7 @@
 
 // -------------------------------------
 
-static UMutex *gDefaultZoneMutex() {
-    static UMutex* m = STATIC_NEW(UMutex);
-    return m;
-}
+static UMutex gDefaultZoneMutex;
 
 /**
  * Initialize DEFAULT_ZONE from the system default time zone.  
@@ -541,7 +538,7 @@
 {
     ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
 
-    Mutex lock(gDefaultZoneMutex());
+    Mutex lock(&gDefaultZoneMutex);
     // If setDefault() has already been called we can skip getting the
     // default zone information from the system.
     if (DEFAULT_ZONE != NULL) {
@@ -575,7 +572,7 @@
 {
     umtx_initOnce(gDefaultZoneInitOnce, initDefault);
     {
-        Mutex lock(gDefaultZoneMutex());
+        Mutex lock(&gDefaultZoneMutex);
         return (DEFAULT_ZONE != NULL) ? DEFAULT_ZONE->clone() : NULL;
     }
 }
@@ -588,7 +585,7 @@
     if (zone != NULL)
     {
         {
-            Mutex lock(gDefaultZoneMutex());
+            Mutex lock(&gDefaultZoneMutex);
             TimeZone *old = DEFAULT_ZONE;
             DEFAULT_ZONE = zone;
             delete old;
diff --git a/icu4c/source/i18n/translit.cpp b/icu4c/source/i18n/translit.cpp
index 9f92bb3..3feb0a3 100644
--- a/icu4c/source/i18n/translit.cpp
+++ b/icu4c/source/i18n/translit.cpp
@@ -91,10 +91,7 @@
 /**
  * The mutex controlling access to registry object.
  */
-static icu::UMutex *registryMutex() {
-    static icu::UMutex *m = STATIC_NEW(icu::UMutex);
-    return m;
-}
+static icu::UMutex registryMutex;
 
 /**
  * System transliterator registry; non-null when initialized.
@@ -981,11 +978,11 @@
     TransliteratorAlias* alias = 0;
     Transliterator* t = 0;
 
-    umtx_lock(registryMutex());
+    umtx_lock(&registryMutex);
     if (HAVE_REGISTRY(ec)) {
         t = registry->get(id, alias, ec);
     }
-    umtx_unlock(registryMutex());
+    umtx_unlock(&registryMutex);
 
     if (U_FAILURE(ec)) {
         delete t;
@@ -1013,11 +1010,11 @@
             alias = 0;
 
             // Step 2. reget
-            umtx_lock(registryMutex());
+            umtx_lock(&registryMutex);
             if (HAVE_REGISTRY(ec)) {
                 t = registry->reget(id, parser, alias, ec);
             }
-            umtx_unlock(registryMutex());
+            umtx_unlock(&registryMutex);
 
             // Step 3. Loop back around!
         } else {
@@ -1215,7 +1212,7 @@
 void U_EXPORT2 Transliterator::registerFactory(const UnicodeString& id,
                                      Transliterator::Factory factory,
                                      Transliterator::Token context) {
-    Mutex lock(registryMutex());
+    Mutex lock(&registryMutex);
     UErrorCode ec = U_ZERO_ERROR;
     if (HAVE_REGISTRY(ec)) {
         _registerFactory(id, factory, context);
@@ -1254,7 +1251,7 @@
  * @see #unregister
  */
 void U_EXPORT2 Transliterator::registerInstance(Transliterator* adoptedPrototype) {
-    Mutex lock(registryMutex());
+    Mutex lock(&registryMutex);
     UErrorCode ec = U_ZERO_ERROR;
     if (HAVE_REGISTRY(ec)) {
         _registerInstance(adoptedPrototype);
@@ -1268,7 +1265,7 @@
 
 void U_EXPORT2 Transliterator::registerAlias(const UnicodeString& aliasID,
                                              const UnicodeString& realID) {
-    Mutex lock(registryMutex());
+    Mutex lock(&registryMutex);
     UErrorCode ec = U_ZERO_ERROR;
     if (HAVE_REGISTRY(ec)) {
         _registerAlias(aliasID, realID);
@@ -1290,7 +1287,7 @@
 
  */
 void U_EXPORT2 Transliterator::unregister(const UnicodeString& ID) {
-    Mutex lock(registryMutex());
+    Mutex lock(&registryMutex);
     UErrorCode ec = U_ZERO_ERROR;
     if (HAVE_REGISTRY(ec)) {
         registry->remove(ID);
@@ -1305,7 +1302,7 @@
  */
 int32_t U_EXPORT2 Transliterator::countAvailableIDs(void) {
     int32_t retVal = 0;
-    Mutex lock(registryMutex());
+    Mutex lock(&registryMutex);
     UErrorCode ec = U_ZERO_ERROR;
     if (HAVE_REGISTRY(ec)) {
         retVal = registry->countAvailableIDs();
@@ -1321,12 +1318,12 @@
  */
 const UnicodeString& U_EXPORT2 Transliterator::getAvailableID(int32_t index) {
     const UnicodeString* result = NULL;
-    umtx_lock(registryMutex());
+    umtx_lock(&registryMutex);
     UErrorCode ec = U_ZERO_ERROR;
     if (HAVE_REGISTRY(ec)) {
         result = &registry->getAvailableID(index);
     }
-    umtx_unlock(registryMutex());
+    umtx_unlock(&registryMutex);
     U_ASSERT(result != NULL); // fail if no registry
     return *result;
 }
@@ -1334,11 +1331,11 @@
 StringEnumeration* U_EXPORT2 Transliterator::getAvailableIDs(UErrorCode& ec) {
     if (U_FAILURE(ec)) return NULL;
     StringEnumeration* result = NULL;
-    umtx_lock(registryMutex());
+    umtx_lock(&registryMutex);
     if (HAVE_REGISTRY(ec)) {
         result = registry->getAvailableIDs();
     }
-    umtx_unlock(registryMutex());
+    umtx_unlock(&registryMutex);
     if (result == NULL) {
         ec = U_INTERNAL_TRANSLITERATOR_ERROR;
     }
@@ -1346,14 +1343,14 @@
 }
 
 int32_t U_EXPORT2 Transliterator::countAvailableSources(void) {
-    Mutex lock(registryMutex());
+    Mutex lock(&registryMutex);
     UErrorCode ec = U_ZERO_ERROR;
     return HAVE_REGISTRY(ec) ? _countAvailableSources() : 0;
 }
 
 UnicodeString& U_EXPORT2 Transliterator::getAvailableSource(int32_t index,
                                                   UnicodeString& result) {
-    Mutex lock(registryMutex());
+    Mutex lock(&registryMutex);
     UErrorCode ec = U_ZERO_ERROR;
     if (HAVE_REGISTRY(ec)) {
         _getAvailableSource(index, result);
@@ -1362,7 +1359,7 @@
 }
 
 int32_t U_EXPORT2 Transliterator::countAvailableTargets(const UnicodeString& source) {
-    Mutex lock(registryMutex());
+    Mutex lock(&registryMutex);
     UErrorCode ec = U_ZERO_ERROR;
     return HAVE_REGISTRY(ec) ? _countAvailableTargets(source) : 0;
 }
@@ -1370,7 +1367,7 @@
 UnicodeString& U_EXPORT2 Transliterator::getAvailableTarget(int32_t index,
                                                   const UnicodeString& source,
                                                   UnicodeString& result) {
-    Mutex lock(registryMutex());
+    Mutex lock(&registryMutex);
     UErrorCode ec = U_ZERO_ERROR;
     if (HAVE_REGISTRY(ec)) {
         _getAvailableTarget(index, source, result);
@@ -1380,7 +1377,7 @@
 
 int32_t U_EXPORT2 Transliterator::countAvailableVariants(const UnicodeString& source,
                                                const UnicodeString& target) {
-    Mutex lock(registryMutex());
+    Mutex lock(&registryMutex);
     UErrorCode ec = U_ZERO_ERROR;
     return HAVE_REGISTRY(ec) ? _countAvailableVariants(source, target) : 0;
 }
@@ -1389,7 +1386,7 @@
                                                    const UnicodeString& source,
                                                    const UnicodeString& target,
                                                    UnicodeString& result) {
-    Mutex lock(registryMutex());
+    Mutex lock(&registryMutex);
     UErrorCode ec = U_ZERO_ERROR;
     if (HAVE_REGISTRY(ec)) {
         _getAvailableVariant(index, source, target, result);
diff --git a/icu4c/source/i18n/tridpars.cpp b/icu4c/source/i18n/tridpars.cpp
index fd9bcfc..9de8a16 100644
--- a/icu4c/source/i18n/tridpars.cpp
+++ b/icu4c/source/i18n/tridpars.cpp
@@ -50,10 +50,7 @@
 /**
  * The mutex controlling access to SPECIAL_INVERSES
  */
-static UMutex *LOCK() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
+static UMutex LOCK;
 
 TransliteratorIDParser::Specs::Specs(const UnicodeString& s, const UnicodeString& t,
                                      const UnicodeString& v, UBool sawS,
@@ -662,7 +659,7 @@
         bidirectional = FALSE;
     }
 
-    Mutex lock(LOCK());
+    Mutex lock(&LOCK);
 
     UnicodeString *tempus = new UnicodeString(inverseTarget);  // Used for null pointer check before usage.
     if (tempus == NULL) {
@@ -866,9 +863,9 @@
 
     UnicodeString* inverseTarget;
 
-    umtx_lock(LOCK());
+    umtx_lock(&LOCK);
     inverseTarget = (UnicodeString*) SPECIAL_INVERSES->get(specs.target);
-    umtx_unlock(LOCK());
+    umtx_unlock(&LOCK);
 
     if (inverseTarget != NULL) {
         // If the original ID contained "Any-" then make the
diff --git a/icu4c/source/i18n/tzfmt.cpp b/icu4c/source/i18n/tzfmt.cpp
index 22c5ab2..3e7b3bd 100644
--- a/icu4c/source/i18n/tzfmt.cpp
+++ b/icu4c/source/i18n/tzfmt.cpp
@@ -150,10 +150,7 @@
 static TextTrieMap *gShortZoneIdTrie = NULL;
 static icu::UInitOnce gShortZoneIdTrieInitOnce = U_INITONCE_INITIALIZER;
 
-static UMutex *gLock() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
+static UMutex gLock;
 
 U_CDECL_BEGIN
 /**
@@ -1391,12 +1388,12 @@
         return NULL;
     }
 
-    umtx_lock(gLock());
+    umtx_lock(&gLock);
     if (fTimeZoneGenericNames == NULL) {
         TimeZoneFormat *nonConstThis = const_cast<TimeZoneFormat *>(this);
         nonConstThis->fTimeZoneGenericNames = TimeZoneGenericNames::createInstance(fLocale, status);
     }
-    umtx_unlock(gLock());
+    umtx_unlock(&gLock);
 
     return fTimeZoneGenericNames;
 }
@@ -1407,7 +1404,7 @@
         return NULL;
     }
 
-    umtx_lock(gLock());
+    umtx_lock(&gLock);
     if (fTZDBTimeZoneNames == NULL) {
         TZDBTimeZoneNames *tzdbNames = new TZDBTimeZoneNames(fLocale);
         if (tzdbNames == NULL) {
@@ -1417,7 +1414,7 @@
             nonConstThis->fTZDBTimeZoneNames = tzdbNames;
         }
     }
-    umtx_unlock(gLock());
+    umtx_unlock(&gLock);
 
     return fTZDBTimeZoneNames;
 }
diff --git a/icu4c/source/i18n/tzgnames.cpp b/icu4c/source/i18n/tzgnames.cpp
index 5a92a65..e056461 100644
--- a/icu4c/source/i18n/tzgnames.cpp
+++ b/icu4c/source/i18n/tzgnames.cpp
@@ -272,10 +272,7 @@
     return results;
 }
 
-static UMutex *gLock() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
+static UMutex gLock;
 
 class TZGNCore : public UMemory {
 public:
@@ -494,11 +491,11 @@
 
     const UChar *locname = NULL;
     TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
-    umtx_lock(gLock());
+    umtx_lock(&gLock);
     {
         locname = nonConstThis->getGenericLocationName(tzCanonicalID);
     }
-    umtx_unlock(gLock());
+    umtx_unlock(&gLock);
 
     if (locname == NULL) {
         name.setToBogus();
@@ -749,11 +746,11 @@
 
     const UChar *uplname = NULL;
     TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
-    umtx_lock(gLock());
+    umtx_lock(&gLock);
     {
         uplname = nonConstThis->getPartialLocationName(tzCanonicalID, mzID, isLong, mzDisplayName);
     }
-    umtx_unlock(gLock());
+    umtx_unlock(&gLock);
 
     if (uplname == NULL) {
         name.setToBogus();
@@ -1016,11 +1013,11 @@
 
     TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
 
-    umtx_lock(gLock());
+    umtx_lock(&gLock);
     {
         fGNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
     }
-    umtx_unlock(gLock());
+    umtx_unlock(&gLock);
 
     if (U_FAILURE(status)) {
         return NULL;
@@ -1047,7 +1044,7 @@
 
     // All names are not yet loaded into the local trie.
     // Load all available names into the trie. This could be very heavy.
-    umtx_lock(gLock());
+    umtx_lock(&gLock);
     {
         if (!fGNamesTrieFullyLoaded) {
             StringEnumeration *tzIDs = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status);
@@ -1069,18 +1066,18 @@
             }
         }
     }
-    umtx_unlock(gLock());
+    umtx_unlock(&gLock);
 
     if (U_FAILURE(status)) {
         return NULL;
     }
 
-    umtx_lock(gLock());
+    umtx_lock(&gLock);
     {
         // now try it again
         fGNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
     }
-    umtx_unlock(gLock());
+    umtx_unlock(&gLock);
 
     results = handler.getMatches(maxLen);
     if (results != NULL && maxLen > 0) {
@@ -1121,10 +1118,7 @@
 } TZGNCoreRef;
 
 // TZGNCore object cache handling
-static UMutex *gTZGNLock() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
+static UMutex gTZGNLock;
 static UHashtable *gTZGNCoreCache = NULL;
 static UBool gTZGNCoreCacheInitialized = FALSE;
 
@@ -1190,13 +1184,13 @@
 }
 
 TimeZoneGenericNames::~TimeZoneGenericNames() {
-    umtx_lock(gTZGNLock());
+    umtx_lock(&gTZGNLock);
     {
         U_ASSERT(fRef->refCount > 0);
         // Just decrement the reference count
         fRef->refCount--;
     }
-    umtx_unlock(gTZGNLock());
+    umtx_unlock(&gTZGNLock);
 }
 
 TimeZoneGenericNames*
@@ -1212,7 +1206,7 @@
 
     TZGNCoreRef *cacheEntry = NULL;
     {
-        Mutex lock(gTZGNLock());
+        Mutex lock(&gTZGNLock);
 
         if (!gTZGNCoreCacheInitialized) {
             // Create empty hashtable
@@ -1304,13 +1298,13 @@
 TimeZoneGenericNames::clone() const {
     TimeZoneGenericNames* other = new TimeZoneGenericNames();
     if (other) {
-        umtx_lock(gTZGNLock());
+        umtx_lock(&gTZGNLock);
         {
             // Just increments the reference count
             fRef->refCount++;
             other->fRef = fRef;
         }
-        umtx_unlock(gTZGNLock());
+        umtx_unlock(&gTZGNLock);
     }
     return other;
 }
diff --git a/icu4c/source/i18n/tznames.cpp b/icu4c/source/i18n/tznames.cpp
index bceab39..50d7a66 100644
--- a/icu4c/source/i18n/tznames.cpp
+++ b/icu4c/source/i18n/tznames.cpp
@@ -29,10 +29,7 @@
 U_NAMESPACE_BEGIN
 
 // TimeZoneNames object cache handling
-static UMutex *gTimeZoneNamesLock() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
+static UMutex gTimeZoneNamesLock;
 static UHashtable *gTimeZoneNamesCache = NULL;
 static UBool gTimeZoneNamesCacheInitialized = FALSE;
 
@@ -135,7 +132,7 @@
 }
 
 TimeZoneNamesDelegate::TimeZoneNamesDelegate(const Locale& locale, UErrorCode& status) {
-    Mutex lock(gTimeZoneNamesLock());
+    Mutex lock(&gTimeZoneNamesLock);
     if (!gTimeZoneNamesCacheInitialized) {
         // Create empty hashtable if it is not already initialized.
         gTimeZoneNamesCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
@@ -211,7 +208,7 @@
 }
 
 TimeZoneNamesDelegate::~TimeZoneNamesDelegate() {
-    umtx_lock(gTimeZoneNamesLock());
+    umtx_lock(&gTimeZoneNamesLock);
     {
         if (fTZnamesCacheEntry) {
             U_ASSERT(fTZnamesCacheEntry->refCount > 0);
@@ -219,7 +216,7 @@
             fTZnamesCacheEntry->refCount--;
         }
     }
-    umtx_unlock(gTimeZoneNamesLock());
+    umtx_unlock(&gTimeZoneNamesLock);
 }
 
 UBool
@@ -240,13 +237,13 @@
 TimeZoneNamesDelegate::clone() const {
     TimeZoneNamesDelegate* other = new TimeZoneNamesDelegate();
     if (other != NULL) {
-        umtx_lock(gTimeZoneNamesLock());
+        umtx_lock(&gTimeZoneNamesLock);
         {
             // Just increment the reference count
             fTZnamesCacheEntry->refCount++;
             other->fTZnamesCacheEntry = fTZnamesCacheEntry;
         }
-        umtx_unlock(gTimeZoneNamesLock());
+        umtx_unlock(&gTimeZoneNamesLock);
     }
     return other;
 }
diff --git a/icu4c/source/i18n/tznames_impl.cpp b/icu4c/source/i18n/tznames_impl.cpp
index 09bf12e..d92f5fb 100644
--- a/icu4c/source/i18n/tznames_impl.cpp
+++ b/icu4c/source/i18n/tznames_impl.cpp
@@ -52,10 +52,7 @@
 static const char* TZDBNAMES_KEYS[]               = {"ss", "sd"};
 static const int32_t TZDBNAMES_KEYS_SIZE = UPRV_LENGTHOF(TZDBNAMES_KEYS);
 
-static UMutex *gDataMutex() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
+static UMutex gDataMutex;
 
 static UHashtable* gTZDBNamesMap = NULL;
 static icu::UInitOnce gTZDBNamesMapInitOnce = U_INITONCE_INITIALIZER;
@@ -391,9 +388,9 @@
         //       Don't do unless it's really required.
 
         // Mutex for protecting the lazy creation of the Trie node structure on the first call to search().
-        static UMutex *TextTrieMutex = STATIC_NEW(UMutex);
+        static UMutex TextTrieMutex;
 
-        Mutex lock(TextTrieMutex);
+        Mutex lock(&TextTrieMutex);
         if (fLazyContents != NULL) {
             TextTrieMap *nonConstThis = const_cast<TextTrieMap *>(this);
             nonConstThis->buildTrie(status);
@@ -1217,7 +1214,7 @@
     TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
 
     {
-        Mutex lock(gDataMutex());
+        Mutex lock(&gDataMutex);
         UErrorCode status = U_ZERO_ERROR;
         znames = nonConstThis->loadMetaZoneNames(mzID, status);
         if (U_FAILURE(status)) { return name; }
@@ -1243,7 +1240,7 @@
     TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
 
     {
-        Mutex lock(gDataMutex());
+        Mutex lock(&gDataMutex);
         UErrorCode status = U_ZERO_ERROR;
         tznames = nonConstThis->loadTimeZoneNames(tzID, status);
         if (U_FAILURE(status)) { return name; }
@@ -1266,7 +1263,7 @@
     TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
 
     {
-        Mutex lock(gDataMutex());
+        Mutex lock(&gDataMutex);
         UErrorCode status = U_ZERO_ERROR;
         tznames = nonConstThis->loadTimeZoneNames(tzID, status);
         if (U_FAILURE(status)) { return name; }
@@ -1361,7 +1358,7 @@
     // Synchronize so that data is not loaded multiple times.
     // TODO: Consider more fine-grained synchronization.
     {
-        Mutex lock(gDataMutex());
+        Mutex lock(&gDataMutex);
 
         // First try of lookup.
         matches = doFind(handler, text, start, status);
@@ -1588,7 +1585,7 @@
     if (U_FAILURE(status)) return;
 
     {
-        Mutex lock(gDataMutex());
+        Mutex lock(&gDataMutex);
         internalLoadAllDisplayNames(status);
     }
 }
@@ -1605,7 +1602,7 @@
 
     // Load the time zone strings
     {
-        Mutex lock(gDataMutex());
+        Mutex lock(&gDataMutex);
         tznames = (void*) nonConstThis->loadTimeZoneNames(tzID, status);
         if (U_FAILURE(status)) { return; }
     }
@@ -1625,7 +1622,7 @@
                 } else {
                     // Load the meta zone strings
                     // Mutex is scoped to the "else" statement
-                    Mutex lock(gDataMutex());
+                    Mutex lock(&gDataMutex);
                     mznames = (void*) nonConstThis->loadMetaZoneNames(mzID, status);
                     if (U_FAILURE(status)) { return; }
                     // Note: when the metazone doesn't exist, in Java, loadMetaZoneNames returns
@@ -2253,8 +2250,8 @@
     U_ASSERT(status == U_ZERO_ERROR);   // already checked length above
     mzIDKey[mzID.length()] = 0;
 
-    static UMutex *gTZDBNamesMapLock = STATIC_NEW(UMutex);
-    umtx_lock(gTZDBNamesMapLock);
+    static UMutex gTZDBNamesMapLock;
+    umtx_lock(&gTZDBNamesMapLock);
     {
         void *cacheVal = uhash_get(gTZDBNamesMap, mzIDKey);
         if (cacheVal == NULL) {
@@ -2297,7 +2294,7 @@
             tzdbNames = (TZDBNames *)cacheVal;
         }
     }
-    umtx_unlock(gTZDBNamesMapLock);
+    umtx_unlock(&gTZDBNamesMapLock);
 
     return tzdbNames;
 }
diff --git a/icu4c/source/i18n/zonemeta.cpp b/icu4c/source/i18n/zonemeta.cpp
index cc53ef9..72c590f 100644
--- a/icu4c/source/i18n/zonemeta.cpp
+++ b/icu4c/source/i18n/zonemeta.cpp
@@ -30,10 +30,7 @@
 #include "olsontz.h"
 #include "uinvchar.h"
 
-static icu::UMutex *gZoneMetaLock() {
-    static icu::UMutex *m = STATIC_NEW(icu::UMutex);
-    return m;
-}
+static icu::UMutex gZoneMetaLock;
 
 // CLDR Canonical ID mapping table
 static UHashtable *gCanonicalIDCache = NULL;
@@ -266,11 +263,11 @@
     }
 
     // Check if it was already cached
-    umtx_lock(gZoneMetaLock());
+    umtx_lock(&gZoneMetaLock);
     {
         canonicalID = (const UChar *)uhash_get(gCanonicalIDCache, utzid);
     }
-    umtx_unlock(gZoneMetaLock());
+    umtx_unlock(&gZoneMetaLock);
 
     if (canonicalID != NULL) {
         return canonicalID;
@@ -351,7 +348,7 @@
         U_ASSERT(canonicalID != NULL);  // canocanilD must be non-NULL here
 
         // Put the resolved canonical ID to the cache
-        umtx_lock(gZoneMetaLock());
+        umtx_lock(&gZoneMetaLock);
         {
             const UChar* idInCache = (const UChar *)uhash_get(gCanonicalIDCache, utzid);
             if (idInCache == NULL) {
@@ -371,7 +368,7 @@
                 }
             }
         }
-        umtx_unlock(gZoneMetaLock());
+        umtx_unlock(&gZoneMetaLock);
     }
 
     return canonicalID;
@@ -449,14 +446,14 @@
         // Check if it was already cached
         UBool cached = FALSE;
         UBool singleZone = FALSE;
-        umtx_lock(gZoneMetaLock());
+        umtx_lock(&gZoneMetaLock);
         {
             singleZone = cached = gSingleZoneCountries->contains((void*)region);
             if (!cached) {
                 cached = gMultiZonesCountries->contains((void*)region);
             }
         }
-        umtx_unlock(gZoneMetaLock());
+        umtx_unlock(&gZoneMetaLock);
 
         if (!cached) {
             // We need to go through all zones associated with the region.
@@ -475,7 +472,7 @@
             delete ids;
 
             // Cache the result
-            umtx_lock(gZoneMetaLock());
+            umtx_lock(&gZoneMetaLock);
             {
                 UErrorCode ec = U_ZERO_ERROR;
                 if (singleZone) {
@@ -488,7 +485,7 @@
                     }
                 }
             }
-            umtx_unlock(gZoneMetaLock());
+            umtx_unlock(&gZoneMetaLock);
         }
 
         if (singleZone) {
@@ -575,11 +572,11 @@
     // get the mapping from cache
     const UVector *result = NULL;
 
-    umtx_lock(gZoneMetaLock());
+    umtx_lock(&gZoneMetaLock);
     {
         result = (UVector*) uhash_get(gOlsonToMeta, tzidUChars);
     }
-    umtx_unlock(gZoneMetaLock());
+    umtx_unlock(&gZoneMetaLock);
 
     if (result != NULL) {
         return result;
@@ -593,7 +590,7 @@
     }
 
     // put the new one into the cache
-    umtx_lock(gZoneMetaLock());
+    umtx_lock(&gZoneMetaLock);
     {
         // make sure it's already created
         result = (UVector*) uhash_get(gOlsonToMeta, tzidUChars);
@@ -621,7 +618,7 @@
             delete tmpResult;
         }
     }
-    umtx_unlock(gZoneMetaLock());
+    umtx_unlock(&gZoneMetaLock);
 
     return result;
 }
diff --git a/icu4c/source/io/locbund.cpp b/icu4c/source/io/locbund.cpp
index 4b6fe34..46c97bc 100644
--- a/icu4c/source/io/locbund.cpp
+++ b/icu4c/source/io/locbund.cpp
@@ -47,8 +47,8 @@
 
 static inline UNumberFormat * copyInvariantFormatter(ULocaleBundle *result, UNumberFormatStyle style) {
     U_NAMESPACE_USE
-    static UMutex *gLock = STATIC_NEW(UMutex);
-    Mutex lock(gLock);
+    static UMutex gLock;
+    Mutex lock(&gLock);
     if (result->fNumberFormat[style-1] == NULL) {
         if (gPosixNumberFormat[style-1] == NULL) {
             UErrorCode status = U_ZERO_ERROR;
diff --git a/icu4c/source/test/depstest/depstest.py b/icu4c/source/test/depstest/depstest.py
index d83937d..83dbfc0 100755
--- a/icu4c/source/test/depstest/depstest.py
+++ b/icu4c/source/test/depstest/depstest.py
@@ -107,6 +107,10 @@
 allowed_errors = (
   ("common/umutex.o", "std::__throw_system_error(int)"),
   ("common/umutex.o", "std::uncaught_exception()"),
+  ("common/umutex.o", "std::__once_callable"),
+  ("common/umutex.o", "std::__once_call"),
+  ("common/umutex.o", "__once_proxy"),
+  ("common/umutex.o", "__tls_get_addr"),
   ("common/unifiedcache.o", "std::__throw_system_error(int)"),
 )
 
diff --git a/icu4c/source/test/intltest/intltest.cpp b/icu4c/source/test/intltest/intltest.cpp
index c1b6e5b..3d6793e 100644
--- a/icu4c/source/test/intltest/intltest.cpp
+++ b/icu4c/source/test/intltest/intltest.cpp
@@ -1116,8 +1116,8 @@
     // All error messages generated by tests funnel through here.
     // Multithreaded tests can concurrently generate errors, requiring synchronization
     // to keep each message together.
-    static UMutex *messageMutex = STATIC_NEW(UMutex);
-    Mutex lock(messageMutex);
+    static UMutex messageMutex;
+    Mutex lock(&messageMutex);
 
     // string that starts with a LineFeed character and continues
     // with spaces according to the current indentation
diff --git a/icu4c/source/test/intltest/tsmthred.cpp b/icu4c/source/test/intltest/tsmthred.cpp
index 2f92526..396c490 100644
--- a/icu4c/source/test/intltest/tsmthred.cpp
+++ b/icu4c/source/test/intltest/tsmthred.cpp
@@ -62,7 +62,6 @@
 
     TESTCASE_AUTO_BEGIN;
     TESTCASE_AUTO(TestThreads);
-    TESTCASE_AUTO(TestMutex);
 #if !UCONFIG_NO_FORMATTING
     TESTCASE_AUTO(TestThreadedIntl);
 #endif
@@ -72,7 +71,6 @@
     TESTCASE_AUTO(TestString);
     TESTCASE_AUTO(TestArabicShapingThreads);
     TESTCASE_AUTO(TestAnyTranslit);
-    TESTCASE_AUTO(TestConditionVariables);
     TESTCASE_AUTO(TestUnifiedCache);
 #if !UCONFIG_NO_TRANSLITERATION
     TESTCASE_AUTO(TestBreakTranslit);
@@ -232,108 +230,6 @@
 }
 
 
-//-----------------------------------------------------------------------
-//
-//  TestMutex  - a simple (non-stress) test to verify that ICU mutexes
-//               and condition variables are functioning.  Does not test the use of
-//               mutexes within ICU services, but rather that the
-//               platform's mutex support is at least superficially there.
-//
-//----------------------------------------------------------------------
-static UMutex *gTestMutexA() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
-static std::condition_variable *gThreadsCountChanged() {
-    static std::condition_variable *cv = STATIC_NEW(std::condition_variable);
-    return cv;
-}
-
-static int     gThreadsStarted = 0;
-static int     gThreadsInMiddle = 0;
-static int     gThreadsDone = 0;
-
-static const int TESTMUTEX_THREAD_COUNT = 40;
-
-class TestMutexThread : public SimpleThread
-{
-public:
-    virtual void run() {
-        // This is the code that each of the spawned threads runs.
-        // All threads move together throught the started - middle - done sequence together,
-        // waiting for all other threads to reach each point before advancing.
-        std::unique_lock<std::mutex> lock(gTestMutexA()->fMutex);
-        gThreadsStarted += 1;
-        gThreadsCountChanged()->notify_all();
-        while (gThreadsStarted < TESTMUTEX_THREAD_COUNT) {
-            if (gThreadsInMiddle != 0) {
-                IntlTest::gTest->errln(
-                    "%s:%d gThreadsInMiddle = %d. Expected 0.", __FILE__, __LINE__, gThreadsInMiddle);
-                return;
-            }
-            gThreadsCountChanged()->wait(lock);
-        }
-
-        gThreadsInMiddle += 1;
-        gThreadsCountChanged()->notify_all();
-        while (gThreadsInMiddle < TESTMUTEX_THREAD_COUNT) {
-            if (gThreadsDone != 0) {
-                IntlTest::gTest->errln(
-                    "%s:%d gThreadsDone = %d. Expected 0.", __FILE__, __LINE__, gThreadsDone);
-                return;
-            }
-            gThreadsCountChanged()->wait(lock);
-        }
-
-        gThreadsDone += 1;
-        gThreadsCountChanged()->notify_all();
-        while (gThreadsDone < TESTMUTEX_THREAD_COUNT) {
-            gThreadsCountChanged()->wait(lock);
-        }
-    }
-};
-
-void MultithreadTest::TestMutex()
-{
-    gThreadsStarted = 0;
-    gThreadsInMiddle = 0;
-    gThreadsDone = 0;
-    int32_t i = 0;
-    TestMutexThread  threads[TESTMUTEX_THREAD_COUNT];
-    {
-        std::unique_lock<std::mutex> lock(gTestMutexA()->fMutex);
-        for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
-            if (threads[i].start() != 0) {
-                errln("%s:%d Error starting thread %d", __FILE__, __LINE__, i);
-                return;
-            }
-        }
-
-        // Because we are holding gTestMutexA, all of the threads should be blocked
-        // at the start of their run() function.
-        if (gThreadsStarted != 0) {
-            errln("%s:%d gThreadsStarted=%d. Expected 0.", __FILE__, __LINE__, gThreadsStarted);
-            return;
-        }
-
-        while (gThreadsInMiddle < TESTMUTEX_THREAD_COUNT) {
-            if (gThreadsDone != 0) {
-                errln("%s:%d gThreadsDone=%d. Expected 0.", __FILE__, __LINE__, gThreadsStarted);
-                return;
-            }
-            gThreadsCountChanged()->wait(lock);
-        }
-
-        while (gThreadsDone < TESTMUTEX_THREAD_COUNT) {
-            gThreadsCountChanged()->wait(lock);
-        }
-    }
-    for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
-        threads[i].join();
-    }
-}
-
-
 //-------------------------------------------------------------------------------------------
 //
 //   TestMultithreadedIntl.  Test ICU Formatting in a multi-threaded environment
@@ -1151,96 +1047,6 @@
 }
 
 
-//
-// Condition Variables Test
-//   Create a swarm of threads.
-//   Using a mutex and a condition variables each thread
-//     Increments a global count of started threads.
-//     Broadcasts that it has started.
-//     Waits on the condition that all threads have started.
-//     Increments a global count of finished threads.
-//     Waits on the condition that all threads have finished.
-//     Exits.
-//
-
-class CondThread: public SimpleThread {
-  public:
-    CondThread() :fFinished(false)  {};
-    ~CondThread() {};
-    void run();
-    bool  fFinished;
-};
-
-static UMutex *gCTMutex() {
-    static UMutex *m = STATIC_NEW(UMutex);
-    return m;
-}
-static std::condition_variable *gCTConditionVar() {
-    static std::condition_variable *cv = STATIC_NEW(std::condition_variable);
-    return cv;
-}
-int gConditionTestOne = 1;   // Value one. Non-const, extern linkage to inhibit
-                             //   compiler assuming a known value.
-int gStartedThreads;
-int gFinishedThreads;
-static const int NUMTHREADS = 10;
-
-
-// Worker thread function.
-void CondThread::run() {
-    std::unique_lock<std::mutex> lock(gCTMutex()->fMutex);
-    gStartedThreads += gConditionTestOne;
-    gCTConditionVar()->notify_all();
-
-    while (gStartedThreads < NUMTHREADS) {
-        if (gFinishedThreads != 0) {
-            IntlTest::gTest->errln("File %s, Line %d: Error, gStartedThreads = %d, gFinishedThreads = %d",
-                             __FILE__, __LINE__, gStartedThreads, gFinishedThreads);
-        }
-        gCTConditionVar()->wait(lock);
-    }
-
-    gFinishedThreads += gConditionTestOne;
-    fFinished = true;
-    gCTConditionVar()->notify_all();
-
-    while (gFinishedThreads < NUMTHREADS) {
-        gCTConditionVar()->wait(lock);
-    }
-}
-
-void MultithreadTest::TestConditionVariables() {
-    gStartedThreads = 0;
-    gFinishedThreads = 0;
-    int i;
-    CondThread *threads[NUMTHREADS];
-
-    {
-        std::unique_lock<std::mutex> lock(gCTMutex()->fMutex);
-        for (i=0; i<NUMTHREADS; ++i) {
-            threads[i] = new CondThread;
-            threads[i]->start();
-        }
-
-        while (gStartedThreads < NUMTHREADS) {
-            gCTConditionVar()->wait(lock);
-        }
-
-        while (gFinishedThreads < NUMTHREADS) {
-            gCTConditionVar()->wait(lock);
-        }
-    }
-
-    for (i=0; i<NUMTHREADS; ++i) {
-        assertTrue(WHERE, threads[i]->fFinished);
-    }
-
-    for (i=0; i<NUMTHREADS; ++i) {
-        threads[i]->join();
-        delete threads[i];
-    }
-}
-
 
 //
 // Unified Cache Test
@@ -1275,6 +1081,9 @@
 
 U_NAMESPACE_BEGIN
 
+static std::mutex *gCTMutex = nullptr;
+static std::condition_variable *gCTConditionVar = nullptr;
+
 template<> U_EXPORT
 const UCTMultiThreadItem *LocaleCacheKey<UCTMultiThreadItem>::createObject(
         const void *context, UErrorCode &status) const {
@@ -1292,7 +1101,7 @@
 
     bool firstObject = false;
     {
-        std::unique_lock<std::mutex> lock(gCTMutex()->fMutex);
+        std::unique_lock<std::mutex> lock(*gCTMutex);
         firstObject = (gObjectsCreated == 0);
         if (firstObject) {
             // Force the first object creation that comes through to wait
@@ -1303,7 +1112,7 @@
             // early, to keep subsequent threads from entering this path.
             gObjectsCreated = 1;
             while (gObjectsCreated < 3) {
-                gCTConditionVar()->wait(lock);
+                gCTConditionVar->wait(lock);
             }
         }
     }
@@ -1319,11 +1128,11 @@
     // Log that we created an object. The first object was already counted,
     //    don't do it again.
     {
-        std::unique_lock<std::mutex> lock(gCTMutex()->fMutex);
+        std::unique_lock<std::mutex> lock(*gCTMutex);
         if (!firstObject) {
             gObjectsCreated += 1;
         }
-        gCTConditionVar()->notify_all();
+        gCTConditionVar->notify_all();
     }
 
     return result;
@@ -1386,7 +1195,9 @@
     cache.setEvictionPolicy(2, 0, status);
     U_ASSERT(U_SUCCESS(status));
 
-    gFinishedThreads = 0;
+    gCTMutex = new std::mutex();
+    gCTConditionVar = new std::condition_variable();
+
     gObjectsCreated = 0;
 
     UnifiedCacheThread *threads[CACHE_LOAD][UPRV_LENGTHOF(gCacheLocales)];
@@ -1428,6 +1239,8 @@
             delete threads[i][j];
         }
     }
+    delete gCTMutex;
+    delete gCTConditionVar;
 }
 
 #if !UCONFIG_NO_TRANSLITERATION
diff --git a/icu4c/source/test/intltest/tsmthred.h b/icu4c/source/test/intltest/tsmthred.h
index 565080a..d3983cf 100644
--- a/icu4c/source/test/intltest/tsmthred.h
+++ b/icu4c/source/test/intltest/tsmthred.h
@@ -36,10 +36,6 @@
      **/
     void TestArabicShapingThreads(void);
 	
-    /**
-     * test that mutexes work 
-     **/
-    void TestMutex(void);
 #if !UCONFIG_NO_FORMATTING
     /**
      * test that intl functions work in a multithreaded context
@@ -49,7 +45,6 @@
     void TestCollators(void);
     void TestString();
     void TestAnyTranslit();
-    void TestConditionVariables();
     void TestUnifiedCache();
     void TestBreakTranslit();
     void TestIncDec();