私たちのレガシーアプリはEventListeners
、最も単純な操作でとんでもない数(〜100,000)を含むひどいフレームワーク(タペストリー4です)で立ち往生しています。私は、これはjavax.swing.event.EventListenerList
これまで処理することを意図していたものを超えていると推測しています.
HashMap/ArrayList
以下のかなり素朴なベースの置換を作成するのに数時間を費やしましたが、ほぼすべての点で非常に高速です。
50,000 人のリスナーを追加します。
EventListenerList
> 2 秒EventListenerMap
〜 3.5 ミリ秒
50,000 人のリスナーに対してイベントを発生させる:
EventListenerList
0.3~0.5ミリ秒EventListenerMap
0.4~0.5ミリ秒
50,000 人のリスナーを削除します (一度に 1 人ずつ):
EventListenerList
> 2 秒EventListenerMap
~280 ミリ秒
発砲はわずかに遅いかもしれませんが、変更は非常に高速です。確かに、このフレームワークが私たちを陥れた状況は病的なものですが、それでもEventListenerList
ずっと前に置き換えられた可能性があるように思えます. パブリック API には明らかに問題があります (たとえば、生の内部状態配列を公開するなど) が、それ以上の問題があるはずです。たぶん、EventListenerList
はるかに安全またはパフォーマンスの高いマルチスレッドのケースがあるでしょうか?
public class EventListenerMap
{
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();
private Map<Class, List> llMap = new HashMap<Class, List>();
public <L extends EventListener> void add ( Class<L> listenerClass, L listener )
{
try
{
writeLock.lock();
List<L> list = getListenerList( listenerClass );
if ( list == null )
{
list = new ArrayList<L>();
llMap.put( listenerClass, list );
}
list.add( listener );
}
finally
{
writeLock.unlock();
}
}
public <L extends EventListener> void remove ( Class<L> listenerClass, L listener )
{
try
{
writeLock.lock();
List<L> list = getListenerList( listenerClass );
if ( list != null )
{
list.remove( listener );
}
}
finally
{
writeLock.unlock();
}
}
@SuppressWarnings("unchecked")
public <L extends EventListener> L[] getListeners ( Class<L> listenerClass )
{
L[] copy = (L[]) Array.newInstance( listenerClass, 0 );
try
{
readLock.lock();
List<L> list = getListenerList( listenerClass );
if ( list != null )
{
copy = (L[]) list.toArray( copy );
}
}
finally
{
readLock.unlock();
}
return copy;
}
@SuppressWarnings("unchecked")
private <L extends EventListener> List<L> getListenerList ( Class<L> listenerClass )
{
return (List<L>) llMap.get( listenerClass );
}
}