即使在vm args中使用XstartOnFirstThread也无效的线程访问

我有一个胚胎Java Web Start应用程序,只有一个类。 它在Windows和Linux上运行,但在Mac OS X上遇到了可怕的无效线程访问错误。我意识到这已在其他地方处理过。 我花了整整两天时间在互联网上搜索并实施了所有解决方案,但问题仍然存在。

我的理解是,必须从主线程调用SWT,这就是这里的情况。 如果我错了,请纠正我。

我将在下面发布3个片段,应用程序的源代码,jnlp文件的相关部分以及Mac上的错误消息。 问题是最后的问题。


JAVA SOURCE CODE

package client; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; public class AccountWindow { public static void main(String[] args) { Display display = new Display(); **// error occurs here** Shell shell = new Shell(display); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } } 

JNLP SNIPPET

     

错误信息

 org.eclipse.swt.SWTException: Invalid thread access at org.eclipse.swt.SWT.error(Unknown Source) at org.eclipse.swt.SWT.error(Unknown Source) at org.eclipse.swt.SWT.error(Unknown Source) at org.eclipse.swt.widgets.Display.error(Unknown Source) at org.eclipse.swt.widgets.Display.createDisplay(Unknown Source) at org.eclipse.swt.widgets.Display.create(Unknown Source) at org.eclipse.swt.graphics.Device.(Unknown Source) at org.eclipse.swt.widgets.Display.(Unknown Source) at org.eclipse.swt.widgets.Display.(Unknown Source) at client.AccountWindow.main(AccountWindow.java:16) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.sun.javaws.Launcher.executeApplication(Launcher.java:1550) at com.sun.javaws.Launcher.executeMainClass(Launcher.java:1488) at com.sun.javaws.Launcher.doLaunchApp(Launcher.java:1299) at com.sun.javaws.Launcher.run(Launcher.java:114) at java.lang.Thread.run(Thread.java:637) 

请注意
– http://www.eclipse.org/swt/faq.php#javawebstart上发布的display.syncExec解决方案不适用,因为在您调用它之前需要显示。 当我尝试创建显示时,会发生错误。
– 我使用JaNeLavalidationjnlp文件,没有红色错误。
– 正在被正确解释,因为正在加载正确的swt库。
– 您可以在http://thelinkjuicer.com/gannonline/client.jnlp上重现错误


现在问题
任何人都可以在源代码或jnlp片段中看到任何会导致错误的内容吗?
次要问题:如何判断VM是否实际读取-XstartOnFirstThread参数?

显然,主要方法没有在主线程上执行。 您可以在堆栈跟踪中看到启动器实际上是在另一个线程中启动的,然后Launcher只间接调用main 。 不幸的是,这只是诊断,我不确定解决方案。 我做了类似的事情(通过Java Web Start的SWT应用程序),但我不记得我们是如何解决这个问题的,如果有的话。

检查com.sun.javaws.Launcher源代码后,目前还不清楚如何使其工作。 Launcher.launch方法启动一个新线程,在该线程中执行main方法。 您可以按照代码重新创建您正在获得的精确堆栈跟踪。

Java Web Start的主要入口点表明主线程在启动后很快就会死掉。

更新

我挖了一些东西:在这个Eclipse bug报告中 ,建议问题可能与此有关:

     

解析器从这里获取j2se规范并忽略后面更具体的规范。 尝试删除行。

更新2

现在我从这里挖出来 :

 com.apple.concurrent.Dispatch.getInstance().getNonBlockingMainQueueExecutor().execute( new Runnable() { public void run() { final Display display = Display.getDefault(); while (!display.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } }); 

这实际上听起来像是可行的。 它完全按照我在下面的评论中描述的那样:通过专门为此目的而实施的机制修补主线程。 尝试根据您的需要进行调整。 您可能甚至不需要-XstartOnFirstThread。

更新3

我终于找到了我的旧SWT-JWS项目。 它有这个:

     

它的工作原理。 它没有默认的j2se元素,该元素出现在OSX特定的条目中。

这是第二个问题的答案,“如何判断VM是否实际读取-XstartOnFirstThread参数?” (或相关问题,“如何检测-XstartOnFirstThread是否已传递给VM?”)我查看了java.lang.management.RuntimeMXBean.getInputArguments() ,但-XstartOnFirstThread 包含在返回的List 。 经过一些研究,我能够找到一些东西,所以我希望这可以帮助那些在我身边的人。

根据此链接 ,启动器设置了几个环境变量。 其中包括:

  JAVA_MAIN_CLASS_ pid
 JAVA_STARTED_ON_FIRST_THREAD_ pid 

使用System.getenv()获取环境变量的Map 。 从那里,您可以遍历entrySet()直到找到一个带有getKey()Entry ,其返回值以"JAVA_MAIN_CLASS_"开头。 如果发现的EntrygetValue()包含主类的名称,则可以使用密钥的其余部分来确定pid

获得pid后 ,在环境Map查找字符串"JAVA_STARTED_ON_FIRST_THREAD_ pid " 。 如果它存在并且值为"1" ,则使用-XstartOnFirstThread启动该过程。 否则,该过程在没有标志的情况下启动。

这可能不适用于未签名的WebStart应用程序,因为默认情况下禁止使用System.getenv()方法。 但是在签名的webstart应用程序或常规Java应用程序中,这确实有效。

希望有所帮助,