run()的Java线程问题

run()的Java线程问题,java,multithreading,Java,Multithreading,我有两个定义如下的类: public class TextsManager extends Thread { LinkedList<String> lstOfPendingStr = new LinkedList<String>(); boolean stopLoop = false; JTextArea txtArea; public void run() { while (!stopLoop)

我有两个定义如下的类:

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);   
    }   

}
程序将从
textField
读取用户输入,并将其传递到
TextsManager.lstoffendingstr
。然后,在
TextsManager.run
()中的每个循环上,它将检查
lstoffendingstr
中存在的成员,并通过
txtArea
输出它们

问题是,如果我删除了
Thread.sleep(0)
中的
run()
,那么
run()
显然会停止工作。尽管已使用新元素成功更新了
lstoffendingstr
,但是(!lstoffendingstr.isEmpty())时循环中的代码将永远不会被调用

在(!stopLoop)期间,我将硬代码(如
System.out.println
Thread.sleep(0)
(如提供的代码中所示)放入
中,然后工作正常

虽然我通过强制线程睡眠几毫秒来解决问题,但我想知道这个问题背后的原因

我欣赏你的智慧


注意:)

你有几个问题

  • 您正在从两个线程调用
    lstoffendingstr
    上的方法,但使用
    LinkedList
    对其进行初始化,这不是线程安全的。您应该使用线程安全类,
    LinkedBlockingQueue
    似乎是我从您的代码中了解到的最佳选项
  • 在您正在调用的线程内
    JTextArea#append()
    。与所有AWT/Swing方法一样,您不能从任意线程调用它们,只能从AWT线程调用它们。将调用包装在
    invokeLater
    块中

  • sleep
    似乎使代码正常工作,这只是并发问题的一个迹象。

    您的示例在发布时没有编译,通常看起来有点太大。请缩小它。一个猜测是,当另一个线程正在添加更新时,试图从列表中读取的线程中看不到更新。您可能希望尝试使用一个能够与多个线程协同工作的集合(请参见java.util.concurrent)。我很不确定Thread.sleep的语义,但这可能会导致内存同步,这就是为什么在添加Thread.sleep后,代码可以正常工作。在消除代码中的编译错误并使其运行后,即使删除
    Thread.sleep(0)
    部分,我也会得到预期的输出。即使删除了这个部分,当我在JTextField中键入一些内容并按enter键时,它也会显示在JTextArea中,这里是我完成的src代码和一个可执行版本,其中我排除了Thread.sleep(0)。顺便说一下,代码在调试模式下运行良好。是发布的版本遇到了这个问题。
    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("");
                    }
                }
            });
    
        }
    
    }