3

アーキテクチャのプロトタイプを書いているときに奇妙な問題に遭遇しました。

同じコマンドを個別にディスパッチする 2 つのスレッドを作成しようとしました。最初のスレッドは a を使用しScanner、2 番目のスレッドは Swing を使用しました。問題は、最初のスレッドが 2 番目のスレッドの開始を妨げていたことです。2 番目のスレッドは、スキャナに十分な入力が与えられた後でのみ開始されました。2番目のスレッドが開始されるまで最初のスレッドを強制的にスリープさせると、問題が一時的に修正されました。

次の例では、この動作を一貫して再現しています。呼び出しの間にスリープすると、さらに一貫性が保たれます。

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Scanner;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.WindowConstants;

public final class Bug {
    public static void main(final String[] arguments) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("The commands are \"wait\" and \"quit\".");
                final Scanner scanner = new Scanner(System.in);
                loop: while (true) {
                    System.out.print("Enter a command: ");
                    final String command = scanner.nextLine();
                    switch (command.toLowerCase()) {
                    case "exit":
                    case "quit":
                        break loop;
                    default:
                        System.out.println("Use \"wait\" or \"quit\" instead of \"" + command + "\".");
                    case "wait":
                    }
                }
                scanner.close();
            }
        }).start();

        try {
            Thread.sleep(1000);//improves consistency
        }
        catch (final InterruptedException exception) {}

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                final JFrame frame = new JFrame("Commands");
                frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
                frame.setResizable(false);
                frame.setLayout(new BorderLayout());
                frame.add(new JButton("Wait"), BorderLayout.LINE_START);
                final JButton button = new JButton("Quit");
                button.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(final ActionEvent event) {
                        frame.dispose();
                    }
                });
                frame.add(button, BorderLayout.LINE_END);
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}

2 番目のスレッドが正しく開始されないのはなぜですか? 私は責任がありますか?

同様の問題が 10 年以上前にバグとして提出されました。


実行java -version結果

java version "1.7.0_21"
Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
Java HotSpot(TM) Client VM (build 23.21-b01, mixed mode, sharing)

そしてcmd -info_

Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

それが重要な場合。

4

2 に答える 2

0

これは、2 番目のスレッドに EventQueue.invokeLater() を使用していることが原因である可能性があります。そのスレッドが開始するまでに、最初のスレッドはすでにコンソールでユーザー入力を待機している可能性があります。最初のスレッドがすでに入力を待っているため、EventQueue が 2 番目のスレッドをすぐに起動せず、イベント ポンプが詰まる可能性があると想像できます。

別のメカニズムを使用して 2 番目のスレッドを開始することをお勧めします。最初のスレッドと同じように開始してみませんか?

また、何が起こっているのか、そしてその理由をより明確にするために、このコードをリファクタリングする必要があるという他のコメントにも同意します。

于 2013-04-26T21:00:52.553 に答える