Test deadlock between java.util and ICU TimeZone.

This commit adds a test for a deadlock between java.util.TimeZone and
android.icu.util.TimeZome.

The fix and a detailed description can be found in change
I9b241d5f49ab4b6747ba73deb94a92ee1b7480fa in external/icu.

Bug: 30937209
Test: libcore/run-libcore-tests libcore.java.util
   org.apache.harmony.tests.java.util

(cherry picked from commit 3d13ad929fd58e280a6e5a8517fc6d314cedad56)

Change-Id: I630dde9bf6e54cf7e8688f9e23a051598bd601a0
diff --git a/luni/src/test/java/libcore/java/util/TimeZoneTest.java b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
index 5a6fa7f..2dd0bb5 100644
--- a/luni/src/test/java/libcore/java/util/TimeZoneTest.java
+++ b/luni/src/test/java/libcore/java/util/TimeZoneTest.java
@@ -16,13 +16,17 @@
 
 package libcore.java.util;
 
+import junit.framework.TestCase;
+
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.Locale;
 import java.util.SimpleTimeZone;
 import java.util.TimeZone;
-import junit.framework.TestCase;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class TimeZoneTest extends TestCase {
     // http://code.google.com/p/android/issues/detail?id=877
@@ -340,4 +344,59 @@
             TimeZone.setDefault(origTz);
         }
     }
+
+    // http://b/30937209
+    public void testSetDefaultDeadlock() throws InterruptedException, BrokenBarrierException {
+        // Since this tests a deadlock, the test has two fundamental problems:
+        // - it is probabilistic: it's not guaranteed to fail if the problem exists
+        // - if it fails, it will effectively hang the current runtime, as no other thread will
+        //   be able to call TimeZone.getDefault()/setDefault() successfully any more.
+
+        // 10 was too low to be reliable, 100 failed more than half the time (on a bullhead).
+        final int iterations = 100;
+        TimeZone otherTimeZone = TimeZone.getTimeZone("Europe/London");
+        AtomicInteger setterCount = new AtomicInteger();
+        CyclicBarrier startBarrier = new CyclicBarrier(2);
+        Thread setter = new Thread(() -> {
+            waitFor(startBarrier);
+            for (int i = 0; i < iterations; i++) {
+                TimeZone.setDefault(otherTimeZone);
+                TimeZone.setDefault(null);
+                setterCount.set(i+1);
+            }
+        });
+        setter.setName("testSetDefaultDeadlock setter");
+
+        AtomicInteger getterCount = new AtomicInteger();
+        Thread getter = new Thread(() -> {
+            waitFor(startBarrier);
+            for (int i = 0; i < iterations; i++) {
+                android.icu.util.TimeZone.getDefault();
+                getterCount.set(i+1);
+            }
+        });
+        getter.setName("testSetDefaultDeadlock getter");
+
+        setter.start();
+        getter.start();
+
+        // 2 seconds is plenty: If successful, we usually complete much faster.
+        setter.join(1000);
+        getter.join(1000);
+        if (setter.isAlive() || getter.isAlive()) {
+            fail("Threads are still alive. Getter iteration count: " + getterCount.get()
+                    + ", setter iteration count: " + setterCount.get());
+        }
+        // Guard against unexpected uncaught exceptions.
+        assertEquals("Setter iterations", iterations, setterCount.get());
+        assertEquals("Getter iterations", iterations, getterCount.get());
+    }
+
+    private static void waitFor(CyclicBarrier barrier) {
+        try {
+            barrier.await();
+        } catch (InterruptedException | BrokenBarrierException e) {
+            throw new RuntimeException(e);
+        }
+    }
 }