无法检索 Java 个线程来停止它

Can't retrieve Java thread to stop it

我有一个带有开始和停止按钮的简单 Java GUI。我使用开始按钮 运行 线程和停止按钮来停止它。线程开始正常,但我无法用停止按钮停止它。这是我的一段代码:

这是图形界面的class:

public class GridController implements ActionListener {
// Definisco la vista
private final GridView vista;

acqreg  acq;
public GridController(final GridView vista)  {
    this.vista = vista;

} 

@Override
public void actionPerformed(final ActionEvent e)  {
  Object src = e.getSource();  
  String ID = null;
  String IP = null;



  if (src == this.vista.startacqButton) {      

        // Reset di tutte le Label di errore
        this.resetLabels();

        // Check degli input sui campi
        if (this.checkAllInputs()) {
            // CONTROLLO CAMPI ANDATO A BUON FINE
            System.out.println("Campi Compilati Correttamente");

            // Inibisco le pressioni successive del bottone start
            this.vista.startacqButton.setEnabled(false);
            // Inibisco la modifica dei campi inseriti sul form
            this.vista.getcbIDphidget().setEnabled(false);
            this.vista.gettfMiscela().setEnabled(false);
            this.vista.gettfLotto().setEnabled(false);
            this.vista.gettfDataop().setEnabled(false);
            // Riattivo lo stop button
            this.vista.stopacqButton.setEnabled(true);

            // POSSO FAR PARTIRE L'ACQUISIZIONE -----------------------------------------------------------------------------------------------------------------

            try {

                // Recupero la coppia ID Scheda - IP Scheda dal file conf
                BufferedReader phidgetip = new BufferedReader(new  FileReader("PhidgetsIP.conf"));
                String riga;
                while ( (riga = phidgetip.readLine()) != null){
                    String[] parts = riga.split("#");
                    String part1 = parts[0];  // ID Phidget
                    String part2 = parts[1]; // IP Phidget


                        if (part1.equals(this.vista.cbIDphidget.getSelectedItem())) {
                            ID = part1;
                            IP = part2;


                            // Creo oggetto per l'acquisizione
                            acq = new acqreg(ID , IP , vista);
                            //Avvio il thread
                            acq.start();

                            }

                }
            } catch (FileNotFoundException ex) {
                Logger.getLogger(GridController.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(GridController.class.getName()).log(Level.SEVERE, null, ex);
            }

            // Ho trovato l'ID giusto --> apro il canale di comunicazione



        }else{ 
            System.out.println("Alcuni campi non sono stati compilati correttamente");
                }


  }else if(src == this.vista.stopacqButton ){

            // Inibisco le pressioni successive del bottone stop
            this.vista.stopacqButton.setEnabled(false);
            // Riattivo lo start button
            this.vista.startacqButton.setEnabled(true);
            // Inibisco la modifica dei campi inseriti sul form
            this.vista.getcbIDphidget().setEnabled(true);
            this.vista.gettfMiscela().setEnabled(true);
            this.vista.gettfLotto().setEnabled(true);
            this.vista.gettfDataop().setEnabled(true);
            // Stoppo l'acquisizione

            acq.interrupt();
  }                                                                                            
  }

}

...这是 运行 线程 "acq" 的 class。

public class acqreg extends Thread {

private final String ID;
private final String IP;
private final GridView vista;



public acqreg(String ID , String IP, GridView vista){
    this.IP=IP;
    this.ID = ID;
    this.vista=vista;

}



 public void run()  {



    stopped=false;


        try{

            //.....do something.....




            //dichiarazione variabili di acquisizione
            final long start = System.nanoTime();     
            int seriale;
            double tempDevice;
            double tempAmbiente;
            long  prg = 1;

                    //Ciclo di acquisizione
                    while (!stopped) { 

                    // ....do the long work....

                    Thread.sleep(1000);




                    }

    }
        }catch(Exception ex){



        }
}

@Override
public void  interrupt() {


 stopped=true;


}

我认为问题出在我定义线程对象的地方"acq"(在 try catch 块中):

                           // Creo oggetto per l'acquisizione
                            acq = new acqreg(ID , IP , vista);
                            //Avvio il thread
                            acq.start();

因为当我试图停止线程时:

else if(src == this.vista.stopacqButton ){

        .......some code.........

        // Stoppo l'acquisizione

        acq.interrupt();

interrupt() 方法未启动,线程继续 运行ning!在调试模式下,我在 "acq.interrupt()":

行出现此错误
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException

其实有几个问题:

1) 你的代码格式太糟糕了...至少使用一些 IDE 来为你做准备。

2) 您的 class 命名有误。请遵守命名约定。 Class 名称以 "C" 大写字母开头。

3) 最好不要使用方法名"interrupt()"。更糟糕的是,永远不要在 Thread/Runnable class 中覆盖此方法!除非在那里调用 super.interrupt() 这会导致严重的问题! 因为 interrupt() 正是可以让您的 sleep() 脱离暂停状态的一件事。

4) 至少做一些基本的异常处理,你永远不应该忽略异常,除非你确切地知道你在做什么,然后它应该被评论!

这里有一个小例子,说明一个比较体面的工作线程应该是什么样子。它从调用者那里带走了所有与线程相关的东西,并且只授予对 startThread() 和 stopThread() 方法的访问权限。这样就不会受到外界的错误干扰。

/**
 * This worker can only run once
 * @author JayC667
 */
public class ProperThreading {

    private final Thread        mThread         = new Thread(() -> runWorkingLoop());   // if you want worker to be able to run multiple times, move initialisation into startThread()
    private volatile boolean    mThreadStarted  = false;
    private volatile boolean    mStopRequested  = false;

    private final long          mLoopSleepTime;

    public ProperThreading(final long pLoopSleepTime /* pass more arguments here, store in members */ ) {
        mLoopSleepTime = pLoopSleepTime;
    }

    public synchronized void startThread() {
        if (mThreadStarted) throw new IllegalStateException("Worker Thread may only be started once and is already running!");
        mThreadStarted = true;
        mThread.start();
    }

    private void runWorkingLoop() {
        while (!mStopRequested /* && other checks */ ) {
            try {
                // do the magic work here
                Thread.sleep(mLoopSleepTime);

            } catch (final InterruptedException e) {
                break;
            } catch (final Exception e) {
                // do at least some basic handling here, you should NEVER ignore exception unless you know exactly what you're doing, and then it should be commented!
            }
        }
    }

    public synchronized void stopThread() {
        if (!mThreadStarted) throw new IllegalStateException("Worker Thread is not even running yet!");
        mStopRequested = true;
        mThread.interrupt();
    }

}

谢谢大家的宝贵意见,我解决了NullPointerException。问题出在 acq 对象的声明中,它必须是 STATIC。现在线程工作正常。