SLING-2535 Undid my previous commit and put the synchronisation one layer further out as orriginally suggested. Synchronising in incUsage and decUsage is too risky from a deadlock point of view. Added Javadoc to warn about thread safety on the methods.
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1404430 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/sling/commons/threads/impl/DefaultThreadPoolManager.java b/src/main/java/org/apache/sling/commons/threads/impl/DefaultThreadPoolManager.java
index 65f3059..024b2e6 100644
--- a/src/main/java/org/apache/sling/commons/threads/impl/DefaultThreadPoolManager.java
+++ b/src/main/java/org/apache/sling/commons/threads/impl/DefaultThreadPoolManager.java
@@ -126,6 +126,7 @@
final String poolName = (name == null ? DEFAULT_THREADPOOL_NAME : name);
Entry entry = null;
boolean created = false;
+ ThreadPool threadPool = null;
synchronized (this.pools) {
entry = this.pools.get(poolName);
if ( entry == null ) {
@@ -136,11 +137,12 @@
this.pools.put(poolName, entry);
}
+ threadPool = entry.incUsage();
}
if (created) {
entry.registerMBean();
}
- return entry.incUsage();
+ return threadPool;
}
/**
@@ -193,11 +195,13 @@
final String name = "ThreadPool-" + UUID.randomUUID().toString() +
(label == null ? "" : " (" + label + ")");
final Entry entry = new Entry(null, config, name, bundleContext);
+ ThreadPool threadPool = null;
synchronized ( this.pools ) {
this.pools.put(name, entry);
+ threadPool = entry.incUsage();
}
entry.registerMBean();
- return entry.incUsage();
+ return threadPool;
}
/**
@@ -342,22 +346,30 @@
}
}
+ /**
+ * Increments a usage counter and gets the ThreadPoolFacade inside the Entry.
+ * Note this method is not thread safe and must at all time be protected from
+ * multiple threads accessing it at the same time. The counter is volatile and
+ * hence not atomic in updates.
+ * @return the thread pool Facade instance after reference counting the usage.
+ */
public ThreadPoolFacade incUsage() {
- synchronized (usagelock) {
- if ( pool == null ) {
- pool = new ThreadPoolFacade(new DefaultThreadPool(name, this.config));
- }
- this.count++;
- return pool;
+ if ( pool == null ) {
+ pool = new ThreadPoolFacade(new DefaultThreadPool(name, this.config));
}
+ this.count++;
+ return pool;
}
+ /**
+ * Decrement the usage counter, and if its zero initiate a shutdown the entry (and the thread pool).
+ * Note: this method is not thread safe and must at all time be protected from multiple threads
+ * accessing it at the same time. The counter is volatile and hence not atomic in updates.
+ */
public void decUsage() {
- synchronized (usagelock) {
- this.count--;
- if ( this.count == 0 ) {
- this.shutdown();
- }
+ this.count--;
+ if ( this.count == 0 ) {
+ this.shutdown();
}
}