diff --git a/src/dorkbox/messagebus/subscription/Subscription.java b/src/dorkbox/messagebus/subscription/Subscription.java index 9958361..5fd597a 100644 --- a/src/dorkbox/messagebus/subscription/Subscription.java +++ b/src/dorkbox/messagebus/subscription/Subscription.java @@ -66,7 +66,10 @@ class Subscription { this.entries = new IdentityMap(32, SubscriptionManager.LOAD_FACTOR); } - // called on shutdown for GC purposes + /** + * called on shutdown for GC purposes + * called within SYNCHRONIZE + */ public final void clear() { this.entries.clear(); diff --git a/src/dorkbox/messagebus/subscription/SubscriptionManager.java b/src/dorkbox/messagebus/subscription/SubscriptionManager.java index 2024df2..052d7b2 100644 --- a/src/dorkbox/messagebus/subscription/SubscriptionManager.java +++ b/src/dorkbox/messagebus/subscription/SubscriptionManager.java @@ -17,11 +17,11 @@ package dorkbox.messagebus.subscription; import com.esotericsoftware.kryo.util.IdentityMap; import dorkbox.messagebus.MessageBus; -import dorkbox.messagebus.common.MultiClass; -import dorkbox.messagebus.subscription.reflection.ReflectionFactory; import dorkbox.messagebus.common.ClassTree; import dorkbox.messagebus.common.MessageHandler; +import dorkbox.messagebus.common.MultiClass; import dorkbox.messagebus.subscription.asm.AsmFactory; +import dorkbox.messagebus.subscription.reflection.ReflectionFactory; import dorkbox.messagebus.util.ClassUtils; import java.util.ArrayList; @@ -134,16 +134,21 @@ class SubscriptionManager { public void shutdown() { - // explicitly clear out the subscriptions - final IdentityMap.Entries, Subscription[]> entries = subsPerListener.entries(); - for (IdentityMap.Entry, Subscription[]> entry : entries) { - final Subscription[] subscriptions = entry.value; - if (subscriptions != null) { - Subscription subscription; + // synchronized is used here to ensure the "single writer principle", and make sure that ONLY one thread at a time can enter this + // section. Because of this, we can have unlimited reader threads all going at the same time, without contention (which is our + // use-case 99% of the time) + synchronized (singleWriterLock) { + // explicitly clear out the subscriptions + final IdentityMap.Entries, Subscription[]> entries = subsPerListener.entries(); + for (IdentityMap.Entry, Subscription[]> entry : entries) { + final Subscription[] subscriptions = entry.value; + if (subscriptions != null) { + Subscription subscription; - for (int i = 0; i < subscriptions.length; i++) { - subscription = subscriptions[i]; - subscription.clear(); + for (int i = 0; i < subscriptions.length; i++) { + subscription = subscriptions[i]; + subscription.clear(); + } } } }