ICU-10097 Replace ICURWLock implementation with JDK's ReentrantReadWriteLock. At the same time, disabled the stats collection (never used by ICU library consumers) by default.

X-SVN-Rev: 33543
This commit is contained in:
Yoshito Umaoka 2013-04-22 21:04:37 +00:00
parent 4524c8c33d
commit 10f1e3259e
4 changed files with 43 additions and 137 deletions

View 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();
}
}

View 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();

View 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());
}

View 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();