如何在java中将事件插入事件调度线程队列的开头?

2024-04-13

我已经知道怎么做了事件调度线程 http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html作品。如果事件调度线程中存在如下所示的短事件和长事件,则应用程序无法响应。

为了提高 Swing 的响应能力,事件调度线程应该只用于短事件。而长事件应该在 SwingWorkers 上执行。

想象一下有很多短事件。

enter image description here The events should be executed in Event Dispatch thread and you have a special event which you want to be executed before other events existing in Event Dispatch Thread queue. But, events will be enqueued to the end of the queue by default and even InvokeLater do the same.

那么,有什么解决方案可以将事件排队到事件调度线程的开头吗?


虽然更换了EventQueue是一种正确的方法,由于内置,所以并不是真正必要的EventQueue已经支持优先级了。唯一的问题是它只支持内部 API 使用,所以我们只需要了解它是如何工作的;

//from EventQueue.java...

private static final int LOW_PRIORITY = 0;
private static final int NORM_PRIORITY = 1;
private static final int HIGH_PRIORITY = 2;
private static final int ULTIMATE_PRIORITY = 3;

private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;

/*
 * We maintain one Queue for each priority that the EventQueue supports.
 * That is, the EventQueue object is actually implemented as
 * NUM_PRIORITIES queues and all Events on a particular internal Queue
 * have identical priority. Events are pulled off the EventQueue starting
 * with the Queue of highest priority. We progress in decreasing order
 * across all Queues.
 */
private Queue[] queues = new Queue[NUM_PRIORITIES];

//...skipped some parts...

/**
 * Causes <code>runnable</code> to have its <code>run</code>
 * method called in the {@link #isDispatchThread dispatch thread} of
 * {@link Toolkit#getSystemEventQueue the system EventQueue}.
 * This will happen after all pending events are processed.
 *
 * @param runnable  the <code>Runnable</code> whose <code>run</code>
 *                  method should be executed
 *                  asynchronously in the
 *                  {@link #isDispatchThread event dispatch thread}
 *                  of {@link Toolkit#getSystemEventQueue the system EventQueue}
 * @see             #invokeAndWait
 * @see             Toolkit#getSystemEventQueue
 * @see             #isDispatchThread
 * @since           1.2
 */
public static void invokeLater(Runnable runnable) {
    Toolkit.getEventQueue().postEvent(
        new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
}

/**
 * Posts a 1.1-style event to the <code>EventQueue</code>.
 * If there is an existing event on the queue with the same ID
 * and event source, the source <code>Component</code>'s
 * <code>coalesceEvents</code> method will be called.
 *
 * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
 *          or a subclass of it
 * @throws NullPointerException if <code>theEvent</code> is <code>null</code>
 */
public void postEvent(AWTEvent theEvent) {
    SunToolkit.flushPendingEvents(appContext);
    postEventPrivate(theEvent);
}

/**
 * Posts a 1.1-style event to the <code>EventQueue</code>.
 * If there is an existing event on the queue with the same ID
 * and event source, the source <code>Component</code>'s
 * <code>coalesceEvents</code> method will be called.
 *
 * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
 *          or a subclass of it
 */
private final void postEventPrivate(AWTEvent theEvent) {
    theEvent.isPosted = true;
    pushPopLock.lock();
    try {
        if (nextQueue != null) {
            // Forward the event to the top of EventQueue stack
            nextQueue.postEventPrivate(theEvent);
            return;
        }
        if (dispatchThread == null) {
            if (theEvent.getSource() == AWTAutoShutdown.getInstance()) {
                return;
            } else {
                initDispatchThread();
            }
        }
        postEvent(theEvent, getPriority(theEvent));
    } finally {
        pushPopLock.unlock();
    }
}

private static int getPriority(AWTEvent theEvent) {
    if (theEvent instanceof PeerEvent) {
        PeerEvent peerEvent = (PeerEvent)theEvent;
        if ((peerEvent.getFlags() & PeerEvent.ULTIMATE_PRIORITY_EVENT) != 0) {
            return ULTIMATE_PRIORITY;
        }
        if ((peerEvent.getFlags() & PeerEvent.PRIORITY_EVENT) != 0) {
            return HIGH_PRIORITY;
        }
        if ((peerEvent.getFlags() & PeerEvent.LOW_PRIORITY_EVENT) != 0) {
            return LOW_PRIORITY;
        }
    }
    int id = theEvent.getID();
    if ((id >= PaintEvent.PAINT_FIRST) && (id <= PaintEvent.PAINT_LAST)) {
        return LOW_PRIORITY;
    }
    return NORM_PRIORITY;
}

/**
 * Posts the event to the internal Queue of specified priority,
 * coalescing as appropriate.
 *
 * @param theEvent an instance of <code>java.awt.AWTEvent</code>,
 *          or a subclass of it
 * @param priority  the desired priority of the event
 */
private void postEvent(AWTEvent theEvent, int priority) {
    if (coalesceEvent(theEvent, priority)) {
        return;
    }

    EventQueueItem newItem = new EventQueueItem(theEvent);

    cacheEQItem(newItem);

    boolean notifyID = (theEvent.getID() == this.waitForID);

    if (queues[priority].head == null) {
        boolean shouldNotify = noEvents();
        queues[priority].head = queues[priority].tail = newItem;

        if (shouldNotify) {
            if (theEvent.getSource() != AWTAutoShutdown.getInstance()) {
                AWTAutoShutdown.getInstance().notifyThreadBusy(dispatchThread);
            }
            pushPopCond.signalAll();
        } else if (notifyID) {
            pushPopCond.signalAll();
        }
    } else {
        // The event was not coalesced or has non-Component source.
        // Insert it at the end of the appropriate Queue.
        queues[priority].tail.next = newItem;
        queues[priority].tail = newItem;
        if (notifyID) {
            pushPopCond.signalAll();
        }
    }
}

如你看到的EventQueue有 4 个不同的队列LOW, NORM, HIGH and ULTIMATE, SwingUtilities.invokeLater(Runnable) or EventQueue.invokeLater(Runnable)包裹你的Runnable进入一个InvocationEvent并打电话postEvent(AWTEvent)方法。此方法在线程和调用之间进行一些同步postEvent(AWTEvent, int)像这样postEvent(theEvent, getPriority(theEvent));现在有趣的部分是如何getPriority(AWTEvent)有效,基本上它给除了某些事件之外的每个事件提供正常的优先级PaintEvents and PeerEvents.

所以你需要做的就是包裹你的Runnable into a PeerEvent with ULTIMATE_PRIORTY代替InvocationEvent像这样;

Toolkit.getDefaultToolkit().getSystemEventQueue()
   .postEvent(new PeerEvent(Toolkit.getDefaultToolkit(), () -> {


    //execute your high priority task here!
    System.out.println("I'm ultimate prioritized in EventQueue!");


}, PeerEvent.ULTIMATE_PRIORITY_EVENT));

您可以查看完整的源代码事件队列 http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b27/java/awt/EventQueue.java and 同行事件 http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b27/sun/awt/PeerEvent.java .

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

如何在java中将事件插入事件调度线程队列的开头? 的相关文章

  • JDK 文档是语言规范的一部分吗?

    只有一名官员Java语言规范 https docs oracle com javase specs jls se8 html index html所有 Java 实现都必须遵守它 API文档怎么样 所有Java实现都需要遵守吗这个版本 ht
  • @RestController 没有 @ResponseBody 方法工作不正确

    我有以下控制器 RestController RequestMapping value base url public class MyController RequestMapping value child url method Req
  • 通过SOCKS代理连接Kafka

    我有一个在 AWS 上运行的 Kafka 集群 我想用标准连接到集群卡夫卡控制台消费者从我的应用程序服务器 应用程序服务器可以通过 SOCKS 代理访问互联网 无需身份验证 如何告诉 Kafka 客户端通过代理进行连接 我尝试了很多事情 包
  • “java.net.MalformedURLException:未找到协议”读取到 html 文件

    我收到一个错误 java net MalformedURLException Protocol not found 我想读取网络上的 HTML 文件 mainfest uses permission android name android
  • 如何在 Antlr4 中为零参数函数编写语法

    我的函数具有参数语法 如下面的词法分析器和解析器 MyFunctionsLexer g4 lexer grammar MyFunctionsLexer FUNCTION FUNCTION NAME A Za z0 9 DOT COMMA L
  • 打印星号的 ASCII 菱形

    我的程序打印出这样的钻石 但只有当参数或菱形的每一面为4 例如如果我输入6 底部三角形的间距是错误的 我一直在试图找出答案 当参数改变时 底部的三角形不会改变 只有顶部的三角形会改变 它只适用于输入4 public static void
  • 如何在代理后面安装 Eclipse Neon

    对于 Neon Eclipse 附带了一个安装程序 我在安装程序中找不到任何配置菜单 我的java版本是 java version java version 1 8 0 72 Java TM SE Runtime Environment b
  • 什么时候可以在 Java 中使用 Thead.stop() ?

    Thread stop 的 Java 文档听起来好像如果您调用 Thread stop 世界就会终结 已弃用 这种方法本质上是不安全的 停止线程 Thread stop 导致它解锁所有已锁定的监视器 作为未经检查的 ThreadDeath
  • 使用 JUnit 时,有没有办法验证测试方法中是否调用了 try/catch 指令的 Catch 部分?

    例如 如果我想测试以下课程 public class SomeClass public void someMethod try Some code where comething could go wrong catch Exception
  • 自动生成Flyway的迁移SQL

    当通过 Java 代码添加新模型 字段等时 JPA Hibernate 的自动模式生成是否可以生成新的 Flyway 迁移 捕获自动生成的 SQL 并将其直接保存到新的 Flyway 迁移中 以供审查 编辑 提交到项目存储库 这将很有用 预
  • 是否可以通过编程方式查找 logback 日志文件?

    自动附加日志文件以支持电子邮件会很有用 我可以以编程方式设置路径 如以编程方式设置 Logback Appender 路径 https stackoverflow com questions 3803184 setting logback
  • 生成的序列以 1 开头,而不是注释中设置的 1000

    我想请求一些有关 Hibernate 创建的数据库序列的帮助 我有这个注释 下面的代码 在我的实体类中 以便为合作伙伴表提供单独的序列 我希望序列以 1000 开头 因为我在部署期间使用 import sql 将测试数据插入数据库 并且我希
  • 在 SWT/JFace RCP 应用程序中填充巨大的表

    您将如何在 SWT 表中显示大量行 巨大是指超过 20K 行 20 列的东西 不要问我为什么需要展示那么多数据 这不是重点 关键是如何让它尽可能快地工作 这样最终用户就不会厌倦等待 每行显示某个对象的实例 列是其属性 一些 我想使用 JFa
  • JMenu 中的文本居中

    好吧 我一直在网上寻找有关此问题的帮助 但我尝试的任何方法似乎都不起作用 我想让所有菜单文本都集中在菜单按钮上 当我使用setHorizontalTextPosition JMenu CENTER 没有变化 事实上 无论我使用什么常量 菜单
  • 在 Google App-Engine JAVA 中将文本转换为字符串,反之亦然

    如何从字符串转换为文本 java lang String to com google appengine api datastore Text 反之亦然 Check Javadoc http code google com appengin
  • Resteasy 可以查看 JAX-RS 方法的参数类型吗?

    我们使用 Resteasy 3 0 9 作为 JAX RS Web 服务 最近切换到 3 0 19 我们开始看到很多RESTEASY002142 Multiple resource methods match request警告 例如 我们
  • 如何重新启动死线程? [复制]

    这个问题在这里已经有答案了 有哪些不同的可能性可以带来死线程回到可运行状态 如果您查看线程生命周期图像 就会发现一旦线程终止 您就无法返回到新位置 So 没有办法将死线程恢复到可运行状态 相反 您应该创建一个新的 Thread 实例
  • 将 Apache Camel 执行器指标发送到 Prometheus

    我正在尝试转发 添加 Actuator Camel 指标 actuator camelroutes 将交换 交易数量等指标 发送到 Prometheus Actuator 端点 有没有办法让我配置 Camel 将这些指标添加到 Promet
  • Java EE 目录结构

    我对以下教程有疑问 http www mkyong com jsf2 jsf 2 internationalization example http www mkyong com jsf2 jsf 2 internationalizatio
  • Spring表单ModelAttribute字段验证避免400 Bad Request错误

    我有一个ArticleFormModel包含正常发送的数据html form由 Spring 使用注入 ModelAttribute注释 即 RequestMapping value edit method RequestMethod PO

随机推荐