使用Java 7 Update 25的rmi线程中的AppContext为null

我们最近从Update 21更新到Java 7 Update 25,并且当从rmi线程调用SwingUtilities.isEventDispatchThread()时,现在遇到空指针exception,因为AppContext.getAppContext()返回null。

位于sun.awt.SunToolkit.getSystemEventQueueImplPP(未知来源)的sun.awt.SunToolkit.getSystemEventQueueImplPP(未知来源)的java.lang.NullPointerException,位于sun.awt.SunToolkit.getSystemEventQueueImpl(未知来源),位于java.awt.Toolkit.getEventQueue(来自sun.reflect的sun.reflect.NativeMethodAccessorImpl.invoke0(本地方法)的javax.swing.SwingUtilities.isEventDispatchThread(未知来源)的java.awt.EventQueue.isDispatchThread(未知来源)处的未知来源位于太阳的sun.rmi.server.UnicastServerRef.dispatch(未知来源)的sun.reflect.DelegatingMethodAccessorImpl.invoke(未知来源)sun.rmi.server.UnicastServerRef.dispatch(未知来源)的.NativeMethodAccessorImpl.invoke(未知来源)位于sun.rmi.transport.Transport.serviceCall的java.security.AccessController.doPrivileged(Native Method)的sun.rmi.transport.Transport $ 1.run(未知来源)的.rmi.transport.Transport $ 1.run(未知来源) (未知来源)at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown So urce)at sun.rmi.transport.tcp.TCPTransport $ ConnectionHandler.run0(Unknown Source)at sun.rmi.transport.tcp.TCPTransport $ ConnectionHandler.run(Unknown Source)at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown)来自java.lang.Thread.run的java.util.concurrent.ThreadPoolExecutor $ Worker.run(未知来源)(未知来源)

此错误仅在Web启动时出现,当我们通过IDE运行我们的应用程序时,它很好。

还有其他人遇到过这个吗? 有关AppContext的最新更新中有什么变化的想法吗?

似乎其他人在更新后与AppContext有一些相关的问题: https ://forums.oracle.com/message/11077767#11077767

Java3D作为Java Web Start运行时遇到了同样的问题。 我找到了另一个解决方案。 您必须使用runnables队列准备自己的InvokeLaterProcessor。 它必须扩展Thread并获取runnables并在run方法中处理它们:

public class InvokeLaterProcessor extends Thread { private BlockingQueue queue=new ArrayBlockingQueue(1); public InvokeLaterProcessor(String name) { super(name); } public void invokeLater(Runnable runnable) { try { queue.put(runnable); } catch (InterruptedException ex) { log.warn("invokeLater interrupted"); } } public void run() { Runnable runnable=null; do { try { runnable = queue.take(); SwingUtilities.invokeLater(runnable); } catch (InterruptedException ex) { runnable=null; } } while(runnable!=null); } } 

你所要做的就是在主线程中创建的某些类的静态中创建它:

 static { invokeLaterProcessor=new InvokeLaterProcessor("MyInvokeLater"); invokeLaterProcessor.start(); } 

并通过此代码处理runnables:

 invokeLaterProcessor.invokeLater(runnable); 

你不需要专有

 sun.awt.SunToolkit.invokeLaterOnAppContext(evtContext, rn) 

这不是最终答案,但它是一种解决方法,对我有用。

应用程序需要在EVT中保存当前的AppContext:

  AppContext evtContext; //field SwingUtilities.invokeLater(new Runnable() { public void run() { evtContext = AppContext.getAppContext(); } }); 

然后,必须使用自定义invokeLater2(Runnable rn)方法替换来自RMI线程的所有对SwingUtilities.invokeLater(..)的调用,该方法使用sun.awt.SunToolkit.invokeLaterOnAppContext(..,..)如:

 void invokeLater2(Runnable rn) { if (AppContext.getAppContext() == null) { logger.warning("AppContext is null, using EVT AppContext" + " through SunToolKit"); sun.awt.SunToolkit.invokeLaterOnAppContext(evtContext, rn); } else { SwingUtilities.invokeLater(rn); } } 

不幸的是,必须替换来自RMI线程的所有对SwingUtilities.invokeLater(..)的调用,并且该程序现在依赖于内部Sun JRE专有API。

我希望Oracle能够尽快为JRE 1.7.0.u25提供补丁来解决这个问题。

– 这个解决方法是根据guruman在这里的评论中提出的建议guruman的。

以下是JDK-8019274的解决方法,打包在实用程序类中。

对我们来说, invokeAndWait()是个大问题。 此示例具有invokeLater()的现有修复程序和invokeAndWait()的新修复程序。

笔记:

  • 你需要jnlp.jar
  • 在调用invokeLater()之前,在main()方法的早期调用init() invokeLater()
  • 用这些调用替换对invokeLater()invokeAndWait()的所有调用

(免责声明:这是我们的产品。此解决方案的某些方面可能不适用于您。)

 public class JreFix { private static String badVersionInfo = null; private static AppContext awtEventDispatchContext = null; private static AppContext mainThreadContext = null; private static Boolean isWebStart = null; private static BasicService basicService = null; private static IntegrationService integrationService = null; /** * Call this early in main(). */ public static void init() { if (isWebstart() && isApplicableJvmType()) { String javaVersion = System.getProperty("java.version"); if ("1.7.0_25".equals(javaVersion)) { badVersionInfo = "7u25"; } else if ("1.7.0_40".equals(javaVersion)) { badVersionInfo = "7u40"; } else if (javaVersion != null && "1.6.0_51".equals(javaVersion.substring(0,8))) { badVersionInfo = "6u51"; } else if ("javaws-10.25.2.16".equals(System.getProperty("javawebstart.version"))) { badVersionInfo = "Web Start 10.25.2.16"; } } if (badVersionInfo != null) { mainThreadContext = AppContext.getAppContext(); try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { awtEventDispatchContext = AppContext.getAppContext(); } }); } catch (Exception e) { displayErrorAndExit(null); } if (mainThreadContext == null || awtEventDispatchContext == null) { displayErrorAndExit(null); } } } public static void invokeNowOrLater(Runnable runnable) { if (hasAppContextBug()) { invokeLaterOnAwtEventDispatchThreadContext(runnable); } else { SwingUtilities.invokeLater(runnable); } } public static void invokeNowOrWait(Runnable runnable) { if (hasAppContextBug()) { fixThreadAppContext(null); } try { SwingUtilities.invokeAndWait(runnable); } catch (Exception e) { // handle it } } public static boolean hasAppContextBug() { return isJreWithAppContextBug() && AppContext.getAppContext() == null; } public static void invokeLaterOnAwtEventDispatchThreadContext(Runnable runnable) { sun.awt.SunToolkit.invokeLaterOnAppContext(awtEventDispatchContext, runnable); } public static void fixThreadAppContext(Component parent) { try { final Field field = AppContext.class.getDeclaredField("threadGroup2appContext"); field.setAccessible(true); Map threadGroup2appContext = (Map)field.get(null); final ThreadGroup currentThreadGroup = Thread.currentThread().getThreadGroup(); threadGroup2appContext.put(currentThreadGroup, mainThreadContext); } catch (Exception e) { displayErrorAndExit(parent); } if (AppContext.getAppContext() == null) { displayErrorAndExit(parent); } } private static boolean isJreWithAppContextBug() { return badVersionInfo != null; } private static void displayErrorAndExit(Component parent) { JLabel msgLabel = new JLabel("" + "Our application cannot run using Web Start with this version of Java.

" + "Java " + badVersionInfo + " contains a bug acknowledged by Oracle (JDK-8019274)."); JOptionPane.showMessageDialog(parent, msgLabel, "Java Version Error", JOptionPane.ERROR_MESSAGE); System.exit(1); } private static boolean isApplicableJvmType() { String vendor = System.getProperty("java.vendor"); String vmName = System.getProperty("java.vm.name"); if (vendor != null && vmName != null) { return vmName.contains("Java HotSpot") && (vendor.equals("Oracle Corporation") || vendor.equals("Sun Microsystems Inc.")); } return false; } private static boolean isWebstart() { if (isWebStart == null) { try { basicService = (BasicService) ServiceManager.lookup("javax.jnlp.BasicService"); isWebStart = true; } catch (UnavailableServiceException e) { isWebStart = false; } try { integrationService = (IntegrationService) ServiceManager.lookup("javax.jnlp.IntegrationService"); } catch (UnavailableServiceException e) { } } return isWebStart; } }