Keeping and checking Process alive in Java 1.7 - java

How to make sure process (java.lang.Process) is alive in Java 1.7. In Java 1.8, there is isAlive() method. How can it be done in Java 1.7.
Thank you!

Probably wait too late, but since I faced the same problem, here is my solution:
Just copy the implementation of the Process.isAlive() method from Java 8:
public boolean isAlive() {
try {
exitValue();
return false;
} catch(IllegalThreadStateException e) {
return true;
}
}

with out knowing about the context of need of the Process. But in general, we could use Threads with Executors framework..
Executors.newCachedThreadPool()
Then submit Tasks to it...

I used the following for monitoring multiple processes launched through a Swing application. It follows the same logic mentioned by #mastah. See whether it helps.
package snippet;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class ProcessMonitor extends Thread {
private Process process;
private int exitCode;
public ProcessMonitor(Process process) {
this.process = process;
start();
}
#Override public void run() {
try {
exitCode = process.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void setOutputStream(final OutputStream s) {
new Thread(new Runnable() {
#Override public void run() {
InputStream is = process.getInputStream();
int c ;
try {
while((c = is.read()) >= 0) {
s.write(c);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
public void setErrorStream(final OutputStream s) {
new Thread(new Runnable() {
#Override public void run() {
InputStream is = process.getErrorStream();
int c ;
try {
while((c = is.read()) >= 0) {
s.write(c);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
public int getExitCode() {
return exitCode;
}
public static void main(String[] args) throws IOException, InterruptedException {
if(args.length == 1) {
System.err.println("In child process.. going to sleep for 1 second");
Thread.sleep(1000);
System.err.println("In child process.. done sleep exiting...");
System.exit(-1);
}
String[] pbArgs = new String[] {
"java", "-cp", System.getProperty("java.class.path"), ProcessMonitor.class.getName(), "arg"
};
ProcessBuilder pb = new ProcessBuilder(pbArgs);
pb.redirectErrorStream(true);
System.out.println("Starting process: " + pb.command());
final Process process = pb.start();
ProcessMonitor pm = new ProcessMonitor(process);
pm.setOutputStream(System.err);
while (pm.isAlive()) {
System.out.println("Process is still alive");
Thread.sleep(1000);
}
System.out.println("Process exited with: " + pm.getExitCode());
}
}

Related

cmd command from java application error

Recently I added "adb devices" in the nano ./bash_profile so that I can run it from any directory.
I used one java application to run
public static void main(String [] args) {
executeCmd("adb devices");
}
private static void executeCmd(String string) {
InputStream pipedOut = null;
try {
Process aProcess = Runtime.getRuntime().exec(string);
// These two thread shall stop by themself when the process end
Thread pipeThread = new Thread(new StreamGobber(aProcess.getInputStream()));
Thread errorThread = new Thread(new StreamGobber(aProcess.getErrorStream()));
pipeThread.start();
errorThread.start();
aProcess.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
class StreamGobber implements Runnable {
private InputStream Pipe;
public StreamGobber(InputStream pipe) {
if(pipe == null) {
throw new NullPointerException("bad pipe");
}
Pipe = pipe;
}
public void run() {
try {
byte buffer[] = new byte[2048];
int read = Pipe.read(buffer);
while(read >= 0) {
System.out.write(buffer, 0, read);
read = Pipe.read(buffer);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(Pipe != null) {
try {
Pipe.close();
} catch (IOException e) {
}
}
}
when I run any other commands such as "ls" it's working fine!!
I'm using mac ..
thanks :)
Maybe global path problem on mac. You can try run with absolute adb program path as command.

Java application and AMD processor issues

We have a windows application, which was tested on Windows XP, 7, 8, 8.1. Application consists of 2 parts: Bootstrap and main application. Bootstrap assures updates of the main app, and updates main app at a particular point. But users were able to force stop Boostrap process via the Task Manager (Ctrl+Shift+ESC->processes) by killing a process named javaw. In that case main app would not update and elder version would be launched. To avoid such issue we introduced interface of Bootstrap with main application via Socket. Here are the VM parameters of Bootstrap when it starts:
javaw.exe -Xms75M -Xmx90M -Xincgc -jar bootstrap.jar
There is a class SocketServer in the bootstrap:
public class Provider {
ServerSocket providerSocket;
Socket connection = null;
ObjectOutputStream out;
ObjectInputStream in;
String message;
public Provider() {
}
public void run() {
try{
providerSocket = new ServerSocket(54345);
connection = providerSocket.accept();
out = new ObjectOutputStream(connection.getOutputStream());
out.flush();
in = new ObjectInputStream(connection.getInputStream());
sendMessage("Connection successful");
do {
try {
message = (String)in.readObject();
if (message.equals("bye")) {
sendMessage("bye");
}
} catch(ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
} while (!message.equals("bye"));
} catch(IOException ioe) {
ioe.printStackTrace();
} finally {
try {
in.close();
out.close();
providerSocket.close();
} catch(IOException ioef) {
ioef.printStackTrace();
}
}
}
public void sendMessage(String msg) {
try {
out.writeObject(msg);
out.flush();
} catch(IOException ioe) {
ioe.printStackTrace();
}
}
public void stop() {
if (providerSocket != null && in != null && out != null && !providerSocket.isClosed()) {
try {
in.close();
out.close();
providerSocket.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
}
Main app is being started by Bootstrap via ProcessBuilder like so:
public static void communicate(Process process) {
final BufferedReader stdOut = new BufferedReader(new InputStreamReader(process.getInputStream(), Charset.forName("Windows-1251")));
final BufferedReader stdErr = new BufferedReader(new InputStreamReader(process.getErrorStream(), Charset.forName("Windows-1251")));
//InputStream
new Thread() {
#Override
public void run() {
String line;
try {
while ((line = stdOut.readLine()) != null) {
debugOut(line);
}
} catch (Exception e) {
e.printStackTrace();
}
try {
stdOut.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}.start();
//ErrorStream
new Thread() {
#Override
public void run() {
String line;
try {
while ((line = stdErr.readLine()) != null) {
debugOut(line);
}
} catch (Exception e) {
e.printStackTrace();
}
try {
stdErr.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}.start();
try {
final Provider provider = new Provider();
ExecutorService pEexec = Executors.newCachedThreadPool();
Future<Void> FPExec = pEexec.submit(new Callable<Void>() {
#Override
public Void call() throws Exception {
while (!Thread.currentThread().isInterrupted()) {
provider.run();
}
return null;
}
});
pEexec.shutdown();
process.waitFor();
debugOut("[MainApp] Exit");
provider.stop();
FPExec.cancel(true);
debug("Destroy process");
process.destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void startApp() {
try {
ArrayList<String> params = new ArrayList<String>();
...
params.add("-Xms32M");
params.add("-Xmx48M");
params.add("-Xincgc");
params.add("-cp");
params.add(new File(pathToJar, "mainapp.jar").getPath());
params.add("net.craftwork.mainapp.AppStart");
params.add(licCode());
ProcessBuilder procBuild = new ProcessBuilder(params);
debugOut("[MainApp] Start");
Process proc = procBuild.start();
communicate(proc);
} catch (Exception e) {
e.printStackTrace();
}
}
There is a class SocketClient in the main app:
public class Requester {
Socket requestSocket;
ObjectOutputStream out;
ObjectInputStream in;
String message;
static Future<Void> oExec;
Requester() {
}
void run() {
try {
requestSocket = new Socket("localhost", 54345);
out = new ObjectOutputStream(requestSocket.getOutputStream());
out.flush();
in = new ObjectInputStream(requestSocket.getInputStream());
do {
try {
message = (String)in.readObject();
sendMessage("bye");
} catch(ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
} while (!message.equals("bye"));
} catch(UnknownHostException uhe) {
uhe.printStackTrace();
} catch(IOException ioe) {
ioe.printStackTrace();
oExec.cancel(true);
CommonUtils.debug("Bootstrap not found. Exit.");
System.exit(0);
} finally {
try {
in.close();
out.close();
requestSocket.close();
} catch(IOException ioef) {
ioef.printStackTrace();
}
}
}
void sendMessage(String msg) {
try {
out.writeObject(msg);
out.flush();
} catch(IOException ioe) {
ioe.printStackTrace();
}
}
public static void main() {
final Requester client = new Requester();
ExecutorService exec = Executors.newCachedThreadPool();
oExec = exec.submit(new Callable<Void>() {
#Override
public Void call() throws Exception {
while (!Thread.currentThread().isInterrupted()) {
client.run();
Thread.sleep(1000);
}
return null;
}
});
exec.shutdown();
}
}
Socket Client is called when main application starts
public class AppStart {
public static void main(final String[] args) {
Requester.main();
EventQueue.invokeLater(new Runnable() {
public void run() {
...
}
});
}
}
This is all to it I do believe. Whole setup worked perfectly fine, even on slower computers. Problem is that after introduction of Socket interface we had major complaints from some users, reporting crashes. Took us some time to figure out the issue, but here is what we found: computers with Intel processors are perfectly fine, only ones with AMD processors crash. Crash normally happens within 3 to 15 minutes from the start of Bootstrap. When crash occurs resources of the computer are not fully used, processor workload is about 20-50% and RAM is quite free as well. When crash occurs user is only able to reset computer using hardware reset or power button, nothing else responds. All users have latest JAVA 1.7.0_51. Whether system is 32 or 64 bit does both crash (or not crash if it is Intel based). Please share your thoughts. May be someone had identical issues and could help me to figure this out.

How to use exitValue() with parameter?

A very good article (When Runtime.exec() won't) says: The only possible time you would use exitValue() instead of waitFor() would be when you don't want your program to block waiting on an external process that may never complete. Instead of using the waitFor() method, I would prefer passing a boolean parameter called waitFor into the exitValue() method to determine whether or not the current thread should wait. A boolean would be more beneficial because exitValue() is a more appropriate name for this method, and it isn't necessary for two methods to perform the same function under different conditions. Such simple condition discrimination is the domain of an input parameter.
I have exactly same situation where my system call would start a process which will keep running until user decides to kill it. If I use '(process.waitFor() == 0)' it will block program there because process will not be completed. Author in article above suggest that exitValue() can be used with 'waitFor' parameter. Did anybody try it out ? Any example would be helpful.
Code:
// Start ProcessBuilder, 'str' contains a command
ProcessBuilder pbuilder = new ProcessBuilder(str);
pbuilder.directory(new File("/root/workspace/Project1"));
pbuilder.redirectErrorStream(true);
Process prcs = pbuilder.start();
AForm.execStatustext.append("\n=> Process is:" + prcs);
// Read output
StringBuilder out = new StringBuilder();
BufferedReader bfrd = new BufferedReader(new InputStreamReader(process.getInputStream()));
String current_line = null, previous_line = null;
while ((current_line = bfrd.readLine()) != null) {
if (!line.equals(previous_line)) {
previous_line = current_line;
out.append(current_line).append('\n');
//System.out.println(line);
}
}
//process.getInputStream().close();
// Send 'Enter' keystroke through BufferedWriter to get control back
BufferedWriter bfrout = new BufferedWriter(new OutputStreamWriter(prcs.getOutputStream()));
bfrout.write("\\r");
bfrout.newLine();
bfrout.flush();
bfrout.write("\\r");
bfrout.newLine();
bfrout.flush();
//process.getOutputStream().close();*/
if (prcs.waitFor() == 0)
System.out.println("Commands executed successfully");
System.exit(0);
This is a "rough" example of some library code I use to launch external processes.
Basically, this uses three threads. The first is used to execute the actually command and then wait till it exists.
The other two deal with the processes output and input streams. This makes these independent of each other prevents the ability for one to block the other.
The whole thing is then tied together with a listener that is notified when something happens.
The error handling could be better (as the fail condition is a little unclear as to what/who actually failed), but the basic concept is there...
This means you can launch the process and not care...(until you want to)
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class TestBackgroundProcess {
public static void main(String[] args) {
new TestBackgroundProcess();
}
public TestBackgroundProcess() {
BackgroundProcess bp = new BackgroundProcess("java", "-jar", "dist/BackgroundProcess.jar");
bp.setListener(new ProcessListener() {
#Override
public void charRead(BackgroundProcess process, char value) {
}
#Override
public void lineRead(BackgroundProcess process, String text) {
System.out.println(text);
}
#Override
public void processFailed(BackgroundProcess process, Exception exp) {
System.out.println("Failed...");
exp.printStackTrace();
}
#Override
public void processCompleted(BackgroundProcess process) {
System.out.println("Completed - " + process.getExitValue());
}
});
System.out.println("Execute command...");
bp.start();
bp.send("dir");
bp.send("exit");
System.out.println("I'm not waiting here...");
}
public interface ProcessListener {
public void charRead(BackgroundProcess process, char value);
public void lineRead(BackgroundProcess process, String text);
public void processFailed(BackgroundProcess process, Exception exp);
public void processCompleted(BackgroundProcess process);
}
public class BackgroundProcess extends Thread {
private List<String> commands;
private File startIn;
private int exitValue;
private ProcessListener listener;
private OutputQueue outputQueue;
public BackgroundProcess(String... cmds) {
commands = new ArrayList<>(Arrays.asList(cmds));
outputQueue = new OutputQueue(this);
}
public void setStartIn(File startIn) {
this.startIn = startIn;
}
public File getStartIn() {
return startIn;
}
public int getExitValue() {
return exitValue;
}
public void setListener(ProcessListener listener) {
this.listener = listener;
}
public ProcessListener getListener() {
return listener;
}
#Override
public void run() {
ProcessBuilder pb = new ProcessBuilder(commands);
File startIn = getStartIn();
if (startIn != null) {
pb.directory(startIn);
}
pb.redirectError();
Process p;
try {
p = pb.start();
InputStreamConsumer isc = new InputStreamConsumer(p.getInputStream(), this, getListener());
outputQueue.init(p.getOutputStream(), getListener());
outputQueue.start();
p.waitFor();
isc.join();
outputQueue.terminate();
outputQueue.join();
ProcessListener listener = getListener();
if (listener != null) {
listener.processCompleted(this);
}
} catch (InterruptedException ex) {
ProcessListener listener = getListener();
if (listener != null) {
listener.processFailed(this, ex);
}
} catch (IOException ex) {
ProcessListener listener = getListener();
if (listener != null) {
listener.processFailed(this, ex);
}
}
}
public void send(String cmd) {
outputQueue.send(cmd);
}
}
public class OutputQueue extends Thread {
private List<String> cmds;
private OutputStream os;
private ProcessListener listener;
private BackgroundProcess backgroundProcess;
private ReentrantLock waitLock;
private Condition waitCon;
private boolean keepRunning = true;
public OutputQueue(BackgroundProcess bp) {
backgroundProcess = bp;
cmds = new ArrayList<>(25);
waitLock = new ReentrantLock();
waitCon = waitLock.newCondition();
}
public ProcessListener getListener() {
return listener;
}
public OutputStream getOutputStream() {
return os;
}
public BackgroundProcess getBackgroundProcess() {
return backgroundProcess;
}
public void init(OutputStream outputStream, ProcessListener listener) {
os = outputStream;
this.listener = listener;
}
public void send(String cmd) {
waitLock.lock();
try {
cmds.add(cmd);
waitCon.signalAll();
} finally {
waitLock.unlock();
}
}
public void terminate() {
waitLock.lock();
try {
cmds.clear();
keepRunning = false;
waitCon.signalAll();
} finally {
waitLock.unlock();
}
}
#Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
}
BackgroundProcess backgroundProcess = getBackgroundProcess();
ProcessListener listener = getListener();
OutputStream outputStream = getOutputStream();
try {
while (keepRunning) {
while (cmds.isEmpty() && keepRunning) {
waitLock.lock();
try {
waitCon.await();
} catch (Exception exp) {
} finally {
waitLock.unlock();
}
}
if (!cmds.isEmpty()) {
waitLock.lock();
try {
while (!cmds.isEmpty()) {
String cmd = cmds.remove(0);
System.out.println("Send " + cmd);
outputStream.write(cmd.getBytes());
outputStream.write('\n');
outputStream.write('\r');
outputStream.flush();
}
} finally {
waitLock.unlock();
}
}
}
} catch (IOException ex) {
if (listener != null) {
listener.processFailed(backgroundProcess, ex);
}
}
}
}
public class InputStreamConsumer extends Thread {
private InputStream is;
private ProcessListener listener;
private BackgroundProcess backgroundProcess;
public InputStreamConsumer(InputStream is, BackgroundProcess backgroundProcess, ProcessListener listener) {
this.is = is;
this.listener = listener;
this.backgroundProcess = backgroundProcess;
start();
}
public ProcessListener getListener() {
return listener;
}
public BackgroundProcess getBackgroundProcess() {
return backgroundProcess;
}
#Override
public void run() {
BackgroundProcess backgroundProcess = getBackgroundProcess();
ProcessListener listener = getListener();
try {
StringBuilder sb = new StringBuilder(64);
int in = -1;
while ((in = is.read()) != -1) {
char value = (char) in;
if (listener != null) {
listener.charRead(backgroundProcess, value);
if (value == '\n' || value == '\r') {
if (sb.length() > 0) {
listener.lineRead(null, sb.toString());
sb.delete(0, sb.length());
}
} else {
sb.append(value);
}
}
}
} catch (IOException ex) {
listener.processFailed(backgroundProcess, ex);
}
}
}
}
Before using waitFor in main thread, create another thread (child) and construct logic for your termination cases in this new thread. For example, wait for 10 secs.
If the condition is fulfilled, then interrupt the main thread from the child thread ant handle the following logic on your main thread.
The following code creates a child thread to invoke the process and the main thread does its work until the child finishes successfully.
import java.io.IOException;
public class TestExecution {
public boolean myProcessState = false;
class MyProcess implements Runnable {
public void run() {
//------
Process process;
try {
process = Runtime.getRuntime().exec("your command");
process.waitFor();
int processExitValue = process.exitValue();
if(processExitValue == 0) {
myProcessState = true;
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void doMyWork() {
MyProcess myProcess = new MyProcess();
Thread myProcessExecuter = new Thread(myProcess);
myProcessExecuter.start();
while(!myProcessState) {
// do your job until the process exits with success
}
}
public static void main(String[] args) {
TestExecution testExecution = new TestExecution();
testExecution.doMyWork();
}
}
If I use '(process.waitFor() == 0)' it will block program there because process will not be completed.
No it won't. It will block the thread. That's why you have threads.
Author in article above suggest that exitValue() can be used with 'waitFor' parameter
No he doesn't. He is talking about how he would have designed it, if anybody had asked him. But they didn't, and he didn't.
Did anybody try it out ?
You can't. It doesn't exist.

Problem getting output and passing input to a executing process running under java

I am trying to call a simple program test.exe which is as simple as-
int main()
{
int a;
cout<<"Welcome\n";
while(cin>>a&&a!=0)
cout<<"you entered "<<a<<endl;
}
I want to run it from a java program as a process, and send+recieve i/o from it. I am using the process with 2 threads as follows-
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Processproblem {
public static void main(String[] args)throws IOException, InterruptedException {
final Process process;
try {
process = Runtime.getRuntime().exec("test.exe");
} catch (IOException e1) {
e1.printStackTrace();
return;
}
new Thread(new Runnable() {
public void run() {
String line;
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
try {
while ((line = br.readLine()) != null) {
System.out.println("[OUT] " + line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
public void run() {
try {
byte[] buffer = new byte[1024];
int reading=0;
System.out.println(reading);
BufferedWriter bw= new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
while(reading!=-1)
{
reading= System.in.read(buffer);
for(int i = 0; i < buffer.length; i++) {
int intValue = new Byte(buffer[i]).intValue();
if (intValue == 0) {
reading = i;
break;
}
else
{
bw.append((char)intValue);
}
}
bw.newLine();
bw.flush();
}
} catch (Exception e) {
}
}
}
).start();
}
}
But they are not working as expected. When i run the program it just shows the "Welcome\n" message and then stops for input. When i give a integer and press enter in the java console it does nothing.
What am I doing wrong? They are two separate threads so why are they blocking each other? Is there any problem in my concept?
The program waits for your input. Grab the process output stream (using getOutputStream) and write to it.

how to restart a thread

I tried to write a file monitor which will check the file if a new line is appended,the monitor in fact is a thread which will read the line by a randomaccessfile all the time.
This is the monitor core codes:
public class Monitor {
public static Logger log = Logger.getLogger(Monitor.class);
public static final Monitor instance = new Monitor();
private static final ArrayList<Listener> registers = new ArrayList<Listener>();
private Runnable task = new MonitorTask();
private Thread monitorThread = new Thread(task);
private boolean beStart = true;
private static RandomAccessFile raf = null;
private File monitoredFile = null;
private long lastPos;
public void register(File f, Listener listener) {
this.monitoredFile = f;
registers.add(listener);
monitorThread.start();
}
public void replaceFile(File newFileToBeMonitored) {
this.monitoredFile = newFileToBeMonitored;
// here,how to restart the monitorThread?
}
private void setRandomFile() {
if (!monitoredFile.exists()) {
log.warn("File [" + monitoredFile.getAbsolutePath()
+ "] not exist,will try again after 30 seconds");
try {
Thread.sleep(30 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
setRandomFile();
return;
}
try {
if (raf != null) {
raf.close();
lastPos = 0;
}
raf = new RandomAccessFile(monitoredFile, "r");
log.info("monitor file " + monitoredFile.getAbsolutePath());
} catch (FileNotFoundException e) {
// The file must exist now
} catch (IOException e) {}
}
private void startRead() {
beStart = true;
String line;
while (beStart) {
try {
raf.seek(lastPos);
while ((line = raf.readLine()) != null) {
fireEvent(new FileEvent(monitoredFile.getAbsolutePath(),
line));
}
lastPos = raf.getFilePointer();
} catch (IOException e1) {}
}
}
private void stopRead() {
this.beStart = false;
}
private void fireEvent(FileEvent event) {
for (Listener lis : registers) {
lis.lineAppended(event);
}
}
private class MonitorTask implements Runnable {
#Override
public void run() {
stopRead();
//why putting the resetReandomAccessFile in this thread method is that it will sleep if the file not exist.
setRandomFile();
startRead();
}
}
}
This is some help classes:
public interface Listener {
void lineAppended(FileEvent event);
}
public class FileEvent {
private String line;
private String source;
public FileEvent(String filepath, String addedLine) {
this.line = addedLine;
this.source = filepath;
}
//getter and setter
}
And this is a example to call the monitor:
public class Client implements Listener {
private static File f = new File("D:/ab.txt");
public static void main(String[] args) {
Monitor.instance.register(f, new Client());
System.out.println(" I am done in the main method");
try {
Thread.sleep(5000);
Monitor.instance.replaceFile(new File("D:/new.txt"));
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
#Override
public void lineAppended(FileEvent event) {
String line = event.getLine();
if (line.length() <= 0)
return;
System.err.println("found in listener:" + line + ":" + line.length());
}
}
Now,my probelm is the code work well if I just call:
Monitor.instance.register(file,listener);
This will monitor the file for line appending,and will notify the listener.
However it does not work when I call the :
Monitor.instance.replaceFile(anotherfile);
This means I want to monitor another file rather than before.
So in my Monitor I have to restart the thread,how to make it?
I have tried the:
monitorThread.interruppt();
It does not wrok.
Anyone can fix it for me or tell me how to do ?
Thanks.
Before I ask,I have googling the "restart java thread",so I know one can not restart a dead thread,but my thread does not return,so I think it can be restarted.
You don't restart a Thread, instead you create a new one each time you want to start a thread.
A better alternative may be to use Executors.newCachedThreadPool() which gives you a pool of thread which will be started/recycle for you.
BTW: You are using recursion rather than a loop to poll if the file exists. Using recursion can mean if you wait too long it will throw a StackOverflowError. IMHO you shouldn't wait at all, the polling thread should repeatedly attempt to open the file until it is told to stop (or the file appears)
Your current implementation also means if the file is replaced, you will have to reopen the file in the background thread anyway.
Instead of explaining, I just coded up a skeleton example. I did not test it terribly well, but it may be of some use.
In order to monitor a(nother) file, just create a new Monitor, passing it a ScheduledExecutorService. Starting and stopping monitoring is straightforward. You can (should) reuse the same executor for multiple monitors.
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public interface Event
{
}
public interface Listener
{
void handle(Event event);
}
public class Monitor
{
private static final int CHECK_EVERY_SECONDS = 10;
private static final int RECHECK_AFTER_IF_NOT_EXISTS_SECONDS = 30;
private File file;
private ScheduledExecutorService executor;
private boolean active;
private List<Listener> listeners;
public Monitor(File file, ScheduledExecutorService executor)
{
super();
this.file = file;
this.executor = executor;
listeners = new ArrayList<Listener>();
}
public synchronized void start()
{
if (active)
{
return;
}
active = true;
executor.execute(new Runnable()
{
public void run()
{
synchronized (Monitor.this)
{
if (!active)
{
System.out.println("not active");
return;
}
}
if (!file.exists())
{
System.out.println("does not exist, rescheduled");
executor.schedule(this, RECHECK_AFTER_IF_NOT_EXISTS_SECONDS, TimeUnit.SECONDS);
return;
}
Event event = doStuff(file);
System.out.println("generated " + event);
updateListeners(event);
System.out.println("updated listeners and rescheduled");
executor.schedule(this, CHECK_EVERY_SECONDS, TimeUnit.SECONDS);
}
});
}
private Event doStuff(final File file)
{
return new Event()
{
public String toString()
{
return "event for " + file;
}
};
}
public synchronized void stop()
{
active = false;
}
public void addListener(Listener listener)
{
synchronized (listeners)
{
listeners.add(listener);
}
}
public void removeListener(Listener listener)
{
synchronized (listeners)
{
listeners.remove(listener);
}
}
private void updateListeners(Event event)
{
synchronized (listeners)
{
for (Listener listener : listeners)
{
listener.handle(event);
}
}
}
public static void main(String[] args) throws IOException
{
ScheduledExecutorService executor = Executors.newScheduledThreadPool(4);
File file = new File("test.png");
Monitor monitor = new Monitor(file, executor);
monitor.addListener(new Listener()
{
public void handle(Event event)
{
System.out.println("handling " + event);
}
});
monitor.start();
System.out.println("started...");
System.in.read();
monitor.stop();
System.out.println("done");
executor.shutdown();
}
}
See this post How to start/stop/restart a thread in Java?
I assume you answered your question
one can not restart a dead thread
This link may be helpful to you How to restart thread in java?
A thread in Java cannot be re-started. Every time you need to restart the thread you must make a new one.
That said, you might want to look at:
private void setRandomFile() {
if (!monitoredFile.exists()) {
log.warn("File [" + monitoredFile.getAbsolutePath()
+ "] not exist,will try again after 30 seconds");
try {
Thread.sleep(30 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
setRandomFile();
return;
}
// ....
}
Here you sleep for 30 seconds if the file does not exist, then recursively call the same function. Now, I don't know what business requirements you have, but if this recursion ran long enough you will run out of stack space. Perhaps you will be better served with a while loop or even better, a little synchronisation like a Semaphore.

Categories

Resources