Swing UI 线程是何时创建的?

2024-04-13

在运行 Swing 程序的过程中,什么时候 UI 线程(事件调度线程,EDT)首先产生? 想必任何给定的 JVM 都可以做任何它想做的事 (例如,始终在启动时生成 EDT,无论 或从未使用过),但作为一个实际问题,当 通常会创建 EDT 吗?

它是在 SwingUtilities.invokeLater() 时创建的吗 首先被调用? JPanel 何时首次实例化? 如果事件泵与创建分开启动 EDT,通常什么时候发生?


查看代码后,它似乎是“延迟初始化”的,这意味着它会在需要时立即初始化(如果尚未初始化)。在这种情况下,每当任何事件被发布到其队列中时。


完整的故事如下:

The EventDispatchThread被封装在EventQueue. Each 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;
}

The 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) http://docs.oracle.com/javase/8/docs/api/java/awt/EventQueue.html#postEvent-java.awt.AWTEvent-)
  3. 在包私有方法中EventQueue#createSecondaryLoop(Conditional, EventFilter, long).

Before initDispatchThread()叫做,dispatchThread检查以确保它尚未初始化。有几种方法可以查看 JDK 中类的完整源代码(最简单的是附加源代码);如果您是,请研究这些方法REALLY感兴趣的。

所以现在我们知道了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 是一个抽象类。我们不是实例化此类的对象,而是创建 Toolkit 子类的实例:SunToolkit。我们需要知道这一点才能查看队列是在哪里创建的。

一旦我们有了 Toolkit,我们就可以使用它来访问它的 EventQueueToolkit#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. EDT 位于 EventQueue 内
  2. EventQueue 位于 Toolkit 内
  3. 创建工具包时会创建队列
  4. 该工具包可以手动创建(通过调用Toolkit.getDefaultToolkit(),或者每当程序的另一部分(例如将数据发送到队列的 Swing 组件)调用它时)
  5. 每当事件发布到队列时都会创建 EDT(并且 EDT 尚未运行)

如果您对此有任何疑问,请告诉我

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Swing UI 线程是何时创建的? 的相关文章

  • createImage(int width, int height) 的问题

    我有以下代码 作为游戏的一部分每 10 毫秒运行一次 private void gameRender if dbImage null createImage returns null if GraphicsEnvironment isHea
  • Java Runtime.getRuntime().freeMemory() 问题

    我搜索并看到了一些线程 但没有一个能够解决我遇到的具体问题 我正在尝试使用以下方式监视我的内存使用情况Runtime getRuntime freeMemory Runtime getRuntime maxMemory and Runtim
  • Spring Security 自定义过滤器

    我想自定义 Spring security 3 0 5 并将登录 URL 更改为 login 而不是 j spring security check 我需要做的是允许登录 目录并保护 admin report html 页面 首先 我使用教
  • 如何在 Firebase 远程配置中从 JSON 获取值

    我是 Android 应用开发和 Firebase 的新手 我想知道如何获取存储在 Firebase 远程配置中的 JSONArray 文件中的值 String 和 Int 我使用 Firebase Remote Config 的最终目标是
  • “java.net.MalformedURLException:未找到协议”读取到 html 文件

    我收到一个错误 java net MalformedURLException Protocol not found 我想读取网络上的 HTML 文件 mainfest uses permission android name android
  • Spring Data JPA 选择不同

    我有一个情况 我需要建立一个select distinct a address from Person a 其中地址是 Person 内的地址实体 类型的查询 我正在使用规范动态构建我的 where 子句并使用findAll Specifi
  • 通往楼梯顶部的可能路径

    这是一个非常经典的问题 我听说谷歌在他们的面试中使用过这个问题 问题 制定一个递归方法 打印从楼梯底部到楼梯顶部的所有可能的独特路径 有 n 个楼梯 您一次只能走 1 步或 2 步 示例输出 如果它是一个有 3 级楼梯的楼梯 1 1 1 2
  • org.hibernate.QueryException:无法解析属性:文件名

    我正在使用休眠Criteria从列中获取值filename在我的桌子上contaque recording log 但是当我得到结果时 它抛出异常 org hibernate QueryException 无法解析属性 文件名 com co
  • Kotlin 未解决的参考:CLI 上 gradle 的 println

    放一个printlnkotlin 函数返回之前的语句会崩溃 堆栈跟踪 thufir dur NetBeansProjects kotlin thufir dur NetBeansProjects kotlin gradle clean bu
  • 什么时候可以在 Java 中使用 Thead.stop() ?

    Thread stop 的 Java 文档听起来好像如果您调用 Thread stop 世界就会终结 已弃用 这种方法本质上是不安全的 停止线程 Thread stop 导致它解锁所有已锁定的监视器 作为未经检查的 ThreadDeath
  • Spring Security SAML2 使用 G Suite 作为 Idp

    我正在尝试使用 Spring Security 5 3 3 RELEASE 来处理 Spring Boot 应用程序中的 SAML2 身份验证 Spring Boot 应用程序将成为 SP G Suite 将成为 IDP 在我的 Maven
  • 需要使用 joda 进行灵活的日期时间转换

    我想使用 joda 解析电子邮件中的日期时间字符串 不幸的是我得到了各种不同的格式 例如 Wed 19 Jan 2011 12 52 31 0600 Wed 19 Jan 2011 10 15 34 0800 PST Wed 19 Jan
  • 套接字的读写如何同步?

    我们创建一个套接字 在套接字的一侧有一个 服务器 在另一侧有一个 客户端 服务器和客户端都可以向套接字写入和读取 这是我的理解 我不明白以下事情 如果服务器从套接字读取数据 它在套接字中是否只看到客户端写入套接字的内容 我的意思是 如果服务
  • Freemarker 和 Struts 2,有时它计算为序列+扩展哈希

    首先我要说的是 使用 Struts2 Freemarker 真是太棒了 然而有些事情让我发疯 因为我不明白为什么会发生这种情况 我在这里问是因为也许其他人有一个想法可以分享 我有一个动作 有一个属性 说 private String myT
  • JMenu 中的文本居中

    好吧 我一直在网上寻找有关此问题的帮助 但我尝试的任何方法似乎都不起作用 我想让所有菜单文本都集中在菜单按钮上 当我使用setHorizontalTextPosition JMenu CENTER 没有变化 事实上 无论我使用什么常量 菜单
  • Resteasy 可以查看 JAX-RS 方法的参数类型吗?

    我们使用 Resteasy 3 0 9 作为 JAX RS Web 服务 最近切换到 3 0 19 我们开始看到很多RESTEASY002142 Multiple resource methods match request警告 例如 我们
  • 如何使用play框架上传多个文件?

    我在用play framework 2 1 2 使用java我正在创建视图来上传多个文件 我的代码在这里 form action routes upload up enctype gt multipart form data
  • org.apache.commons.net.io.CopyStreamException:复制时捕获 IOException

    我正在尝试使用以下方法中的代码将在我的服务器中创建的一些文件复制到 FTP 但奇怪的是我随机地低于错误 我无法弄清楚发生了什么 Exception org apache commons net io CopyStreamException
  • 泛型、数组和 ClassCastException

    我想这里一定发生了一些我不知道的微妙事情 考虑以下 public class Foo
  • Java EE 目录结构

    我对以下教程有疑问 http www mkyong com jsf2 jsf 2 internationalization example http www mkyong com jsf2 jsf 2 internationalizatio

随机推荐

  • fetch-api 中的“最大重定向”错误意味着什么?

    我试图从网站获取一些数据 但收到以下错误 FetchError maximum redirect reached at
  • 在 Bash 中的函数内部使用声明

    我想使用函数更改全局变量 或至少附加到它 input Hello example input func declare x example input World func echo input 其输出将是 Hello 的原始值 如果该函数
  • 重新排序时无法将 UITableViewCell 从当前位置拖动

    我试图让我的核心数据支持的 UITableView 具有重新排序的能力 在实现所有这些委托和提到的核心数据的一些技术之后here https stackoverflow com q 1077568 147564我发现奇怪的行为 点击编辑按钮
  • 垃圾收集和 JNI 调用

    我遇到 JNI 程序随机内存不足的问题 这是一个 32 位 java 程序 它读取文件 进行一些图像处理 通常使用 250MB 到 1GB 然后 所有这些对象都会被丢弃 然后程序对 JNI 程序进行一系列调用 通常需要 100 250MB
  • 转换为Weka日期格式

    我有一个带有一些属性的 csv 文件 一种是日期属性 日期采用这种形式 yyyy mm dd hh mm ss 但 Weka 将其视为名义类型而不是日期类型 如何解决这个问题 请在这件事上给予我帮助 我用Weka资源管理器 一个很好的参考
  • 执行 `brew tap exolnet/homebrew-deprecated` 时出错

    我要安装 电子邮件受保护 cdn cgi l email protection在我的 MacBook Pro 和 Macos M1 上 我想执行以下步骤 brew tap exolnet homebrew deprecated brew i
  • OpenCV - 如何在 iOS 上将自适应阈值应用于图像

    我正在尝试将自适应阈值应用于 A4 纸的图像 如下所示 我使用下面的代码来应用图像处理 UIImage processImageWithOpenCV UIImage inputImage cv Mat cvImage inputImage
  • 将 jQuery 加载到 chrome-extension 中

    我正在尝试迈入 Chrome 扩展的神奇世界的第一步 现在我已经构建了我的清单并尝试加载jquery name Test Extension version 0 1 manifest version 2 description First
  • 删除表中的重复条目[重复]

    这个问题在这里已经有答案了 我想从下表中删除多个重复的键 id name uid 1 ekta 5 2 ekta 5 3 sharma 10 4 sharma 10 希望它像 id name uid 1 ekta 5 3 sharma 10
  • 如何从点击事件中知道是否选择了垫选项?

    我有多个mat select并想知道是否mat option所单击的内容已被选择或取消选择 这 event target对象传递时 click 被解雇 没有selected我可以使用的属性
  • 在图表上绘制单点

    我有一个小提琴图 如下所示 我想在小提琴顶部的每个 x 值上绘制一些单独的点 或线 十字 点 以最简单的为准 如下所示 我该怎么做呢 这是制作小提琴图的代码 参见使用 Matplotlib 绘制小提琴图 http pyinsci blogs
  • 使用div和jquery连续循环

    我正在继续一个上一篇文章 https stackoverflow com questions 1748656 images sliding continuously with table and jquery 但我想我应该打开一个新线程 因
  • 是否可以将实体框架与 Windows Azure 开发存储服务一起使用?

    编辑 是否可以将实体框架与 Windows Azure 开发存储服务一起使用 如何 Thanks 不 这是不可能或不切实际的 Azure 存储 与 SQL Azure 不同 不支持加入 并且可能无法很好地响应即席查询 但你不需要它 Azur
  • 覆盖 ZipArchiveEntry 的内容

    如何覆盖 a 的内容ZipArchiveEntry 以下代码使用StreamWriter with StringBuilder如果新文件内容比原始文件内容短 则会失败 例如 using System IO Compression using
  • Git 1.8:推送错误:dst ref refs/heads/master 从多个 src 接收

    git 1 8 的另一个问题 git push error dst ref refs heads master receives from more than one src error failed to push some refs t
  • 如何使用加密的 DLQ 将重新驱动策略添加到 SNS

    我有一个 SNS 用 KMS 加密 由两个 lambda 订阅 我正在尝试向其中一项订阅添加重新驱动策略 相关 DLQ 已加密 添加重新驱动策略会出现错误 无法检查 Amazon SQS 队列权限 确保队列存在并且您的帐户有权读取队列的属性
  • 捏合 MKMapView 时保持中心坐标

    如果您在跟踪设备位置时在 Apple 地图应用程序中进行捏合放大 缩小 则捏合手势的 平移 部分将被忽略 蓝色位置指示器将保持固定在屏幕中央 使用普通的时情况并非如此MKMapView 假设我已经有了用户的位置 我怎样才能达到这个效果呢 我
  • 如何对多种文件类型使用 grep --include 选项?

    当我想 grep 某个目录中的所有 html 文件时 我执行以下操作 grep include html pattern R some path 效果很好 问题是如何grep某个目录中的所有html htm php文件 由此使用 grep
  • Android中如何使用Intent在Activity之间传递值?

    我想将一个活动类别中的位置值传递给另一个活动类别 我的代码如下 protected void onListItemClick ListView listView View v int position long id switch posi
  • Swing UI 线程是何时创建的?

    在运行 Swing 程序的过程中 什么时候 UI 线程 事件调度线程 EDT 首先产生 想必任何给定的 JVM 都可以做任何它想做的事 例如 始终在启动时生成 EDT 无论 或从未使用过 但作为一个实际问题 当 通常会创建 EDT 吗 它是