7

単一のクラスを持つ初期の Java Web Start アプリケーションがあります。これは Windows と Linux で動作しますが、Mac OS X では恐ろしい Invalid Thread Access エラーが発生します。私は丸 2 日かけてインターネットを探し回り、すべての解決策を実装しましたが、問題は解決しません。

私の理解では、SWT の呼び出しはメイン スレッドから行う必要があります。私が間違っている場合は修正してください。

アプリケーションのソース コード、jnlp ファイルの関連部分、および Mac でのエラー メッセージの 3 つのスニペットを以下に掲載します。質問は最後にあります。


Java ソースコード

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 スニペット

<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 ファイルを検証しましたが、赤いエラーはありません。 - 正しい swt ライブラリがロードされているため、<resources os="Mac\ OS\ X" arch="i386"> が正しく解釈されています。- http://thelinkjuicer.com/gannonline/client.jnlp でエラーを再現できます




そして今、質問
ソースコードまたはjnlpスニペットでエラーを引き起こす何かを見ることができますか?
二次的な質問: -XstartOnFirstThread 引数が実際に VM によって読み取られているかどうかをどのように確認できますか?

4

2 に答える 2

6

明らかに、メイン メソッドはメイン スレッドで実行されていません。スタック トレースで、ランチャーが実際には別のスレッドで開始され、Launcher間接的にmain. 残念ながら、これは単なる診断であり、解決策についてはわかりません。私は似たようなこと (Java Web Start を介した SWT アプリ) を行いましたが、これをどのように解決したか思い出せません。

com.sun.javaws.Launcherのソース コードを調べたところ、これをどのように機能させることができるかはまったく不明です。メソッドは、メソッドが実行されるLauncher.launch新しいスレッドを開始します。mainコードに従って、取得している正確なスタック トレースを再作成できます。

Java Web Startのメイン エントリ ポイントは、メイン スレッドが起動後すぐに終了することを示しています。

アップデート

私は何かを掘り起こしました:この Eclipse バグレポートでは、問題がこれに関連している可能性があることが示唆されています:

<resources>
  <j2se version="1.4+" />
  <jar href="client.jar" />
</resources>

パーサーはここから j2se 仕様を取得し、後のより具体的な仕様を無視します。行を削除してみてください<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 プロジェクトを見つけました。これには次のものがあります。

<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 固有のエントリにのみ表示されます。

于 2012-10-17T15:54:59.960 に答える
3

これは、「-XstartOnFirstThread 引数が実際に VM によって読み取られているかどうかをどのように確認できますか?」という 2 番目の質問に対する回答です。(または関連する質問、「-XstartOnFirstThread が VM に渡されたかどうかを検出するにはどうすればよいですか?」) を見ましjava.lang.management.RuntimeMXBean.getInputArguments()たが、返された には含まれて-XstartOnFirstThreadませんList。いくつかの調査の後、私は何かを理解することができたので、これが私の立場にあった他の誰かに役立つことを願っています.

このリンクによると、ランチャーによって設定される環境変数がいくつかあります。その中には次のものがあります。

JAVA_MAIN_CLASS_pid
JAVA_STARTED_ON_FIRST_THREAD_pid

環境変数のSystem.getenv()取得に使用します。Mapそこから、戻り値が で始まる を持つがentrySet()見つかるまで、 を反復処理できます。検出された にメイン クラスの名前が含まれている場合、残りのキーを使用してpidを特定できます。EntrygetKey()"JAVA_MAIN_CLASS_"EntrygetValue()

pidを取得したら、環境で文字列を検索します。それが存在し、値がである場合、プロセスは で開始されました。それ以外の場合、プロセスはフラグなしで開始されました。"JAVA_STARTED_ON_FIRST_THREAD_pid"Map"1"-XstartOnFirstThread

System.getenv()このメソッドはデフォルトで禁止されているため、署名されていない WebStart アプリケーションではおそらく機能しません。しかし、署名された Webstart アプリケーションまたは通常の Java アプリケーションでは、これは機能します。

それが役立つことを願って、

于 2013-03-05T16:39:29.103 に答える