无法检索 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。现在线程工作正常。
我有一个带有开始和停止按钮的简单 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。现在线程工作正常。