addressed issue 53
This commit is contained in:
parent
b0443680c6
commit
a6d5daed0e
17
README.md
17
README.md
@ -11,7 +11,7 @@ Read this documentation to get an overview of MBassadors features. There is also
|
|||||||
not enough to make a developer happy (work is in progress). But usage of publish subscribe pattern at its core is pretty straight forward and the basic
|
not enough to make a developer happy (work is in progress). But usage of publish subscribe pattern at its core is pretty straight forward and the basic
|
||||||
use cases are very easy to understand and implement.
|
use cases are very easy to understand and implement.
|
||||||
|
|
||||||
The current version is 1.1.7 and it is available from the Maven Central Repository. See the release notes for more details.
|
The current version is 1.1.8 and it is available from the Maven Central Repository. See the release notes for more details.
|
||||||
|
|
||||||
There is also an extension available to support CDI-like transactional message sending in a Spring environment. It's beta but
|
There is also an extension available to support CDI-like transactional message sending in a Spring environment. It's beta but
|
||||||
stable enough to give it a try. See <a href="https://github.com/bennidi/mbassador-spring" target="_blank">here</a>.
|
stable enough to give it a try. See <a href="https://github.com/bennidi/mbassador-spring" target="_blank">here</a>.
|
||||||
@ -157,6 +157,14 @@ to avoid confusion and misunderstanding.
|
|||||||
|
|
||||||
<h2>Release Notes</h2>
|
<h2>Release Notes</h2>
|
||||||
|
|
||||||
|
<h3>1.1.8</h3>
|
||||||
|
|
||||||
|
+ Internal refactorings and code improvements
|
||||||
|
+ Fixed #44 #45 #47
|
||||||
|
+ NOTE: This release has a known issue with weak references which introduces a memory leak. A fix is on its way for 1.1.9
|
||||||
|
to be released soon
|
||||||
|
|
||||||
|
|
||||||
<h3>1.1.7</h3>
|
<h3>1.1.7</h3>
|
||||||
|
|
||||||
+ Console Logger not added to message bus instances by default -> use addErrorHandler(IPublicationErrorHandler.ConsoleLogger)
|
+ Console Logger not added to message bus instances by default -> use addErrorHandler(IPublicationErrorHandler.ConsoleLogger)
|
||||||
@ -224,7 +232,12 @@ First stable release!
|
|||||||
|
|
||||||
|
|
||||||
<h2>Roadmap</h2>
|
<h2>Roadmap</h2>
|
||||||
+ Spring integration with support for conditional message dispatch in transactional context (dispatch only after
|
Check the issues marked with label enhancement. Comment if you would like to see the feature in a future release.
|
||||||
|
Please understand that I have limited time to include new features and that I will focus on stability and cleaner APIs.
|
||||||
|
Adding features only works well with well designed and thoroughly tested components especially with all this multi-threaded code
|
||||||
|
and I am still not 100 percent happy with the existing test coverage.
|
||||||
|
|
||||||
|
Planned for release:Spring integration with support for conditional message dispatch in transactional context (dispatch only after
|
||||||
successful commit etc.). Currently in beta, see <a href="https://github.com/bennidi/mbassador-spring">this</a> repository
|
successful commit etc.). Currently in beta, see <a href="https://github.com/bennidi/mbassador-spring">this</a> repository
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|||||||
public abstract class AbstractConcurrentSet<T> implements IConcurrentSet<T> {
|
public abstract class AbstractConcurrentSet<T> implements IConcurrentSet<T> {
|
||||||
|
|
||||||
// Internal state
|
// Internal state
|
||||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
protected final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||||
private final Map<T, ISetEntry<T>> entries; // maintain a map of entries for O(log n) lookup
|
private final Map<T, ISetEntry<T>> entries; // maintain a map of entries for O(log n) lookup
|
||||||
protected Entry<T> head; // reference to the first element
|
protected Entry<T> head; // reference to the first element
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ package net.engio.mbassy.common;
|
|||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This implementation uses weak references to the elements. Iterators automatically perform cleanups of
|
* This implementation uses weak references to the elements. Iterators automatically perform cleanups of
|
||||||
@ -25,15 +26,36 @@ public class WeakConcurrentSet<T> extends AbstractConcurrentSet<T>{
|
|||||||
public Iterator<T> iterator() {
|
public Iterator<T> iterator() {
|
||||||
return new Iterator<T>() {
|
return new Iterator<T>() {
|
||||||
|
|
||||||
|
// the current listelement of this iterator
|
||||||
|
// used to keep track of the iteration process
|
||||||
private ISetEntry<T> current = head;
|
private ISetEntry<T> current = head;
|
||||||
|
|
||||||
|
// this method will remove all orphaned entries
|
||||||
|
// until it finds the first entry whose value has not yet been garbage collected
|
||||||
|
// the method assumes that the current element is already orphaned and will remove it
|
||||||
|
private void removeOrphans(){
|
||||||
|
Lock writelock = lock.writeLock();
|
||||||
|
try{
|
||||||
|
writelock.lock();
|
||||||
|
do {
|
||||||
|
ISetEntry orphaned = current;
|
||||||
|
current = current.next();
|
||||||
|
orphaned.remove();
|
||||||
|
} while(current != null && current.getValue() == null);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
writelock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
if (current == null) return false;
|
if (current == null) return false;
|
||||||
if (current.getValue() == null) { // auto-removal of orphan references
|
if (current.getValue() == null) {
|
||||||
do {
|
// trigger removal of orphan references
|
||||||
remove();
|
// because a null value indicates that the value has been garbage collected
|
||||||
} while(current != null && current.getValue() == null);
|
removeOrphans();
|
||||||
return hasNext();
|
return current != null; // if any entry is left then it will have a value
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -45,9 +67,7 @@ public class WeakConcurrentSet<T> extends AbstractConcurrentSet<T>{
|
|||||||
}
|
}
|
||||||
T value = current.getValue();
|
T value = current.getValue();
|
||||||
if (value == null) { // auto-removal of orphan references
|
if (value == null) { // auto-removal of orphan references
|
||||||
do {
|
removeOrphans();
|
||||||
remove();
|
|
||||||
} while(current != null && current.getValue() == null);
|
|
||||||
return next();
|
return next();
|
||||||
} else {
|
} else {
|
||||||
current = current.next();
|
current = current.next();
|
||||||
@ -56,6 +76,7 @@ public class WeakConcurrentSet<T> extends AbstractConcurrentSet<T>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void remove() {
|
public void remove() {
|
||||||
|
//throw new UnsupportedOperationException("Explicit removal of set elements is only allowed via the controlling set. Sorry!");
|
||||||
if (current == null) {
|
if (current == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user