Xerces
Xerces

Reputation: 13

Optimizing this event system

So I was reworking my Event System and I want to get it as optimized as possible. I have this down to about 82ms to fire 1 million events. I want to ask if there is anything you'd do differently and how to further optimize this? At the moment there is only some basic logic being done when an event is fired to the method, when I plan to use this for an upcoming project it will be a little more advanced which would probably double the execution time.

package me.xerces.eventbus;

import me.xerces.eventbus.annotation.EventHandler;
import me.xerces.eventbus.event.Event;

import java.lang.invoke.MethodHandle;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;

public class EventManager {

    private ArrayList<Map.Entry<Class, EventHandle>> eventHandlerList = new ArrayList<Map.Entry<Class, EventHandle>>();

    public void addEventListener(Object object)
    {
        for(Method method : object.getClass().getDeclaredMethods())
        {
            if(method.isAnnotationPresent(EventHandler.class))
            {
                Map.Entry<Class, EventHandle> eventHandleEntry = new AbstractMap.SimpleEntry<Class, EventHandle>(method.getParameterTypes()[0], new EventHandle(method, object));
                method.setAccessible(true);
                eventHandlerList.add(eventHandleEntry);
            }
        }
    }

    public void addSpecificEventListener(Object object, Class eventClass)
    {
        for(Method method : object.getClass().getDeclaredMethods())
        {
            if(method.isAnnotationPresent(EventHandler.class) && method.getParameterTypes().length > 0 && method.getParameterTypes()[0].equals(eventClass))
            {
                Map.Entry<Class, EventHandle> eventHandleEntry = new AbstractMap.SimpleEntry<Class, EventHandle>(method.getParameterTypes()[0], new EventHandle(method, object));
                method.setAccessible(true);
                eventHandlerList.add(eventHandleEntry);
            }
        }
    }

    public void removeEventListener(Object object)
    {
        Iterator<Map.Entry<Class, EventHandle>> iterator = eventHandlerList.iterator();
        while(iterator.hasNext())
        {
            Map.Entry<Class, EventHandle> entry = iterator.next();
            if(entry.getValue().getMethodClass().equals(object))
                iterator.remove();
        }
    }

    public void fireEvent(Event event)
    {
        Iterator<Map.Entry<Class, EventHandle>> iterator = eventHandlerList.iterator();
        while(iterator.hasNext())
        {
            Map.Entry<Class, EventHandle> entry = iterator.next();
            if(entry.getKey().equals(event.getClass())) {
                try {
                    EventHandle eventHandle = entry.getValue();
                    eventHandle.getMethod().invoke(eventHandle.getMethodClass(), event);
                } catch (IllegalAccessException | InvocationTargetException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }
}

Github link: https://github.com/X3rces/EventBus EDIT: Is there a way to speed up when the JVM converts the invokation to a straight method call instead of using JNI?

Upvotes: 1

Views: 309

Answers (1)

Vitaly
Vitaly

Reputation: 2662

You can avoid

 if(entry.getKey().equals(event.getClass())) {

by using

private final Map<Class<?>, List<EventHandle>> eventHandlerMap = new HashMap<>();

See my EventSystem code in question

EventSource with Map<Class<? extends Event>, List<EventListener<? extends Event>> without unchecked call

Upvotes: 1

Related Questions