हमारा विरासत ऐप एक भयानक ढांचे के साथ फंस गया है (ठीक है, मैं नामों का नाम दूंगा, यह टेपेस्ट्री 4 है) जिसमें सबसे आसान के लिए EventListeners
(~ 100,000) की हास्यास्पद संख्या शामिल है संचालन। मुझे लगता है कि javax.swing.event.EventListenerList
को संभालने के लिए यह कभी भी था, और इस दुर्भाग्यपूर्ण उपयोग के मामले में यह हमें कुछ खराब प्रदर्शन सिरदर्द पैदा कर रहा है।EventListenerList क्यों नहीं बदला गया है? (या: इसे बदलने में समस्याएं क्या हैं?)
मैं कुछ घंटों बिताए नीचे काफी अनुभवहीन HashMap/ArrayList
आधारित प्रतिस्थापन अप सजा, और यह बड़े पैमाने पर तेजी से लगभग हर तरह से है:
EventListenerList
> 2 सेकंड :
EventListenerMap
~ 3.5 मिलीसेकंड
50,000 श्रोताओं जोड़े
आग 50,000 श्रोताओं के लिए घटना:
EventListenerList
0.3-0.5 मिलीसेकेंडEventListenerMap
0.4-0.5 मिलीसेकेंड
50.000 श्रोताओं निकालें (एक समय में एक):
EventListenerList
> 2 सेकंडEventListenerMap
~ 280 मिलीसेकंड
फायरिंग सिर्फ बाल धीमा हो सकता है, लेकिन संशोधन बहुत तेज़ है। माना जाता है कि इस ढांचे ने हमें स्थिति में डाल दिया है, लेकिन यह अभी भी लगता है कि EventListenerList
को बहुत समय पहले बदल दिया जा सकता था। स्पष्ट रूप से सार्वजनिक एपीआई के साथ समस्याएं हैं (उदाहरण के लिए, यह अपनी कच्ची आंतरिक स्थिति सरणी का खुलासा करती है), लेकिन इससे इसके लिए और भी कुछ होना चाहिए। शायद बहुप्रचारित मामले हैं जहां 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);
}
}
+1 पागल (iest) इस महीने के सवाल, क्यू के बारे में (सबसे सरल संचालन के लिए) चरणों के हर अलग हैं या वे पेड़ या सेमाफोर, अगर हाँ तो एक और पागल (iest) सुझाव, eventhandler का उपयोग करें और से श्रृंखलित कर रहे हैं, रनटाइम पर स्ट्रिंग फॉर्म में पथ बनाने के लिए, तो शायद स्मृति में विधियों का समूह पकड़ने की आवश्यकता नहीं है, फाहा मुझे इस विचार से प्यार है, जो आपके प्रश्न से आया है, आरपीजी हमेशा के लिए जीते हैं (फिर उसी पागल अंतहीन कोड) – mKorbel
क्या आपके पास रिश्तेदार फायरिंग के समय में टाइपो? आप रिपोर्ट करते हैं कि आपका कार्यान्वयन 'EventListenerList' के लिए 0.4 _milliseconds_ बनाम 0.3 _seconds_ पर "केवल बाल धीमा" हो सकता है। –
हां, वह एक टाइपो था, धन्यवाद! –