From 05be60b155047ed686c1074c39f41c258ac47326 Mon Sep 17 00:00:00 2001 From: shuyangzhou Date: Fri, 1 Jul 2016 15:28:49 -0700 Subject: LPS-66959 Use ReadWriteLock to optimzie reading paths in addReference()/removeReference(), when concurrent destroy() happens in between the addReference()/removeReference() window times, upgrade to write lock to ensure proper Condition waiting. Signed-off-by: shuyangzhou --- .../internal/registration/Registration.java | 77 +++++++++++++++++----- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/Registration.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/Registration.java index 0df5d73a0..4e3e612f8 100644 --- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/Registration.java +++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/registration/Registration.java @@ -12,6 +12,11 @@ *******************************************************************************/ package org.eclipse.equinox.http.servlet.internal.registration; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import org.osgi.dto.DTO; public abstract class Registration { @@ -19,42 +24,82 @@ public abstract class Registration { private final D d; private final T t; - protected int referenceCount; + protected final AtomicInteger referenceCount = new AtomicInteger(); public Registration(T t, D d) { this.t = t; this.d = d; } - public synchronized void addReference() { - ++referenceCount; + public void addReference() { + readLock.lock(); + + try { + referenceCount.incrementAndGet(); + } + finally { + readLock.unlock(); + } } - public synchronized void removeReference() { - --referenceCount; - if (referenceCount == 0) { - notifyAll(); + public void removeReference() { + readLock.lock(); + + try { + if (referenceCount.decrementAndGet() == 0 && destroyed) { + readLock.unlock(); + + writeLock.lock(); + + try { + condition.signalAll(); + } + finally { + writeLock.unlock(); + + readLock.lock(); + } + } + } + finally { + readLock.unlock(); } } - public synchronized void destroy() { + public void destroy() { boolean interrupted = false; + + writeLock.lock(); + + destroyed = true; + try { - while (referenceCount != 0) { + while (referenceCount.get() != 0) { try { - (new Exception()).printStackTrace(); - wait(); - } catch (InterruptedException e) { - // wait until the servlet is inactive but save the interrupted status + condition.await(); + } + catch (InterruptedException ie) { interrupted = true; } } - } finally { - if (interrupted) - Thread.currentThread().interrupt(); //restore the interrupted state + } + finally { + writeLock.unlock(); + + if (interrupted) { + Thread.currentThread().interrupt(); + } } } + private volatile boolean destroyed; + + private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); + + private final Lock readLock = readWriteLock.readLock(); + private final Lock writeLock = readWriteLock.writeLock(); + private final Condition condition = writeLock.newCondition(); + public D getD() { return d; } -- cgit v1.2.3