Terminating a specific thread from a Multi-Threading program in Java
Am working on a program in Java as shown below, the class is simply executing commands into the operating system level. Yet, sometimes we are facing a problem where the program get stuck, so the command never return any status, thus the thread does not terminate.
Now am trying to enhance the code, add an additional thing where I can kill specific threads. Am already capturing the ThreadId, so, is this doable?
public class ExecuteCmd implements Runnable {
String ProcessId;
String cmd;
BackendSQL bsql;
Logger myLogger;
Thread myThread;
public ExecuteCmd(String cmd, BackendSQL bsql, String ProcessId, Logger myLogger) {
this.ProcessId=ProcessId;
this.cmd=cmd;
this.bsql=bsql;
this.myLogger=myLogger;
}
public void run() {
int rc = 0;
try {
long ThreadId = Thread.currentThread().getId();
bsql.MarkRunning(ProcessId, ThreadId);
myLogger.debug("[ExecuteCmd] Command is: "+cmd);
String[] cmdFull = cmd.split(";");
Runtime rt = Runtime.getRuntime();
Process p = rt.exec(cmdFull);
myLogger.info("[ExecuteCmd] [Threading] "+ ThreadId + ": Executing command");
myLogger.debug("[ExecuteCmd] Command is: "+cmd);
BufferedReader inStream = new BufferedReader(new InputStreamReader(p.getInputStream()));
String inStreamLine = null;
String inStreamLinebyLine=null;
while((inStreamLine = inStream.readLine()) != null) {
inStreamLinebyLine = inStreamLinebyLine+"\n"+inStreamLine;
}
myLogger.info("Command getInputStream: " + inStreamLinebyLine);
try {
rc = p.waitFor();
if (rc == 0)开发者_开发问答 {
bsql.MarkCompleted(ProcessId);
}else{
bsql.MarkFailed(ProcessId);
}
} catch (InterruptedException intexc) {
System.out.println("Interrupted Exception on waitFor: " +
intexc.getMessage());
}
}catch (IOException IOE) {
myLogger.error("IOException[ExecuteCmd]: " + IOE.getMessage());
}catch (Exception e) {
myLogger.error("Exception[ExecuteCmd]: " + e.getMessage());
}
}
}
You should submit instances of ExecuteCmd to an ExecutorService. That way, you can cancel or interrupt your tasks.
Process#waitFor() is an interruptible operation so it should work OK.
ExecutorService service = Executors.newSingleThreadedExecutor();
Future<?> future = service.submit(new ExecuteCmd(...));
if (takingTooLong()) {
future.cancel(true);
}
To address your fundamental problem (and thus why you need to interrupt a process), I suspect your process is hanging because you're not consuming standard out and standard error concurrently. Basically, if you don't do this, then your spawned process can hang. It's a very common problem. See this answer for more information and a fix.
Also see this Java Specialist newsletter on how to shutdown threads cleanly (via Thread.interrupt()), and how to handle this properly in the thread being shut down. You'll need to handle a shutdown properly even if you use Executor frameworks and the like, since they'll interrupt your thread.
I don't believe you'll need this, however, if you consume your program stdout/err concurrently.
I think Thread.Interrupt is what you'r looking for, you'll have to call it from another thread though.
http://java.sun.com/javase/6/docs/api/java/lang/Thread.html#interrupt%28%29
精彩评论