0

以下に定義された2つのクラスがあります。

public class TextsManager extends Thread {
    LinkedList<String> lstOfPendingStr = new LinkedList<String>();

    boolean stopLoop = false;

    JTextArea txtArea;
    public void run()
    {
        while (!stopLoop)
        {               
            while (!lstOfPendingStr.isEmpty())
            {               
                String tmp = lstOfPendingStr.getFirst();
                this.txtArea.append(tmp);                   
                lstOfPendingStr.removeFirst();              
            }

            try {
                Thread.sleep(0);    //  note: I had to force this code
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }           
        }       
    }

    public void AddNewStr(String newStr)
    {       
        this.lstOfPendingStr.add(newStr);   
    }   

}

public class ClientApp {

    private JFrame frame;
    private JTextField textField;
    private JTextArea textArea;
    static private TextsManager txtManager;
    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    ClientApp window = new ClientApp();
                    window.frame.setVisible(true);                  
                } catch (Exception e) {
                    e.printStackTrace();
                }               
            }
        });     
    }

    /**
     * Create the application.
     */
    public ClientApp() {
        initialize();

        /*
         * Client app
         */
        txtManager =  new TextsManager(textArea);

        txtManager.start();     
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frame = new JFrame();

        textArea = new JTextArea(); 

        textField = new JTextField();
        textField.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER)
                {
                    txtManager.AddNewStr(textField.getText() + "\n");
                    textField.setText("");
                }
            }
        });

    }

}

プログラムは からユーザー入力を読み取りtextField、 に渡しTextsManager.lstOfPendingStrます。次に、() 内の各ループでTextsManager.run、既存のメンバーをチェックし、lstOfPendingStrを介して出力しますtxtArea

Thread.sleep(0)問題は、内のコードを削除するとrun()、 がrun()明らかに機能しなくなったことです。lstOfPendingStr新しい要素で正常に更新されたにもかかわらず、ループ内のコードwhile(!lstOfPendingStr.isEmpty())が呼び出されることはありませんでした。

System.out.printlnまたはThread.sleep(0)(提供されたコードのように)などのハードコードを 内に配置するwhile(!stopLoop)と、正常に機能しました。

スレッドを強制的に数ミリ秒間スリープさせることで問題を解決できましたが、この問題の背後にある理由を知りたいです。

あなたの知恵に感謝します。

由来 :)

4

1 に答える 1

0

いくつかの問題があります。

  1. 2 つのスレッドからメソッドを呼び出していますが、スレッドセーフではない でlstOfPendingStr初期化しています。私があなたのコードから理解している限りLinkedList、スレッドセーフなクラスを使用する必要があります。LinkedBlockingQueue
  2. 呼び出しているスレッド内JTextArea#append()。すべての AWT/Swing メソッドと同様に、任意のスレッドから呼び出すことはできませんが、AWT スレッドからのみ呼び出すことができます。invokeLater呼び出しをブロック内にラップします。

sleepコードが機能しているように見えるという事実は、並行性の問題の兆候にすぎません。

于 2013-10-20T12:22:32.597 に答える