Java 8u161/8u162环境下Swing应用切换窗口CPU占用异常求助
Java 8u161/8u162 Swing JTextField焦点切换后CPU占用过高问题及临时解决方案
最近帮不少客户处理过这个棘手的Swing问题——在Windows 10 8核机器上运行基于Java 8u161或8u162的应用时,只要焦点停在JTextField中,切换到Chrome这类其他应用再切回来,CPU占用会直接飙到15%左右(刚好是一个核心满负荷处理事件)。但只要点击一下标签页,CPU又会立刻降到0%,非常影响用户体验。
复现步骤
- 运行下面的测试代码,打开窗口后让焦点停在
JTextField内 - 切换到其他应用(比如Chrome),再切回Swing窗口
- 观察任务管理器的CPU占用率,会发现直接升到15%左右,点击标签页后恢复正常
测试代码:
public class Test { public static void main(String... args) { SwingUtilities.invokeLater(() -> { JFrame f = new JFrame("Test"); JTabbedPane tp = new JTabbedPane(); tp.addTab("tab 1", new JTextField(20)); f.add(tp); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); }); } }
问题根源追踪
通过监听AWT事件队列,可以发现有一个InvocationEvent(具体是sun.awt.windows.WInputMethod相关的任务)被反复执行,导致事件队列一直处于繁忙状态,直接拉满一个CPU核心。可以添加这段代码观察事件输出:
Toolkit.getDefaultToolkit().getSystemEventQueue().push(new EventQueue(){ @Override protected void dispatchEvent(AWTEvent event) { System.out.println(event); super.dispatchEvent(event); } });
这个问题是版本特定的:
- 在Java 8u151、8u152以及9.0.4中完全不存在
- 从Java 8u161/8u162开始引入,据Oracle Bug追踪和OpenJDK的记录,问题由Bug ID 8184016引入,后在Bug ID 8183504中修复,Java 8u172 b02版本已经彻底解决了这个问题
临时解决方案
如果暂时无法升级到修复后的版本,这里有几个可行的临时 workaround:
- 降级Java版本:直接回退到8u152,这是最直接有效的办法,能立刻消除问题
- 重置输入方法状态:给JFrame添加
WindowListener,在窗口激活时强制结束输入方法的当前任务:
f.addWindowListener(new WindowAdapter() { @Override public void windowActivated(WindowEvent e) { InputContext ic = f.getInputContext(); if (ic != null) { ic.endComposition(); } } });
- 焦点重置技巧:在标签页切换时,临时转移再恢复焦点,打断重复的事件循环:
tp.addChangeListener(e -> { Component focused = f.getFocusOwner(); if (focused instanceof JTextField) { tp.requestFocusInWindow(); focused.requestFocusInWindow(); } });
内容的提问来源于stack exchange,提问作者Brian S.
相关产品推荐
相关产品推荐

