Improve EventBus by removing read locking.

This is primarily done by using ConcurrentHashMap, which has lock-free reads and thread-contention-based writes. Only one thread at a time can register threads, however, as baking events isn't thread safe (and there's no reason to make it thread-safe anyway).

My own benchmarks indicate 1.4-2.2 million operations/ms throughput and approximately ~1ns/event post for four threads posting events.
This commit is contained in:
Tux 2015-09-04 22:44:54 -04:00 committed by md_5
parent bd07be8772
commit 59208aad86

View File

@ -9,8 +9,9 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -18,8 +19,8 @@ public class EventBus
{
private final Map<Class<?>, Map<Byte, Map<Object, Method[]>>> byListenerAndPriority = new HashMap<>();
private final Map<Class<?>, EventHandlerMethod[]> byEventBaked = new HashMap<>();
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Map<Class<?>, EventHandlerMethod[]> byEventBaked = new ConcurrentHashMap<>();
private final Lock lock = new ReentrantLock();
private final Logger logger;
public EventBus()
@ -34,15 +35,7 @@ public class EventBus
public void post(Object event)
{
EventHandlerMethod[] handlers;
lock.readLock().lock();
try
{
handlers = byEventBaked.get( event.getClass() );
} finally
{
lock.readLock().unlock();
}
EventHandlerMethod[] handlers = byEventBaked.get( event.getClass() );
if ( handlers != null )
{
@ -103,7 +96,7 @@ public class EventBus
public void register(Object listener)
{
Map<Class<?>, Map<Byte, Set<Method>>> handler = findHandlers( listener );
lock.writeLock().lock();
lock.lock();
try
{
for ( Map.Entry<Class<?>, Map<Byte, Set<Method>>> e : handler.entrySet() )
@ -129,14 +122,14 @@ public class EventBus
}
} finally
{
lock.writeLock().unlock();
lock.unlock();
}
}
public void unregister(Object listener)
{
Map<Class<?>, Map<Byte, Set<Method>>> handler = findHandlers( listener );
lock.writeLock().lock();
lock.lock();
try
{
for ( Map.Entry<Class<?>, Map<Byte, Set<Method>>> e : handler.entrySet() )
@ -165,7 +158,7 @@ public class EventBus
}
} finally
{
lock.writeLock().unlock();
lock.unlock();
}
}
@ -202,7 +195,7 @@ public class EventBus
byEventBaked.put( eventClass, handlersList.toArray( new EventHandlerMethod[ handlersList.size() ] ) );
} else
{
byEventBaked.put( eventClass, null );
byEventBaked.remove( eventClass );
}
}
}