I have a Java thread:
class MyThread extends Thread {
@Override
public void run() {
BufferedReader stdin =
new BufferedReader(new InputStream
Whats about defining a field within your above thread class definition like:
class MyThread extends Thread {
protected AtomicBoolean abortThread = new AtomicBoolean(false);
public void doAbort()
{
this.abortThread.set(true);
}
@Override public void run()
{
...
if (this.abortThread.get())
{
...something like break loop...
}
}
}
How about...
private static BufferedReader stdInCh = new BufferedReader(
new InputStreamReader(Channels.newInputStream((
new FileInputStream(FileDescriptor.in)).getChannel())));
A thread where stdInch.readline()
is called is now interruptible and the readline() will throw a java.nio.channels.ClosedByInterruptException
.
My first reaction is that a thread and System.in
really don't go together.
So first, split this so that the thread code does not touch any static including System.in
.
A thread reads from InputStream
and passes into a buffer. Pass an InputStream
into your existing thread that reads from the buffer but also checks that you haven't aborted.
JavaDoc for BufferedReader.readLine:
Returns: A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
Based on this, I don't think it'll ever return null (can System.in actually be closed, I don't think it ever returns end of stream?), so the while-loop won't terminate. The usual way to stop a thread is either use a boolean variable in a loop condition and change it from outside of the thread or call the Thread-objects' interrupt() -method (only works if the thread is wait():ing or sleep():ing, or in a blocking method that throws InterruptedException). You can also check if the thread has been interrupted with isInterrupted().
Edit: Here's a simple implementation utilizing isInterrupted()
and interrupt()
. The main-thread waits 5 seconds before interrupting the worker-thread. In this case worker-thread is basically busy-waiting, so it's not that good (looping all the time and checking stdin.ready()
, you could of course let the worker-thread sleep for a while if no input is ready):
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class MyThreadTest
{
public static void main(String[] args)
{
MyThread myThread = new MyThread();
myThread.start();
try
{
Thread.sleep(5000);
}
catch(InterruptedException e)
{
//Do nothing
}
myThread.interrupt();
}
private static class MyThread extends Thread
{
@Override
public void run()
{
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
String msg;
while(!isInterrupted())
{
try
{
if(stdin.ready())
{
msg = stdin.readLine();
System.out.println("Got: " + msg);
}
}
catch(IOException e)
{
e.printStackTrace();
}
}
System.out.println("Aborted.");
}
}
}
It seems there's no way to actually interrupt the BufferedReader if it's blocked on readline, or at least I couldn't find one (using System.in).
Heinz Kabutz's newsletter shows how to abort System.in
reads using a buffer and ExecutorService.
Now, I don't know whether this approach leaks, isn't portable or has any non-obvious side-effects. Personally, I would be reluctant to use it.
You might be able to do something with NIO channels and file descriptors - my own experiments with them didn't yield any results.
Have you tried:
Thread myThread = new MyThread();
myThread.start();
// your code.
myThread.interrupt();
The interrupt method will throw an InterrupedtException and you can handle the code after that.