我有一个胚胎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
<resources os="Mac\ OS\ X" arch="x86_64">
<j2se version="1.5+" java-vm-args="-XstartOnFirstThread" />
<nativelib href="swt-4.2-cocoa-macosx-x86_64.jar" />
</resources>
错误消息
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.<init>(Unknown Source)
at org.eclipse.swt.widgets.Display.<init>(Unknown Source)
at org.eclipse.swt.widgets.Display.<init>(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解决方案不适用,因为在您调用它之前需要显示。当我尝试创建显示时,会发生错误
- 我使用JaNeLa来验证jnlp文件并且没有红色错误
- &lt; resources os =“Mac \ OS \ X”arch =“i386”&gt;正在解释因为正在加载正确的swt库
- 您可以在http://thelinkjuicer.com/gannonline/client.jnlp
现在问题 任何人都可以在源代码或jnlp片段中看到任何会导致错误的内容吗? 次要问题:如何判断VM是否实际读取了-XstartOnFirstThread参数?
答案 0 :(得分:5)
显然,主要方法没有在主线程上执行。您可以在堆栈跟踪中看到启动器实际上是在另一个线程中启动的,然后Launcher
仅间接调用main
。不幸的是,这只是诊断,我不确定解决方案。我做了类似的事情(通过Java Web Start的SWT应用程序),但我不记得我们是如何解决这个问题的,如果有的话。
检查com.sun.javaws.Launcher源代码后,目前尚不清楚如何使其工作。 Launcher.launch
方法启动一个新线程,在该线程中执行main
方法。您可以按照代码重新创建您正在获得的精确堆栈跟踪。
Java Web Start的main entry point表明主线程在启动后很快就会死掉。
我挖了一些东西:在this Eclipse bug report中,有人认为问题可能与此有关:
<resources>
<j2se version="1.4+" />
<jar href="client.jar" />
</resources>
解析器从这里获取j2se规范并忽略后面更具体的规范。尝试删除<j2se...
行。
现在我从here:
中挖出了这个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。
我终于找到了我的旧SWT-JWS项目。它有这个:
<resources os="Mac OS X" arch="x86_64">
<j2se version="1.6+" java-vm-args="-XstartOnFirstThread"/>
<jar href="swt-cocoa-macosx-x86-64-3.6.2.jar" />
</resources>
它有效。它没有默认的j2se
元素,此元素在特定于OSX的条目中显示为 。
答案 1 :(得分:0)
这是对第二个问题的回答,&#34;如何判断VM是否实际读取了-XstartOnFirstThread参数?&#34; (或相关问题,&#34;如何检测-XstartOnFirstThread是否已传递给VM?&#34;)我查看了java.lang.management.RuntimeMXBean.getInputArguments()
,但-XstartOnFirstThread
不是包含在返回的List
中。经过一些研究,我能够找到一些东西,所以我希望这可以帮助那些在我身边的人。
根据this link,启动器设置了几个环境变量。其中包括:
JAVA_MAIN_CLASS_pid
JAVA_STARTED_ON_FIRST_THREAD_pid
使用System.getenv()
获取Map
个环境变量。在那里,您可以遍历entrySet()
,直到找到Entry
的{{1}},其返回值以getKey()
开头。如果发现的"JAVA_MAIN_CLASS_"
Entry
包含主类的名称,则可以使用密钥的其余部分来确定 pid 。
获得 pid 后,在环境getValue()
中查找字符串"JAVA_STARTED_ON_FIRST_THREAD_pid"
。如果它存在并且值为Map
,则该过程以"1"
开始。否则,该过程在没有标志的情况下启动。
这可能无法在未签名的WebStart应用程序中工作,因为默认情况下禁止使用-XstartOnFirstThread
方法。但是在签名的webstart应用程序或常规Java应用程序中,这确实有效。
希望有所帮助,