【问题标题】:How do I restart a Thread after I stop it in Java? [duplicate]在Java中停止线程后如何重新启动它? [复制]
【发布时间】:2014-07-08 01:28:29
【问题描述】:

在我用 java 编写的项目中手动停止线程后,我试图重新启动它。当我尝试重新启动它时,我收到了 IllegalThreadStateException 错误。

我将我的代码简化为以下示例代码。我的问题是:

  1. 如何重新启动 logtest 线程,是否必须启动一个新线程而不是重新启动它?

  2. 从下面的代码可以看出,在LogThread类的run方法中,我使用Thread.Sleep(3)来逐行输出这些数字。如果我删除这一行,线程要么死在中间,要么一次性输出所有这 10000 行。我是否必须强制线程停止 3 毫秒以牺牲其性能?有没有更好的方法来解决这个问题?

代码:

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.text.StyledDocument;

public class LogTest {
  private LogThread logtest;
  public LogTest() {
    JFrame frame = new JFrame("LogTest");
    Container con = frame.getContentPane();
    final JTextPane pane = new JTextPane();
    final JScrollPane scollPane = new JScrollPane(pane);
    JButton button = new JButton("Start Test Log");
    JButton button1 = new JButton("Stop Test Log");
    logtest = new LogThread(pane);
    con.add(scollPane);
    con.add(button, BorderLayout.NORTH);
    con.add(button1, BorderLayout.SOUTH);
    button.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        logtest.start();
      }
    });
    button1.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        logtest.stop();
      }

    });
    frame.setSize(600, 500);
    frame.setVisible(true);
  }

  public static void main(String[] args) {
    new LogTest();
  }

}

class LogThread implements Runnable {
  private final Thread t;
  private String newline;
  private volatile boolean shouldStop = false;
  private StyledDocument doc;
  private JTextPane pane;
  private static int counter = 0;

  public LogThread(JTextPane pane) {
    this.doc = pane.getStyledDocument();
    this.pane = pane;
    t = new Thread(this, "Log Thread");
    newline = System.getProperty("line.separator");
  }

  public void start() {
    t.start();
  }

  public void run() {
    try {
      if (doc.getLength() > 0) {
        doc.remove(0, doc.getLength());
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    if(shouldStop) shouldStop=false;
    for (int i = counter; i <= 1000 && !shouldStop; i++) {
      try {
        doc.insertString(doc.getLength(),
            i + "-------------------------------------------------------------"+ newline,
            null);
        pane.setCaretPosition(doc.getLength());
        Thread.sleep(3);
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

  public void stop() {
    shouldStop = true;    
  }
}

【问题讨论】:

  • 你不能。 Thread 是不可重入的,这意味着您不能多次调用 start。您需要创建一个新的 Thread 并将其传递给 Runnable 实例的引用并启动 Thread

标签: java multithreading restart


【解决方案1】:

基本上,你不能从JavaDocs...

多次启动一个线程是不合法的。特别是,一个 线程一旦完成执行就可能不会重新启动。

您需要做的是,当调用start 时,创建一个新的Thread,将this 传递给它并启动该线程。您将需要确定 Thread 是否已在运行并首先采取措施终止它

class LogThread implements Runnable {
  private final Thread t;
  //....

  public LogThread(JTextPane pane) {
      //...
      //t = new Thread(this, "Log Thread");
      //...
  }

  public void start() throws InterruptedException {
    if (t != null && t.isAlive()) {
        shouldStop = true;
        t.join();
    }
    shouldStop = false;
    t = new Thread(this, "Log Thread");
    t.start();
  }

  //...

  public void stop() throws InterruptedException {
    shouldStop = true;    
    t.join();
    t = null;
  }
} 

您还违反了 Swing 的单线程规则,从 Event Dispatching Thread 的上下文之外修改 UI 的状态...

特别是……

pane.setCaretPosition(doc.getLength());

更安全的解决方案是使用 SwingWorker 并从内部更新 UI,然后使用 process 方法。

查看How to use SwingWorker了解更多详情

【讨论】:

    猜你喜欢
    • 2010-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-22
    相关资源
    最近更新 更多