]> granicus.if.org Git - icu/commitdiff
ICU-10097 Replace ICURWLock implementation with JDK's ReentrantReadWriteLock. At...
authorYoshito Umaoka <y.umaoka@gmail.com>
Mon, 22 Apr 2013 21:04:37 +0000 (21:04 +0000)
committerYoshito Umaoka <y.umaoka@gmail.com>
Mon, 22 Apr 2013 21:04:37 +0000 (21:04 +0000)
X-SVN-Rev: 33543

icu4j/main/classes/core/src/com/ibm/icu/impl/ICURWLock.java
icu4j/main/classes/core/src/com/ibm/icu/impl/ICUService.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/ICUServiceTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/ICUServiceThreadTest.java

index ec1507089836f969ae137d1448d6ee6def5e2a0b..9f2e79dacb0ff0b6af59c3eb8d0b2c7d73054b75 100644 (file)
@@ -1,19 +1,23 @@
 /**
  *******************************************************************************
- * Copyright (C) 2001-2006, International Business Machines Corporation and    *
+ * Copyright (C) 2001-2013, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
 package com.ibm.icu.impl;
 
-// See Allan Holub's 1999 column in JavaWorld, and Doug Lea's code for RWLocks with writer preference.
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 
 /**
- * <p>A simple Reader/Writer lock.  This assumes that there will
- * be little writing contention.  It also doesn't allow 
- * active readers to acquire and release a write lock, or
- * deal with priority inversion issues.</p>
+ * <p>A Reader/Writer lock originally written for ICU service
+ * implementation. The internal implementation was replaced
+ * with the JDK's stock read write lock (ReentrantReadWriteLock)
+ * for ICU 52.</p>
+ *
+ * <p>This assumes that there will be little writing contention.
+ * It also doesn't allow active readers to acquire and release
+ * a write lock, or deal with priority inversion issues.</p>
  *
  * <p>Access to the lock should be enclosed in a try/finally block
  * in order to ensure that the lock is always released in case of
@@ -31,13 +35,9 @@ package com.ibm.icu.impl;
  * to return statistics on the use of the lock.</p>
  */
 public class ICURWLock {
-    private Object writeLock = new Object();
-    private Object readLock = new Object();
-    private int wwc; // waiting writers
-    private int rc; // active readers, -1 if there's an active writer
-    private int wrc; // waiting readers
+    private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
 
-    private Stats stats = new Stats(); // maybe don't init to start...
+    private Stats stats = null;
 
     /**
      * Internal class used to gather statistics on the RWLock.
@@ -120,84 +120,6 @@ public class ICURWLock {
         return stats == null ? null : new Stats(stats);
     }
 
-    // utilities
-
-    private synchronized boolean gotRead() {
-        ++rc;
-        if (stats != null) {
-            ++stats._rc;
-            if (rc > 1) ++stats._mrc;
-        }
-        return true;
-    }
-
-    private synchronized boolean getRead() {
-        if (rc >= 0 && wwc == 0) {
-            return gotRead();
-        }
-        ++wrc;
-        return false;
-    }
-
-    private synchronized boolean retryRead() {
-        if (stats != null) ++stats._wrc;
-        if (rc >= 0 && wwc == 0) {
-            --wrc;
-            return gotRead();
-        }
-        return false;
-    }
-
-    private synchronized boolean finishRead() {
-        if (rc > 0) {
-            return (0 == --rc && wwc > 0);
-        }
-        throw new IllegalStateException("no current reader to release");
-    }
-    
-    private synchronized boolean gotWrite() {
-        rc = -1;
-        if (stats != null) {
-            ++stats._wc;
-        }
-        return true;
-    }
-
-    private synchronized boolean getWrite() {
-        if (rc == 0) {
-            return gotWrite();
-        }
-        ++wwc;
-        return false;
-    }
-
-    private synchronized boolean retryWrite() {
-        if (stats != null) ++stats._wwc;
-        if (rc == 0) {
-            --wwc;
-            return gotWrite();
-        }
-        return false;
-    }
-
-    private static final int NOTIFY_NONE = 0;
-    private static final int NOTIFY_WRITERS = 1;
-    private static final int NOTIFY_READERS = 2;
-
-    private synchronized int finishWrite() {
-        if (rc < 0) {
-            rc = 0;
-            if (wwc > 0) {
-                return NOTIFY_WRITERS;
-            } else if (wrc > 0) {
-                return NOTIFY_READERS;
-            } else {
-                return NOTIFY_NONE;
-            }
-        }
-        throw new IllegalStateException("no current writer to release");
-    }
-    
     /**
      * <p>Acquire a read lock, blocking until a read lock is
      * available.  Multiple readers can concurrently hold the read
@@ -209,20 +131,18 @@ public class ICURWLock {
      * releaseRead when done (for example, in a finally block).</p> 
      */
     public void acquireRead() {
-        if (!getRead()) {
-            for (;;) {
-                try {
-                    synchronized (readLock) {
-                        readLock.wait();
-                    }
-                    if (retryRead()) {
-                        return;
-                    }
+        if (stats != null) {    // stats is null by default
+            synchronized (this) {
+                stats._rc++;
+                if (rwl.getReadLockCount() > 0) {
+                    stats._mrc++;
                 }
-                catch (InterruptedException e) {
+                if (rwl.isWriteLocked()) {
+                    stats._wrc++;
                 }
             }
         }
+        rwl.readLock().lock();
     }
 
     /**
@@ -234,11 +154,7 @@ public class ICURWLock {
      * controlled by acquireRead.</p>
      */
     public void releaseRead() {
-        if (finishRead()) {
-            synchronized (writeLock) {
-                writeLock.notify();
-            }
-        }
+        rwl.readLock().unlock();
     }
 
     /**
@@ -253,20 +169,15 @@ public class ICURWLock {
      * block).<p> 
      */
     public void acquireWrite() {
-        if (!getWrite()) {
-            for (;;) {
-                try {
-                    synchronized (writeLock) {
-                        writeLock.wait();
-                    }
-                    if (retryWrite()) {
-                        return;
-                    }
-                }
-                catch (InterruptedException e) {
+        if (stats != null) {    // stats is null by default
+            synchronized (this) {
+                stats._wc++;
+                if (rwl.getReadLockCount() > 0 || rwl.isWriteLocked()) {
+                    stats._wwc++;
                 }
             }
         }
+        rwl.writeLock().lock();
     }
 
     /**
@@ -279,19 +190,6 @@ public class ICURWLock {
      * acquireWrite.</p> 
      */
     public void releaseWrite() {
-        switch (finishWrite()) {
-        case NOTIFY_WRITERS:
-            synchronized (writeLock) {
-                writeLock.notify();
-            }
-            break;
-        case NOTIFY_READERS:
-            synchronized (readLock) {
-                readLock.notifyAll();
-            }
-            break;
-        case NOTIFY_NONE:
-            break;
-        }
+        rwl.writeLock().unlock();
     }
 }
index 486a06bfe31d5e2bb13e3ca3b62ba928a76dace6..99fc9280bee7717e322e9b91b58b9342814e87f7 100644 (file)
@@ -1,6 +1,6 @@
 /**
  *******************************************************************************
- * Copyright (C) 2001-2011, International Business Machines Corporation and    *
+ * Copyright (C) 2001-2013, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -959,8 +959,10 @@ public class ICUService extends ICUNotifier {
     }
 
     /**
-     * Return a string describing the statistics for this service.
-     * This also resets the statistics. Used for debugging purposes.
+     * When the statistics for this service is already enabled,
+     * return the log and resets he statistics.
+     * When the statistics is not enabled, this method enable
+     * the statistics. Used for debugging purposes.
      */
     public String stats() {
         ICURWLock.Stats stats = factoryLock.resetStats();
index f50e50c5f978f6f3f4c9f7aadc53eda731c671a0..e6295d535d21c0fd078e5267dd1893f3dbcb36fc 100644 (file)
@@ -1,6 +1,6 @@
 /**
  *******************************************************************************
- * Copyright (C) 2001-2010, International Business Machines Corporation and    *
+ * Copyright (C) 2001-2013, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -879,6 +879,8 @@ public class ICUServiceTest extends TestFmwk
     // ICURWLock
 
     ICURWLock rwlock = new ICURWLock();
+    rwlock.resetStats();
+
     rwlock.acquireRead();
     rwlock.releaseRead();
 
@@ -896,7 +898,7 @@ public class ICUServiceTest extends TestFmwk
         rwlock.releaseRead();
         errln("no error thrown");
     }
-    catch (IllegalStateException e) {
+    catch (Exception e) {
         logln("OK: " + e.getMessage());
     }
 
@@ -904,7 +906,7 @@ public class ICUServiceTest extends TestFmwk
         rwlock.releaseWrite();
         errln("no error thrown");
     }
-    catch (IllegalStateException e) {
+    catch (Exception e) {
         logln("OK: " + e.getMessage());
     }
 
index 161e08d370c55cf1930823bb05f51587fa380492..e984dca7ae06704b0db27c377ea79fbc0e95b716 100644 (file)
@@ -1,6 +1,6 @@
 /**
  *******************************************************************************
- * Copyright (C) 2001-2010, International Business Machines Corporation and    *
+ * Copyright (C) 2001-2013, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -371,6 +371,7 @@ public class ICUServiceThreadTest extends TestFmwk
             stableService = new ICULocaleService();
             registerFactories(stableService, getFactoryCollection(50));
         }
+        if (PRINTSTATS) stableService.stats();  // Enable the stats collection
         return stableService;
     }
     private ICUService stableService;
@@ -413,6 +414,7 @@ public class ICUServiceThreadTest extends TestFmwk
     // run register/unregister on a service
     public void Test03_ConcurrentRegUnreg() {
         ICUService service = new ICULocaleService();
+        if (PRINTSTATS) service.stats();    // Enable the stats collection
         for (int i = 0; i < 5; ++i) {
             new RegisterFactoryThread("[" + i + "]", service, 0, this).start();
         }
@@ -425,6 +427,7 @@ public class ICUServiceThreadTest extends TestFmwk
 
     public void Test04_WitheringService() {
         ICUService service = new ICULocaleService();
+        if (PRINTSTATS) service.stats();    // Enable the stats collection
 
         Collection fc = getFactoryCollection(50);
         registerFactories(service, fc);
@@ -452,6 +455,7 @@ public class ICUServiceThreadTest extends TestFmwk
     // run for ten seconds
     public void Test05_ConcurrentEverything() {
         ICUService service = new ICULocaleService();
+        if (PRINTSTATS) service.stats();    // Enable the stats collection
 
         new RegisterFactoryThread("", service, 500, this).start();