Use an atomic reference array instead of ConcurrentHashMap for listeners

This commit is contained in:
Kristian S. Stangeland 2013-03-12 02:33:35 +01:00
parent e3cfa45607
commit ed9b61fd11
3 changed files with 31 additions and 17 deletions

View File

@ -23,6 +23,7 @@ import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.Semaphore;
import com.comphenix.protocol.Packets;
import com.comphenix.protocol.concurrency.AbstractConcurrentListenerMultimap;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.PrioritizedListener;
@ -66,7 +67,7 @@ class PacketProcessingQueue extends AbstractConcurrentListenerMultimap<AsyncList
}
public PacketProcessingQueue(PlayerSendingHandler sendingHandler, int initialSize, int maximumSize, int maximumConcurrency) {
super();
super(Packets.MAXIMUM_PACKET_ID);
try {
this.processingQueue = Synchronization.queue(MinMaxPriorityQueue.

View File

@ -23,6 +23,7 @@ import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReferenceArray;
import com.comphenix.protocol.events.ListeningWhitelist;
import com.comphenix.protocol.injector.PrioritizedListener;
@ -35,8 +36,13 @@ import com.google.common.collect.Iterables;
*/
public abstract class AbstractConcurrentListenerMultimap<TListener> {
// The core of our map
private ConcurrentMap<Integer, SortedCopyOnWriteArray<PrioritizedListener<TListener>>> listeners =
new ConcurrentHashMap<Integer, SortedCopyOnWriteArray<PrioritizedListener<TListener>>>();
private AtomicReferenceArray<SortedCopyOnWriteArray<PrioritizedListener<TListener>>> arrayListeners;
private ConcurrentMap<Integer, SortedCopyOnWriteArray<PrioritizedListener<TListener>>> mapListeners;
public AbstractConcurrentListenerMultimap(int maximumPacketID) {
arrayListeners = new AtomicReferenceArray<SortedCopyOnWriteArray<PrioritizedListener<TListener>>>(maximumPacketID + 1);
mapListeners = new ConcurrentHashMap<Integer, SortedCopyOnWriteArray<PrioritizedListener<TListener>>>();
}
/**
* Adds a listener to its requested list of packet recievers.
@ -53,7 +59,7 @@ public abstract class AbstractConcurrentListenerMultimap<TListener> {
// Add the listener to a specific packet notifcation list
private void addListener(Integer packetID, PrioritizedListener<TListener> listener) {
SortedCopyOnWriteArray<PrioritizedListener<TListener>> list = listeners.get(packetID);
SortedCopyOnWriteArray<PrioritizedListener<TListener>> list = arrayListeners.get(packetID);
// We don't want to create this for every lookup
if (list == null) {
@ -61,12 +67,12 @@ public abstract class AbstractConcurrentListenerMultimap<TListener> {
// which is a essential feature for our purposes.
final SortedCopyOnWriteArray<PrioritizedListener<TListener>> value = new SortedCopyOnWriteArray<PrioritizedListener<TListener>>();
list = listeners.putIfAbsent(packetID, value);
// We may end up creating multiple multisets, but we'll agree
// on the one to use.
if (list == null) {
// We may end up creating multiple multisets, but we'll agree on which to use
if (arrayListeners.compareAndSet(packetID, null, value)) {
mapListeners.put(packetID, value);
list = value;
} else {
list = arrayListeners.get(packetID);
}
}
@ -85,8 +91,7 @@ public abstract class AbstractConcurrentListenerMultimap<TListener> {
// Again, not terribly efficient. But adding or removing listeners should be a rare event.
for (Integer packetID : whitelist.getWhitelist()) {
SortedCopyOnWriteArray<PrioritizedListener<TListener>> list = listeners.get(packetID);
SortedCopyOnWriteArray<PrioritizedListener<TListener>> list = arrayListeners.get(packetID);
// Remove any listeners
if (list != null) {
@ -96,7 +101,8 @@ public abstract class AbstractConcurrentListenerMultimap<TListener> {
list.remove(new PrioritizedListener<TListener>(listener, whitelist.getPriority()));
if (list.size() == 0) {
listeners.remove(packetID);
arrayListeners.set(packetID, null);
mapListeners.remove(packetID);
removedPackets.add(packetID);
}
}
@ -116,7 +122,7 @@ public abstract class AbstractConcurrentListenerMultimap<TListener> {
* @return Registered listeners.
*/
public Collection<PrioritizedListener<TListener>> getListener(int packetID) {
return listeners.get(packetID);
return arrayListeners.get(packetID);
}
/**
@ -124,7 +130,7 @@ public abstract class AbstractConcurrentListenerMultimap<TListener> {
* @return Every listener.
*/
public Iterable<PrioritizedListener<TListener>> values() {
return Iterables.concat(listeners.values());
return Iterables.concat(mapListeners.values());
}
/**
@ -132,13 +138,15 @@ public abstract class AbstractConcurrentListenerMultimap<TListener> {
* @return Registered packet ID.
*/
public Set<Integer> keySet() {
return listeners.keySet();
return mapListeners.keySet();
}
/**
* Remove all packet listeners.
*/
protected void clearListeners() {
listeners.clear();
arrayListeners = new AtomicReferenceArray<
SortedCopyOnWriteArray<PrioritizedListener<TListener>>>(arrayListeners.length());
mapListeners.clear();
}
}

View File

@ -19,6 +19,7 @@ package com.comphenix.protocol.injector;
import java.util.Collection;
import com.comphenix.protocol.Packets;
import com.comphenix.protocol.concurrency.AbstractConcurrentListenerMultimap;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.events.ListenerPriority;
@ -31,6 +32,10 @@ import com.comphenix.protocol.events.PacketListener;
* @author Kristian
*/
public final class SortedPacketListenerList extends AbstractConcurrentListenerMultimap<PacketListener> {
public SortedPacketListenerList() {
super(Packets.MAXIMUM_PACKET_ID);
}
/**
* Invokes the given packet event for every registered listener.
* @param reporter - the error reporter that will be used to inform about listener exceptions.