2014-10-11 5 views
3

Когда в процессе запуска программы Swing используется поток нитей (поток событий-событий, EDT), который был сначала порожден? Предположительно, любой JVM мог бы делать все, что захочет (например, всегда запускает EDT при запуске, или не используется), но как практический вопрос, когда - это EDT, который обычно создается?Когда создается поток Swing UI?

Создается ли оно при первом вызове SwingUtilities.invokeLater() ? Когда сначала создается экземпляр JPanel? И если насос события запускается отдельно от создания EDT, когда это обычно происходит?

ответ

9

Просмотрев код, кажется, что он «лениво инициализирован», что означает его инициализацию, как только это необходимо, если оно еще не инициализировано. В этом случае всякий раз, когда какое-либо событие отправляется в очередь.


Вот полная история:

EventDispatchThread инкапсулируется в EventQueue. Каждый EventQueue имеет свое собственное EDT:

/** 
* Just a summary of the class 
*/ 
public class EventQueue { 
    private static final int ULTIMATE_PRIORITY = 3; 
    private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1; 

    private Queue[] queues = new Queue[NUM_PRIORITIES]; 
    private EventQueue nextQueue; 
    private EventQueue previousQueue; 
    private EventDispatchThread dispatchThread; 
} 

dispatchThread инициализируется с использованием пакета-частный метода initDispatchThread():

final void initDispatchThread() { 
    pushPopLock.lock(); 
    try { 
     if (dispatchThread == null && !threadGroup.isDestroyed() && !appContext.isDisposed()) { 
      dispatchThread = AccessController.doPrivileged(
       new PrivilegedAction<EventDispatchThread>() { 
        public EventDispatchThread run() { 
         EventDispatchThread t = 
          new EventDispatchThread(threadGroup, 
                name, 
                EventQueue.this); 
         t.setContextClassLoader(classLoader); 
         t.setPriority(Thread.NORM_PRIORITY + 1); 
         t.setDaemon(false); 
         AWTAutoShutdown.getInstance().notifyThreadBusy(t); 
         return t; 
        } 
       } 
      ); 
      dispatchThread.start(); 
     } 
    } finally { 
     pushPopLock.unlock(); 
    } 
} 

После проверки ссылок на этот метод, есть 3 места, где этот метод называется:

  1. В частном методе EventQueue#wakeup(boolean)
  2. В частном методе EventQueue#postEventPrivate(AWTEvent) (который вызывается общественным методом EventQueue#postEvent(AWTEvent))
  3. В пакете-частный метод EventQueue#createSecondaryLoop(Conditional, EventFilter, long).

Прежде чем initDispatchThread() вызывается, dispatchThread проверен, убедитесь, что он еще не инициализирован. Существует несколько способов просмотреть весь исходный код для класса в JDK (проще всего подключить источник); посмотрите на эти методы, если вы ДЕЙСТВИТЕЛЬНО заинтересованы.

Теперь мы знаем, что EventQueue содержит поток, и поток создается всякий раз, когда это действительно необходимо (событие отправляется). Время говорить о том, где находится эта очередь, и о том, как с ней общаются.

Если вы проверили код EventQueue#invokeLater(Runnable) (который вызывается его коллегой SwingUtilities), вы увидите, что он вызывает Toolkit.getEventQueue().postEvent(...). Это говорит о том, что очередь находится в Toolkit.

Внутри класса Toolkit мы видим, что оно создано (если оно еще не было) в любое время, когда мы его вызываем. Он использует отражение для создания объекта:

public static synchronized Toolkit getDefaultToolkit() { 
    if (toolkit == null) { 
     try { 
      java.lang.Compiler.disable(); 

      java.security.AccessController.doPrivileged(
        new java.security.PrivilegedAction<Void>() { 
       public Void run() { 
        String nm = null; 
        Class<?> cls = null; 
        try { 
         nm = System.getProperty("awt.toolkit"); 
         try { 
          cls = Class.forName(nm); 
         } catch (ClassNotFoundException e) { 
          ClassLoader cl = ClassLoader.getSystemClassLoader(); 
          if (cl != null) { 
           try { 
            cls = cl.loadClass(nm); 
           } catch (ClassNotFoundException ee) { 
            throw new AWTError("Toolkit not found: " + nm); 
           } 
          } 
         } 
         if (cls != null) { 
          toolkit = (Toolkit)cls.newInstance(); 
          if (GraphicsEnvironment.isHeadless()) { 
           toolkit = new HeadlessToolkit(toolkit); 
          } 
         } 
        } catch (InstantiationException e) { 
         throw new AWTError("Could not instantiate Toolkit: " + nm); 
        } catch (IllegalAccessException e) { 
         throw new AWTError("Could not access Toolkit: " + nm); 
        } 
        return null; 
       } 
      }); 
      loadAssistiveTechnologies(); 
     } finally { 
      // Make sure to always re-enable the JIT. 
      java.lang.Compiler.enable(); 
     } 
    } 
    return toolkit; 
} 

Инструментарий - это абстрактный класс. Вместо создания экземпляра объекта этого класса мы создаем экземпляр подкласса Toolkit: SunToolkit.Нам нужно знать это, чтобы увидеть, где создается очередь.

Как только у нас есть Инструментарий, мы можем получить доступ к его EventQueue, используя Toolkit#getSystemEventQueue(). Это телескоп к защищенному абстрактному методу getSystemEventQueueImpl(). Мы должны проверить подкласс, чтобы увидеть реализацию этого метода. В классе SunToolkit, мы имеем:

protected EventQueue getSystemEventQueueImpl() { 
    return getSystemEventQueueImplPP(); 
} 

// Package private implementation 
static EventQueue getSystemEventQueueImplPP() { 
    return getSystemEventQueueImplPP(AppContext.getAppContext()); 
} 

public static EventQueue getSystemEventQueueImplPP(AppContext appContext) { 
    EventQueue theEventQueue = (EventQueue) appContext.get(AppContext.EVENT_QUEUE_KEY); 
    return theEventQueue; 
} 

(EventQueue) appContext.get(AppContext.EVENT_QUEUE_KEY) Очередь приходящий appContext инструментария. Теперь все, что нам нужно сделать, это найти, где очередь добавляется в контекст приложения:

public SunToolkit() { 
    Runnable initEQ = new Runnable() { 
     public void run() { 
      EventQueue eventQueue; 

      String eqName = System.getProperty("AWT.EventQueueClass", "java.awt.EventQueue"); 

      try { 
       eventQueue = (EventQueue) Class.forName(eqName).newInstance(); 
      } catch (Exception e) { 
       e.printStackTrace(); 
       System.err.println("Failed loading " + eqName + ": " + e); 
       eventQueue = new EventQueue(); 
      } 
      AppContext appContext = AppContext.getAppContext(); 
      appContext.put(AppContext.EVENT_QUEUE_KEY, eventQueue); //queue added here 

      PostEventQueue postEventQueue = new PostEventQueue(eventQueue); 
      appContext.put(POST_EVENT_QUEUE_KEY, postEventQueue); 
     } 
    }; 

    initEQ.run(); 
} 

Так краткий обзор:

  1. The EDT находится в EventQueue
  2. EventQueue находится в Toolkit
  3. Очередь создается при создании инструментария
  4. Инструментарий создается либо вручную (путем вызова Toolkit.getDefaultToolkit(), либо когда другая часть программы (например, Swing Компонент размещение данных в очереди) звонки на нем)
  5. EDT создается любое событие публикуется в очереди (а разве EDT уже запущен)

Позвольте мне знать, если у вас есть какие-либо вопросы по этому поводу

+2

+1 для очень тщательной экспликации, но OP должен опираться на [поток отправки сообщений] (http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html) и не заботиться о (значительная) информация о реализации. – trashgod

+0

Винс, спасибо за хороший ответ. Небольшие последующие вопросы: Является ли это окончательным ответом в том смысле, что вышеуказанное требуется спецификацией java/публичным интерфейсом/документацией, или это «просто», как это происходит в текущей версии swing - - одна разумная реализация - но может измениться в новой версии? – cal

+1

@cal. В спецификации не обязательно указывать, как это библиотека, а не фактическая спецификация языка * (например, для циклов, если инструкции и т. Д.). Что касается изменения в новой версии, это возможно, но я сомневаюсь, что любые огромные изменения будут сделаны, поскольку JavaFX должен был заменить Swing. Хотя я видел незначительные корректировки, основная структура осталась прежней, и, как упоминалось выше, это вещи, о которых вы не должны беспокоиться; вы должны беспокоиться о том, изменится ли API, а не в реализации. –