I have a Java program as follows:
public class foo{
public static void main(String[] args) throws Exception{
Thread t = new Thread(
new Runnable() {
public void run() {
try{System.in.read();}catch(Exception e){}
}
}
);
t.setDaemon(true);
t.start();
Thread.sleep(10); // Make sure it hits the read() call
t.interrupt();
t.stop();
System.exit(0);
}
}
Running this (time java foo) with the System.in.read call present takes ~480ms to exit while running it with the System.in.read call commented out takes ~120ms to exit
I had thought that once the main thread reaches the end, the program terminates, but clearly, there's another 300ms lag hanging around (you can see this by adding a println after the Thread.sleep). I tried t.interrupt t.stop System.exit which should stop things "immediately", but none of them seem able to make the program skip it's 350ms extra exit latency seemingly doing nothing.
Anyone know why that is the case, and if there's anything I can do to avoid this latency?
As it turns out besides collecting bad news, there is some workaround too, see the very bottom of this post.
This is not a full reply, just a check popped into my mind, with sockets.
Based on this and the System.in.read() experiment I have reproduced too, the delay may be the cost of having an outstanding synchronous I/O request towards the OS. (Edit: actually it is an explicit wait which kicks in when threads do not exit normally when the VM is shutting down, see below the horizontal line)
(I am ending the thread(s) with a while(true);, so it (they) never exits prematurely)
if you create a bound socket final ServerSocket srv=new ServerSocket(0);, exit remains 'normal'
if you srv.accept();, you suddenly have the extra wait
if you create an "inner" daemon thread with Socket s=new Socket("localhost",srv.getLocalPort());, and Socket s=srv.accept(); outside, it becomes 'normal' again
however if you invoke s.getInputStream().read(); on any of them, you have the extra wait again
if you do it with both sockets, extra wait extends a bit longer (much less than 300, but consistent 20-50 ms for me)
having the inner thread, it is also possible to get stuck on the new Socket(...); line, if accept() is not invoked outside. This also has the extra wait
So having sockets (just bound or even connected) is not a problem, but waiting for something to happen (accept(), read()) introduces something.
Code (this variant hits the two s.getInputSteam().read()-s)
import java.net.*;
public class foo{
public static void main(String[] args) throws Exception{
Thread t = new Thread(
new Runnable() {
public void run() {
try{
final ServerSocket srv=new ServerSocket(0);
Thread t=new Thread(new Runnable(){
public void run(){
try{
Socket s=new Socket("localhost",srv.getLocalPort());
s.getInputStream().read();
while(true);
}catch(Exception ex){}
}});
t.setDaemon(true);
t.start();
Socket s=srv.accept();
s.getInputStream().read();
while(true);
}catch(Exception ex){}
}
}
);
t.setDaemon(true);
t.start();
Thread.sleep(1000);
}
}
I also tried what appears in the comments: having access (I just used static) to ServerSocket srv, int port, Socket s1,s2, it is faster to kill things on the Java side: close() on srv/s1/s2 shuts down accept() and read() calls very fast, and for shutting down accept() in particular, a new Socket("localhost",port) also works (just it has a race condition when an actual connection arrives at the same time). A connection attempt can be shut down too with close(), just an object is needed for that (so s1=new Socket();s1.connect(new InetSocketAddress("localhost",srv.getLocalPort())); has to be used instead of the connecting constructor).
TL;DR: does it matter to you? Not at all: I tried System.in.close(); and it had absolutely no effect on System.in.read();.
New bad news. When a thread is in native code, and that native code does not check for 'safepoint', one of the final steps of the shutdown procedure waits for 300 milliseconds, minimum:
// [...] In theory, we
// don't have to wait for user threads to be quiescent, but it's always
// better to terminate VM when current thread is the only active thread, so
// wait for user threads too. Numbers are in 10 milliseconds.
int max_wait_user_thread = 30; // at least 300 milliseconds
And it is waiting in vain, because the thread is executing a simple fread on /proc/self/fd/0
While read (and recv too) is wrapped in some magical RESTARTABLE looping thing (https://github.com/openjdk-mirror/jdk7u-hotspot/blob/master/src/os/linux/vm/os_linux.inline.hpp#L168 and read is a bit lower - it is a wrapper for fread in yet another file), which seems to be aware of EINTR
#define RESTARTABLE(_cmd, _result) do { \
_result = _cmd; \
} while(((int)_result == OS_ERR) && (errno == EINTR))
[...]
inline size_t os::restartable_read(int fd, void *buf, unsigned int nBytes) {
size_t res;
RESTARTABLE( (size_t) ::read(fd, buf, (size_t) nBytes), res);
return res;
}
, but that is not happening anywhere, plus there are some comments here and there that they did not want to interfere with libpthread's own signalling and handlers. According to some questions here on SO (like How to interrupt a fread call?), it might not work anyway.
On the library side, readSingle (https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/native/java/io/io_util.c#L38) is the method which has been invoked:
jint
readSingle(JNIEnv *env, jobject this, jfieldID fid) {
jint nread;
char ret;
FD fd = GET_FD(this, fid);
if (fd == -1) {
JNU_ThrowIOException(env, "Stream Closed");
return -1;
}
nread = (jint)IO_Read(fd, &ret, 1);
if (nread == 0) { /* EOF */
return -1;
} else if (nread == JVM_IO_ERR) { /* error */
JNU_ThrowIOExceptionWithLastError(env, "Read error");
} else if (nread == JVM_IO_INTR) {
JNU_ThrowByName(env, "java/io/InterruptedIOException", NULL);
}
return ret & 0xFF;
}
which is capable of handling 'being interrupted' on JRE level, but that part just will not get executed as fread does not return (in case of everything non-Windows, that IO_Read is #define-d to JVM_Read, and that is just a wrapper for the restartable_read mentioned earlier)
So, it is by design.
One thing which works is to provide your own System.in (despite of being final there is a setIn() method for this purpose, doing the nonstandard swap in JNI). But it involves polling, so it is a bit ugly:
import java.io.*;
public class foo{
public static void main(String[] args) throws Exception{
System.setIn(new InputStream() {
InputStream in=System.in;
#Override
public int read() throws IOException {
while(in.available()==0)try{Thread.sleep(100);}catch(Exception ex){}
return in.read();
}
});
Thread t = new Thread(
new Runnable() {
public void run() {
try{
System.out.println(System.in.read());
while(true);
}catch(Exception ex){}
}
}
);
t.setDaemon(true);
t.start();
Thread.sleep(1000);
}
}
With the Thread.sleep() inside InputStream.read() you can balance between being unresponsive or cooking with the CPU. Thread.sleep() correctly checks for being shut down, so even if you put it up to 10000, the process will exit fast.
As others have commented, Thread interrupt does not cause a blocking I/O call to immediately stop. The wait is happening because system in is waiting on input from a File (stdin). If you were to supply the program with some initial input you will notice it finishes much faster:
$ time java -cp build/libs/testjava.jar Foo
real 0m0.395s
user 0m0.040s
sys 0m0.008s
$ time java -cp build/libs/testjava.jar Foo <<< test
real 0m0.064s
user 0m0.036s
sys 0m0.012s
If you want to avoid waiting on I/O threads, then you can check the availability first. You can then perform a wait using a method which is interruptable such as Thread.sleep:
while (true) {
try {
if (System.in.available() > 0) {
System.in.read();
}
Thread.sleep(400);
}
catch(Exception e) {
}
}
This program will exit quickly each time:
$ time java -cp build/libs/testjava.jar Foo
real 0m0.065s
user 0m0.040s
sys 0m0.008s
$ time java -cp build/libs/testjava.jar Foo <<< test
real 0m0.065s
user 0m0.040s
sys 0m0.008s
Related
I have the following thread:
Thread t1 = new Thread() {
#Override
public void run() {
while (!progress.equals(duration)) {
try {
Thread.sleep(1000);
progress = progress.plusSeconds(1);
// synchronized (this) { while (paused) { this.wait(); } }
} catch (InterruptedException e) {
interrupt();
}
}
}
};
t1.start();
I'm trying to implement a functionality which allows the user to pause and stop this thread using the console. Basically, this:
Scanner sc = new Scanner(System.in);
int choice;
while (t1.isAlive()) {
System.out.println("Choose an option:\n1. Pause/Resume\n2. Stop");
choice = Integer.parseInt(sc.nextLine());
// if (choice == 1) { ... } else if (choice == 2) { t1.interrupt() }
// synchronized (t1) { t1.notify(); }
}
My problem is that once t1 dies, t1.isAlive() evaluates to false, but the program doesn't exit the while loop because it is stuck waiting for one last input from the user. I want to interrupt sc.nextLine(), but I read it is not possible because the thread is blocked. How could I do this?
I tried the following:
Thread t2;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while (t1.isAlive()) {
t2 = new Thread() {
#Override
public void run() {
try {
while (!br.ready())
Thread.sleep(200);
choice = Integer.parseInt(br.readLine());
} catch (InterruptedException e) {
} catch (IOException e) {
}
}
};
t2.start();
}
Supposedly, this should allow me to interrupt t2, but I must be doing something wrong because it keeps printing Chose an option: 1. Pause/Resume 2. Stop, so I cannot check if it works.
The crucial issue is that the API of System.in makes no guarantees. A JVM can fulfill the complete JVM spec even if it has a System.in such that, if it is interrupted, nothing happens and it is in fact completely impossible to interrupt System.in, aside from System.exit.
However, most JVM implementations fortunately don't quite work that way: If you raise the interrupt flag on any given thread, 3 things are going to happen:
Any method that is specced to definitely look at em will be interrupted: These are all methods that are declared to throws InterruptedException. All these methods will, if the thread's interrupt flag is raised, stop waiting immediately, lower the flag, and return by way of throwing InterruptedException. Yes, this means that if you first raise the interrupt flag (someThread.interrupt() raises the flag and doesn't do anything else; it's other methods that look at it that makes the magic work), and then invoke e.g. Thread.sleep, the sleep calls returns immediately (by throwing InterruptedEx) and waits no even a single millisecond.
Methods that pause a thread but which are not specced to definitely deal with it properly are in limboland: It is up to the implementation of the java runtime if anything happens. However, usually something will happen. These methods almost always throw some sort of checked exception (for DB connections, SQLEx, for network, file, and pipe operations, IOException); any code that is currently waiting to send or receive data on one of these things will deal with a raised interrupt flag by lowering the flag, aborting the operation, and returning by way of throwing that checked exception with a message that indicates an interruption occurred.
If code is executing that doesn't respond to the interrupt flag at all, then nothing happens: The flag stays raised and the JVM is not going to do anything else; the point of the interrupt flag is that it just gets raised and then you wait until the thread runs code that looks at it. Hopefully, that will happen very soon, but there are no guarantees.
That means that most likely all you need to do is:
In T1
Have some sort of AtomicBoolean object that will be set to true by t1 once the job is completed.
t1 will also raise the interrupt flag of t2 when the job is completed.
In T2
Protect your readLine() call by putting it in a try/catch block, catching IOException. If there is a loop you may also want to consider checking the interrupt flag yourself, in case it is set in between readLine() invokes; you do this with Thread.interrupted(), which returns true and lowers the flag if the flag is up. Generally, something like while (!Thread.interrupted() && other conditions) { /* main loop here */ }.
In the IOException catch handler, check t1's 'we are done' flag (that AtomicBoolean). If it says 'we are done', then interpret the IOEx as simply being notified that the job is done (so, don't log it anywhere - you were expecting it to happen). If, however, the 'we are done' flag isn't set yet, then that IOException is indicating an actual I/O problem with the input pipe, which can happen of course. You should proceed as normal (which usually means, throw it onwards so that the app crashes with a full log, you can't sanely respond to the input pipe getting I/O issues other than to exit with debug info about what happend). So, just throw that IOException. If you can't, throw new UncheckedIOException(thatIoException); is what you are looking for.
The caveat
Just because it works on your system does not mean it will work anywhere else, unfortunately. As I said, on some VM impls System.in.read() is just not interruptable, period. Nothing you can do, other than extremely drastic steps: Stop being a command line app and show a swing GUI window instead or make it a web app of some sort.
Closing notes
ready() and available() are almost completely useless. They aren't broken, in the sense that they do exactly what their javadoc says these methods do, but if you carefully read that javadoc, you'll realize that what they provide is completely useless. The only real way to know if data is available is to actually attempt to read it, which then leads you into the trap of: Well, on some platforms, that's not interruptable. Yup. Sucks. No reliable solution, in the sense that the API guarantees it'll work on all platforms, is available. 99.5% of all code out there that calls these methods is broken. It is highly unlikely that you'd ever want to call these methods.
It looks like an innocent topic, but actually it's a bit more complicated. When you are reading from the standard input, you usually just end up in a call to the operating system. Which will not return until it has actual input to return with, and has no idea about the interruption mechanism of Java. It's described as a by-product here.
What you can do is providing your own InputStream instead of using System.in directly, and implement its read() method in a way that it goes into System.in.read() only when System.in.available() says so. Until then just repeat the check with some delay, like using Thread.sleep() which is prepared to get interrupted anyway:
public static void main(String[] args) {
Thread main = Thread.currentThread();
// try (Scanner sc = new Scanner(System.in)) {
try (Scanner sc = new Scanner(new InputStream() {
#Override
public int read() throws IOException {
while (System.in.available() == 0)
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
throw new IOException();
}
return System.in.read();
}
})) {
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException ie) {
}
main.interrupt();
}
}).start();
String line = sc.nextLine();
System.out.println(line);
System.out.println(main.isInterrupted());
} catch (Exception ex) {
System.out.println("Time's up, probably. Actual exception: " + ex);
System.out.println(main.isInterrupted());
}
}
If you comment the try(Scanner...-})) { block and uncomment the single-line variant, you can try how it doesn't work in itself: you will always have to input something, only the result of System.out.println(main.isInterrupted()); will tell you if you did it in 5 seconds or it took more time.
Side note: in your own attempt you were interrupting the timer thread itself, you need a reference to the other thread instead, here in this example that's the Thread main variable.
Starting multiple threads and having each exec() then destroy() a running java process result in some of the process not being destroyed and still running after program exit. Here is some code that reproduce the issue. I noticed the more threads you start, the more processes stay alive. And the more sleep before destroy(), the less processes stay alive. (I used InfiniteLoop as an example. Any running process will do the trick.)
EDIT : Bug has been reported to Oracle, waiting for an answer. Feel free to share any knowledge/experiments on the subject.
for(int i = 0; i < 100; i++)
{
new Thread(new Runnable()
{
public void run()
{
try
{
Process p = Runtime.getRuntime().exec(new String[]{"java", "InfiniteLoop"});
Thread.sleep(1);
p.destroy();
}catch(IOException | InterruptedException e){e.printStackTrace();}
}
}).start();
}
Use a p.waitFor(); before p.destroy(); ,
this will ensure the completion of the previous process. I think you p.destroy command gets invoked sooner than the exec() command performs the action. Therefore it becomes useless.
If subprocesses write anything to stdout or stderr (intentionally or not), that could cause trouble:
"Because some native platforms only provide limited buffer size for
standard input and output streams, failure to promptly write the input
stream or read the output stream of the subprocess may cause the
subprocess to block, and even deadlock."
Source: http://www.javaworld.com/jw-12-2000/jw-1229-traps.html
The whole article is IMO worth reading if you need to use Runtime.exec().
This is simply because before the threads execute the destroy call, your main program terminates and all the associated threads leaving the started processes running. To verify this, simply add a System.out call after the destroy and you will find it is not executed. To overcome this add a Thread.sleep at the end of your main method and you will not have the orphaned processes. The below does not leave any process running.
public class ProcessTest {
public static final void main (String[] args) throws Exception {
for(int i = 0; i < 100; i++) {
new Thread(new Runnable()
{
public void run() {
try {
Process p = Runtime.getRuntime().exec(new String[]{"java", "InfiniteLoop"});
Thread.sleep(1);
p.destroy();
System.out.println("Destroyed");
}catch(IOException e) {
System.err.println("exception: " + e.getMessage());
} catch(InterruptedException e){
System.err.println("exception: " + e.getMessage());
}
}
}).start();
}
Thread.sleep(1000);
}
}
You should close the input/output/error streams to the process. We saw some issues in the past where the forked process was not completing properly due to those streams not being closed (even if they weren't being used).
An exemplary solution:
p.destroy();
p.getInputStream().close();
p.getOutputStream().close();
p.getErrorStream().close();
I believe that according to link, a distinct process is spawned by the operating system in response to this call. This process has a lifetime independent of your Java program and threads within it so you would expect it to continue running after your program has exited. I just tried it on my machine and it appeared to work as expected:
import java.io.*;
class Mp {
public static void main(String []args) {
for(int i = 0; i < 100; i++) {
new Thread(new Runnable() {
public void run() {
try {
System.out.println("1");
Process p = Runtime.getRuntime().exec
(new String[]{"notepad", ""});
System.out.println("2");
Thread.sleep(5);
System.out.println("3");
p.destroy();
System.out.println("4");
}
catch(IOException | InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
This is not an answer; I am posting complete source for my own attempt at recreating this problem as per discussion in question comments.
I cannot reproduce this problem on Ubuntu 12.04; OpenJDK 6b_27 (however, see below).
ProcessTest.java:
import java.io.*;
public class ProcessTest {
public static final void main (String[] args) throws Exception {
for(int i = 0; i < 100; i++) {
new Thread(new Runnable()
{
public void run() {
try {
Process p = Runtime.getRuntime().exec(new String[]{"java", "InfiniteLoop"});
Thread.sleep(1);
p.destroy();
}catch(IOException e) {
System.err.println("exception: " + e.getMessage());
} catch(InterruptedException e){
System.err.println("exception: " + e.getMessage());
}
}
}).start();
}
}
}
InfiniteLoop.java
public class InfiniteLoop {
public static final void main (String[] args) {
while (true) ;
}
}
I cannot reproduce the issue where processes remaining running after the JVM terminates. However, if I add a long delay in the main thread after starting the threads but before returning from main, I do see roughly a dozen running java processes that stick around (although they are terminated when the main program terminates).
Update:
I just had it leave about 5 processes running after it terminated. It doesn't always happen. Weird. I want to know more about this too. I have a hunch that it has something to do with destroying the process too quickly or some kind of race condition; maybe java forks something off or does something to create a new process that destroy() doesn't take care of if called too quickly / at the wrong time.
I found an old bug (but it is not mark resolved) stating that if a process spawns subprocesses they may not be killed by destroy(). bugs.sun.com/bugdatabase/view_bug.do?bug_id=4770092 What version of the JDK are you using.
Here's another reference to what looks like a similar issue: Java tool/method to force-kill a child process And I want to apologize if I've only added confusion to your life, I don't actually use Process that much and am not familiar with the quirks. Hopefully somebody else will step in with a definitive answer. It seems like it doesn't handle subprocesses well, and I'm presuming java forks something off. That's all I got.
There is a race condition between the time Runtime.exec kicks off a new thread to start a Process and when you tell that process to destroy itself.
I'm on a linux machine so I will use the UNIXProcess.class file to illustrate.
Runtime.exec(...) will create a new ProcessBuilder and start it which on a unix machine creates a new UNIXProcess instance. In the constructor of UNIXProcess there is this block of code which actually executes the process in a background (forked) thread:
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
Thread t = new Thread("process reaper") {
public void run() {
try {
pid = forkAndExec(prog,
argBlock, argc,
envBlock, envc,
dir,
redirectErrorStream,
stdin_fd, stdout_fd, stderr_fd);
} catch (IOException e) {
gate.setException(e); /*remember to rethrow later*/
gate.exit();
return;
}
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction() {
public Object run() {
stdin_stream = new BufferedOutputStream(new
FileOutputStream(stdin_fd));
stdout_stream = new BufferedInputStream(new
FileInputStream(stdout_fd));
stderr_stream = new FileInputStream(stderr_fd);
return null;
}
});
gate.exit(); /* exit from constructor */
int res = waitForProcessExit(pid);
synchronized (UNIXProcess.this) {
hasExited = true;
exitcode = res;
UNIXProcess.this.notifyAll();
}
}
};
t.setDaemon(true);
t.start();
return null;
}
});
Notice that the background thread sets the field pid which is the UNIX process id. This will be used by destroy() to tell the OS which process to kill.
Because there is no way to make sure that this background thread has run when destroy() is called, we may try to kill the process before it has run OR we may try to kill the process before pid field has been set; pid is uninitialized and therefore is 0. So I think calling destroy too early will do the equivalent of a kill -9 0
There is even a comment in the UNIXProcess destroy() that alludes to this but only considers calling destroy after the process has already finished, not before it has started:
// There is a risk that pid will be recycled, causing us to
// kill the wrong process! So we only terminate processes
// that appear to still be running. Even with this check,
// there is an unavoidable race condition here, but the window
// is very small, and OSes try hard to not recycle pids too
// soon, so this is quite safe.
The pid field is not even marked as volatile so we may not even see the most recent value all the time.
I had a very similar issue and the problem with destroy() not working was manifesting even with a single thread.
Process process = processBuilder(ForeverRunningMain.class).start()
long endTime = System.currentTimeMillis() + TIMEOUT_MS;
while (System.currentTimeMillis() < endTime) {
sleep(50);
}
process.destroy();
The process was not always destroyed if TIMEOUT_MS was too low. Adding an additional sleep() before destroy() fixed it (even though I don't have an explanation why):
Thread.sleep(300);
process.destroy();
I am working on an application that reads and processes data over a network. While testing the connecting/disconnecting logic of the program I noticed that my consumer thread was not closing when it reached it's closing condition. Below is a stripped out version of the consumer class.
import java.io.InputStream;
public class Consumer implements Runnable
{
private final InputStream input;
public Consumer(InputStream input)
{
this.input = input;
}
#Override
public void run()
{
byte readBuffer[];
readBuffer = new byte[1];
int goodData;
try
{
while(input.available() > 0)
{
goodData = input.read(readBuffer);
while (goodData > 0 )
{
System.out.println(readBuffer[0]);
if ( readBuffer[0] == 27 )
{
System.out.println("Consumer: found closing byte and closing thread "+Thread.currentThread().getName());
//this is the last packet, so interupt thread to close
Thread.currentThread().interrupt();
//return;
//Thread.currentThread().stop(new InterruptedException("Attempting to close"));
}
goodData = input.read(readBuffer);
}
}
}
catch(Exception e)
{
System.out.println("closing "+Thread.currentThread().getName() +" because of an exception "+e.getClass());
return;
}
System.out.println("closing "+Thread.currentThread().getName());
}
}
I created a dummy main class that demonstrates the problem.
public class ExampleOfInterruptNotWorking
{
public static void main(String[] args)
{
byte[] bytesToWrite = new byte[]{0, 1, 2,3,4,5,6,65,23,65,21,54,13,54,1,76};
Consumer C;
Thread ConsumerThread;
PipedInputStream PIS = null;
PipedOutputStream POS = null;
try
{
PIS = new PipedInputStream();
POS = new PipedOutputStream(PIS);
C = new Consumer(PIS);
ConsumerThread = new Thread(C);
ConsumerThread.start();
POS.write(bytesToWrite);
POS.write(bytesToWrite);
bytesToWrite[1] = 27;
POS.write(bytesToWrite);
ConsumerThread.join();
}
catch(Exception e)
{
System.err.println("Unexpected exception in main");
e.printStackTrace(System.err);
}
finally
{
try
{
PIS.close();
POS.close();
}
catch(Exception ex)
{
//shouldn't happen in example
}
System.out.println("exiting main");
}
}
}
When you run this code as written, the consumer detects the interrupt, but does not stop execution until the pipe is empty (not what I want). Just to try, I changed to a Thread.stop() call which did what I wanted, but I don't want to leave that in production code. I realized that I could use a simple return statement, but this is not the only point the thread could exit, and I'd like to have some common exit code that cleans up resources. So, my question is, why is the consumer thread not being interrupted? and is there a good way for me to be able to have common exit code?
Thanks!
InterruptedExceptions are thrown when a thread is sleeping, waiting for a join etc. (basically any interruptable blocking call) and interrupt() is called.
If you thread is running then the thread interrupt flag will be set but no exception will be thrown, you should check the flag with myThread.isInterrupted().
You can find more information here:
http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html
Which method do you expect to throw InterruptedException? Thread.interrupt() is not throwing it, neither any of your methods. So where do you expect this checked exception should come from?
Your code is not working because interrupt() barely sets the interrupted flag on a thread. You must check that flag explicitly using Thread.isInterrupted(). InterruptedException is only thrown if the thread in question was sleeping or blocking at the time. So if you interrupt different thread and that thread was sleeping, sleep() will throw InterruptedException.
Now to address your problem in detail. Exceptions are for exceptional cases. The fact your thread finished processing is not exceptional case, it's something you definitely expect. For the same reason reading a file past the end is not throwing an exception - end of file is something you should definitely expect - all files have end. Moreover you should not use exceptions to control program flow.
In your case either use return statement (when run() returns, thread dies) or break your loop in some other way. You posted too much code to analyze.
You could simply use break to label
OUTER:
while(input.available() > 0)
{
goodData = input.read(readBuffer);
while (goodData > 0 )
{
System.out.println(readBuffer[0]);
if ( readBuffer[0] == 27 )
{
System.out.println("Consumer: found closing byte and closing thread "+Thread.currentThread().getName());
//this is the last packet, so interupt thread to close
//Thread.currentThread().interrupt();
break OUTER;
//return;
//Thread.currentThread().stop(new InterruptedException("Attempting to close"));
}
goodData = input.read(readBuffer);
}
}
I am writing a content distribution network in java. I have a Link class to manage sockets between two nodes in the system. There are two programs, RouterNode and DiscoveryNode.
When a router node starts up, the first thing it does is try to initialize a connection to the discovery node:
public RouterNode(int num)
{
myNumber = num;
input = new Scanner(System.in);
try {
discoveryServer = new Socket("MONDAY-PC", 60111);
myServerLink = new Link(this, discoveryServer);
} catch (IOException e) {
System.out.println("Socket could not be opened. Node terminating.");
System.exit(-1);
}
There is more to the constructor, but my problem keeps my program from getting past this try block.
The constructor of the link class (called on the line 'myServerLink = new Link(this, discoveryServer); ) looks as such:
public Link(Node n, Socket s)
{
parentNode = n;
regSocket = s;
try {
out = new DataOutputStream(regSocket.getOutputStream());
in = new DataInputStream(regSocket.getInputStream());
} catch (IOException e) {
System.out.println("Data Streams could not be created on the link.");
e.printStackTrace();
}
new Thread(new LinkListenerThread(this, in)).run();
}
where the last line of this constructor starts a new thread that is designed to listen on the socket for incoming messages that are being passed.
The run() method in LinkListenerThread stars as follows:
#Override
public void run()
{
byte[] message;
System.out.println("Link now active and running.");
while(!done)
{
System.out.println("attempting to read from socket...");
try {
// read now many bytes the following message will be
byte[] messageLengthBytes = new byte[4];
in.read(messageLengthBytes, 0, 4);
My problem is that once I instantiate the link from the router node, it's execution stops from what seems to be the LinkListenerThread blocking it when it calls in.read(). This listener is running on a separate thread so I am not sure if this is actually something strange with threads, or it is just an example of my lack of experience with them.
I have another instance in my program where I am reading on a separate thread
Could this be caused because the node classes aren't explicitly implementing runnable and therefore are not on their own threads?
Any help is greatly appreciated.
Edit 1: I have made the Node classes implement Runnable and starting them on their own threads, but it still locks up when the in.read() is called;
You intend to start a thread by calling Thread.run() method instead of Thread.start(). And this makes your program single-threaded, then the I/O ops block the only thread(the main thread) in the try-catch clause if there is no data coming in or the while loop never ends.
Just use Thread.start() to start a thread can fix your problem.
The problem has been resolved by using .start() instead of .run()
It all boiled down to a misunderstanding of how to instantiate threads in java.
Sub-process in java are very expensive. Each process is usually support by a NUMBERS of threads.
a thread to host the process (by JDK 1.6 on linux)
a thread to read to read/print/ignore the input stream
another thread to read/print/ignore the error stream
a more thread to do timeout and monitoring and kill sub-process by your application
the business logic thread, holduntil for the sub-process return.
The number of thread get out of control if you have a pool of thread focking sub-process to do tasks. As a result, there may be more then a double of concurrent thread at peak.
In many cases, we fork a process just because nobody able to write JNI to call native function missing from the JDK (e.g. chmod, ln, ls), trigger a shell script, etc, etc.
Some thread can be saved, but some thread should run to prevent the worst case (buffer overrun on inputstream).
How can I reduce the overhead of creating sub-process in Java to the minimum?
I am thinking of NIO the stream handles, combine and share threads, lower background thread priority, re-use of process. But I have no idea are they possible or not.
JDK7 will address this issue and provide new API redirectOutput/redirectError in ProcessBuilder to redirect stdout/stderr.
However the bad news is that they forget to provide a "Redirect.toNull" what mean you will want to do something like "if(*nix)/dev/null elsif(win)nil"
Unbeliable that NIO/2 api for Process still missing; but I think redirectOutput+NIO2's AsynchronizeChannel will help.
I have created an open source library that allows non-blocking I/O between java and your child processes. The library provides an event-driven callback model. It depends on the JNA library to use platform-specific native APIs, such as epoll on Linux, kqueue/kevent on MacOS X, or IO Completion Ports on Windows.
The project is called NuProcess and can be found here:
https://github.com/brettwooldridge/NuProcess
To answer your topic (I don't understand description), I assume you mean shell subprocess output, check these SO issues:
platform-independent /dev/null output sink for Java
Is there a Null OutputStream in Java?
Or you can close stdout and stderr for the command being executed under Unix:
command > /dev/null 2>&1
You don't need any extra threads to run a subprocess in java, although handling timeouts does complicate things a bit:
import java.io.IOException;
import java.io.InputStream;
public class ProcessTest {
public static void main(String[] args) throws IOException {
long timeout = 10;
ProcessBuilder builder = new ProcessBuilder("cmd", "a.cmd");
builder.redirectErrorStream(true); // so we can ignore the error stream
Process process = builder.start();
InputStream out = process.getInputStream();
long endTime = System.currentTimeMillis() + timeout;
while (isAlive(process) && System.currentTimeMillis() < endTime) {
int n = out.available();
if (n > 0) {
// out.skip(n);
byte[] b = new byte[n];
out.read(b, 0, n);
System.out.println(new String(b, 0, n));
}
try {
Thread.sleep(10);
}
catch (InterruptedException e) {
}
}
if (isAlive(process)) {
process.destroy();
System.out.println("timeout");
}
else {
System.out.println(process.exitValue());
}
}
public static boolean isAlive(Process p) {
try {
p.exitValue();
return false;
}
catch (IllegalThreadStateException e) {
return true;
}
}
}
You could also play with reflection as in Is it possible to read from a InputStream with a timeout? to get a NIO FileChannel from Process.getInputStream(), but then you'd have to worry about different JDK versions in exchange for getting rid of the polling.
nio won't work, since when you create a process you can only access the OutputStream, not a Channel.
You can have 1 thread read multiple InputStreams.
Something like,
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
class MultiSwallower implements Runnable {
private List<InputStream> streams = new CopyOnWriteArrayList<InputStream>();
public void addStream(InputStream s) {
streams.add(s);
}
public void removeStream(InputStream s) {
streams.remove(s);
}
public void run() {
byte[] buffer = new byte[1024];
while(true) {
boolean sleep = true;
for(InputStream s : streams) {
//available tells you how many bytes you can read without blocking
while(s.available() > 0) {
//do what you want with the output here
s.read(buffer, 0, Math.min(s.available(), 1024));
sleep = false;
}
}
if(sleep) {
//if nothing is available now
//sleep
Thread.sleep(50);
}
}
}
}
You can pair the above class with another class that waits for the Processes to complete, something like,
class ProcessWatcher implements Runnable {
private MultiSwallower swallower = new MultiSwallower();
private ConcurrentMap<Process, InputStream> proceses = new ConcurrentHashMap<Process, InputStream>();
public ProcessWatcher() {
}
public void startThreads() {
new Thread(this).start();
new Thread(swallower).start();
}
public void addProcess(Process p) {
swallower.add(p.getInputStream());
proceses.put(p, p.getInputStream());
}
#Override
public void run() {
while(true) {
for(Process p : proceses.keySet()) {
try {
//will throw if the process has not completed
p.exitValue();
InputStream s = proceses.remove(p);
swallower.removeStream(s);
} catch(IllegalThreadStateException e) {
//process not completed, ignore
}
}
//wait before checking again
Thread.sleep(50);
}
}
}
As well, you don't need to have 1 thread for each error stream if you use ProcessBuilder.redirectErrorStream(true), and you don't need 1 thread for reading the process input stream, you can simply ignore the input stream if you are not writing anything to it.
Since you mention, chmod, ln, ls, and shell scripts, it sounds like you're trying to use Java for shell programming. If so, you might want to consider a different language that is better suited to that task such as Python, Perl, or Bash. Although it's certainly possible to create subprocesses in Java, interact with them via their standard input/output/error streams, etc., I think you will find a scripting language makes this kind of code less verbose and easier to maintain than Java.
Have you considered using a single long-running helper process written in another language (maybe a shell script?) that will consume commands from java via stdin and perform file operations in response?