Interrupt sleep in a single thread - java

I would like to implement in Java a stop point in the code so that nothing is done in 20 seconds unless the user presses Enter.
For the moment I am just using:
sleep(20000);
I know a thread can be "awaken" by another thread using wait() and notify(), but I would like to know if there is something that does not require throwing a new thread. Ideally, I would like to be able to add a timeout to the read operations on a InputStream from the keyboard, so that I could do something like:
try {
//Here is where the waiting happens
myStream.read();
} catch (TimeoutException e) { }
//... Continue normally

You could instead of sleeping for 20s instead sleep for 1 second intervals and poll to see if the user has entered anything:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
for (int i = 0; i < 20; i++) {
try {
sleep(1000);
if (in.ready()) {
break;
} else {
System.out.println(i+" seeconds have passed");
}
} catch (InterruptedException | IOException ex) {
}
}

The comments are correct, but to suggest a (somewhat hacky) workaround:
BufferedReader myStream = new BufferedReader(new InputStreamReader(System.in));
long startTime = System.currentTimeMillis();
while(System.currentTimeMillis() < (startTime + 20000)) {
if (myStream.ready()) {
//do something when enter is pressed
break;
}
}

A blocking read with timeout interruption cannot be accomplished using one thread since a read from the input stream blocks indefinitely. There is a way to execute a computation with a timeout using a Future, but this involves concurrent programming in the first place.

Related

How to loop an input that is timed? [duplicate]

Is it possible to set timer for user's input? Wait 10 seconds - do next operation and etc.
I mean for example
//wait several seconds{
String s = new BufferedReader(new InputStreamReader(System.in)).readLine();
//wait server seconds}
//next operation and etc.
A slightly easier way to do this than Benjamin Cox's answer would be to do something like
int x = 2; // wait 2 seconds at most
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
long startTime = System.currentTimeMillis();
while ((System.currentTimeMillis() - startTime) < x * 1000
&& !in.ready()) {
}
if (in.ready()) {
System.out.println("You entered: " + in.readLine());
} else {
System.out.println("You did not enter data");
}
This will, however consume more resources than his solution.
Not right out of the box, no. Normally the Reader only breaks out of a read() call when another thread closes the underlying stream, or you reach the end of the input.
Since read() is not all that interruptible this becomes a bit of a concurrent programming problem. The thread that knows about the timeout will need to be able to interrupt the thread that's trying to read the input.
Essentially, the reading thread will have to poll the Reader's ready() method, rather than getting locked in read() when there's nothing to read. If you wrap this polling and waiting operation in a java.util.concurrent.Future, then you call the Future's get() method with a timeout.
This article goes into some detail: http://www.javaspecialists.eu/archive/Issue153.html
BufferedReader inputInt = new BufferedReader(new InputStreamReader(System.in));
Robot enterKey = new Robot();
TimerTask task = new TimerTask() {
public void run() {
enterKey.keyPress(KeyEvent.VK_ENTER);
}
};
Timer timer = new Timer();
timer.schedule(task, 30 * 1000);
userInputanswer = inputInt.read();
timer.cancel();

Interrupt BufferedReader#readLine() without closing InputStream

The InputStream of my Process should attach and detach whenever the user wants to see it or not. The attaching works fine, but the detach fails. Default answer to interrupt the readLine() method is always to close the stream, but I cant in this case or the Process will finish or at least not available for future attachments. This is how the stream is read:
BufferedReader reader = new BufferedReader(new InputStreamReader(getProcess().getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
To detach I tried some stuff:
Close any of the streams, failed: close method is blocking and waits for the readLine()
Implement another stream to send null / abortion value with SequenceInputStream, failed: when one InputStream was waiting for input, the other was not even called
Use reflections to unlock the read() method inside any of the streams, failed: not sure why, but did not work. Should we go on with this try? Here is the sourcecode:
try {
Field modifiers = Field.class.getDeclaredField("modifiers");
modifiers.setAccessible(true);
Field fdecoder = stream.getClass().getDeclaredField("sd");
fdecoder.setAccessible(true);
modifiers.setInt(fdecoder, 1);
StreamDecoder decoder = (StreamDecoder) fdecoder.get(stream);
Field flock = decoder.getClass().getSuperclass().getDeclaredField("lock");
flock.setAccessible(true);
modifiers.setInt(flock, 1);
Object lock = (Object) flock.get(decoder);
synchronized (lock) {
lock.notifyAll();
}
} catch (NoSuchFieldException | IllegalAccessException e) {
Wrapper.handleException(Thread.currentThread(), e);
}
Not sure how I can fix this. Could you help me interrupting the readLine() method without closing the stream, simple and performant? Thanks.
Edit:
What do I mean by "performant"? My application has not much users, but a lot of processes. The answer by #EJP is not wrong - but unperformant in the case of my application. I cannot have hundreds of threads for hundreds of processes, but I can have as many processes as I have users watching. That's why I try to interrupt the process gracefully. Fewer threads, less running/blocked threads.
Here is the application described (https://imgur.com/VUcYUfi.png)
The Thread that sends the information to the user is the same that reads the input.
I didn't expect it to work, but futures are actually cancelable (but why?).
After #Tarun Lalwani mentioned the TimeLimiter of Googles Guava library, I inspected the code, tried it in my examples (worked!) and rewrote it a bit - make it not time-based, but method-call-based?!
Here is what I got from my research: A wrapper for the BufferedReader:
public class CancelableReader extends BufferedReader {
private final ExecutorService executor;
private Future future;
public CancelableReader(Reader in) {
super(in);
executor = Executors.newSingleThreadExecutor();
}
#Override
public String readLine() {
future = executor.submit(super::readLine);
try {
return (String) future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} catch (CancellationException e) {
return null;
}
return null;
}
public void cancelRead() {
future.cancel(true);
}
}
This class allows you to use the BufferedReader#readLine() when you need it and cancel it when you want to continue / interrupt the Thread it is running in. Here is some example code of it in action:
public static void main(String[] args) {
System.out.println("START");
CancelableReader reader = new CancelableReader(new InputStreamReader(System.in));
String line;
new Thread(() -> {
try {
Thread.sleep(10000);
reader.cancelRead();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
System.out.println("END");
}
And the output of it:
START
> Hello World!
Hello World!
> What's up?
What's up?
END //Exactly after 5 seconds, when the cancel was called
> Hey, you still there?
//No output as expected
And the last thing I wanna say is why this and not closing InputStream or create one Thread per process?
In this case the InputStream is the stream of a Process, which means we cannot close it. One way would be to unblock readLine() and return null to finish the while-loop, but this is made with Reflection, which is not as beautiful as our solution now and didn't work for any reason. The application uses many processes but has a limited amount of users - thats why we decide for the amount of threads per user and not per process.
I hope you guys will find this Thread in the future and it is helpful for you. Would be awesome if you leave an upvote, so I can get back my rep of the bounty.
Dont forget to upvote the comments either! They helped me alot and brought me to the right solution:
Interrupt BufferedReader#readLine() without closing InputStream
You're going at this back to front.
You can't stop collecting the process's output, or you will stall the child process.
You want to stop displaying the output when the user doesn't want to see it. Look on it as a user interface issue only.

Timelimit for valid Java input without System.exit

I have a question how to implement a variation of whats found here:
Set Time Limit on User Input (Scanner) Java
In my case, I would like to ignore the input if the Timelimit is reached while keeping the program alive.
String str = "";
TimerTask task = new TimerTask(){
public void run(){
if(str.equals("")){
System.out.println("No Valid Input detected");
//TimerTask should end here along with the Input
//Other example has System.exit which will also terminate the
//entire program
}else {
// still keep the program alive. The condition itself isn't
//important.
}
}
Timer timer = new Timer();
timer.schedule(task, 10*1000);
Scanner scanner = new Scanner(System.in);
do{
System.out.println("Type a message");
str = scanner.nextLine();
}while(!str.equals("hello"));
timer.cancel();
REACHED HERE!
If the input is given within 10 seconds(and it's valid), the loop ends and the task is canceled, which is perfect. However, if the input is not valid and the timer ends, I would like for it to stop asking for input and skip to the "REACHED HERE" position. Is that even possible?
As #Sedrick mentions, the simplest solution to this is a second thread. The problem is that reading from System.in is blocking. Clearly the example you linked to solves that problem with a System.exit(), but that's too extreme for your case.
Another spin on it might be to use a Deque (double-ended queue) to relay the input, with the timeout on there:
BlockingDeque<String> deque = new LinkedBlockingDeque<>();
new Thread(() -> {
Scanner scanner = new Scanner(System.in);
String input;
do {
System.out.println("Type a message");
input = scanner.nextLine();
deque.add(input);
} while (!input.equals("hello"));
}).start();
String str;
do {
str = deque.poll(10, TimeUnit.SECONDS);
} while (str != null && !str.equals("hello"));
System.out.println("REACHED HERE!");
Expanded answer...
The idea above was to only create the thread once, and re-use the deque as the proxy for System.in. But, in the thread, the read from System.in will always be blocking - there's no clean way to interrupt the thread, short of System.exit().
This can be refined a bit though. Firstly, if the thread is marked as a daemon thread, this allows the JVM to shutdown around it still. E.g. if the main() method completes, the JVM will exit cleanly too:
Thread thread = new Thread(() -> {
...
});
thread.setDaemon(true);
thread.start();
However, by using InputStream.available(), it is possible to poll for waiting input. This then makes it possible to interrupt the thread cleanly:
BlockingDeque<String> deque = new LinkedBlockingDeque<>();
Thread thread = new Thread(() -> {
Scanner scanner = new Scanner(System.in);
String input;
try {
do {
if (System.in.available() > 0) {
input = scanner.nextLine();
deque.add(input);
} else
try {
Thread.sleep(50);
} catch (InterruptedException ex) {
System.err.println("Thread stopped");
break;
}
} while (true);
} catch (IOException ex) {
ex.printStackTrace();
}
});
thread.start();
System.out.println("Type a message");
String str;
do {
str = deque.poll(10, TimeUnit.SECONDS);
} while (str != null && !str.equals("hello"));
System.out.println("REACHED HERE!");
thread.interrupt();
It looks like there's some risk with the user typing a few letters without a line feed. At the moment that would still hang, but this didn't happen on Windows - apparently data from the command window is only released to System.in line by line.

How to end a thread handling socket connection?

I have a thread handling a socket connection:
BufferedReader socketInput = new BufferedReader(new InputStreamReader(mySocket.getInputStream()));
while (true)
{
String line = socketInput.readLine();
// do stuff
}
As I've read in a few answers on this site, the recommended solution is to use a flag which one thread sets and my (socket handling) thread checks and terminates itself when that flag changes state. Something like:
while (!done)
{
String line = socketInput.readLine();
// do stuff
}
But this can get stuck when readLine() is still waiting for input. I guess I could set a timeout:
mySocket.setSoTimeout(100);
while (!done)
{
String line = socketInput.readLine();
// do stuff
}
Which would probably work but I would still get a 100 ms delay before my thread "realizes" the flag's state changed.
Is there a way for the thread to "realize" right away that it should end? If not, is my solution (with timeout and flag done) correct?
Edit: I've clarified that the socketInput is of type BufferedReader (alternatively I'm considering Scanner).
The most common way to handle this is to close the socket from the other Thread. This will lead the reading side to unblock and exit with the (expected) error that the socket was closed. Depending on the socket API that you have available it might also be possible to shutdown only the reading side. From a short look at the JDK shutdownInput() might work.
If you however want to continue to read from the socket later on these obvisouly won't work. Your solution should work there, but is obvisouly worse for performance and reactivity since you basically poll the socket all 100ms.
Create a Selector
Configure your socket.getChannel() to non-blocking and register it to the Selector with SelectionKey.OP_READ
Call your Selector select() method that will return when there are some data to read so you can call readLine() (i.e. select() returns > 0)
Whenever you want to end your socket processing, set your done flag and call your Selector wakeup() method. That will make the select() return immediately (potentially 0, or 1 if there was activity). You can then check your done flag and end your thread gracefully.
Here is a quick implementation. Notice I pass the BufferedReader as an argument as if you're opening it in the thread you should also close it there, which would close the socket too, so it has to be done outside. There are two methods to signal the thread to gracefully stop processing input and one to send data:
public class SocketHandler extends Thread {
private Socket sok;
private BufferedReader socketInput;
private Selector sel;
private SocketChannel chan;
private boolean done;
public SocketHandler(Socket sok, BufferedReader socketInput) throws IOException {
this.sok = sok;
chan = sok.getChannel();
chan.configureBlocking(false);
sel = Selector.open();
chan.register(sel, SelectionKey.OP_READ);
this.socketInput = socketInput;
done = false;
}
#Override
public void run() {
while (!done) {
try {
if (sel.select() == 0)
continue;
} catch (IOException e) {
e.printStackTrace();
}
// Only one channel is registered on only one operation so we know exactly what happened.
sel.selectedKeys().clear();
doRead();
// Otherwise: loop through sel.selectedKeys(), check for readability and clear the set
}
try {
sel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void doRead() {
try {
String line = socketInput.readLine();
// TODO: process 'line'
} catch (IOException e) {
e.printStackTrace();
}
}
public void signalStop() {
done = true;
if (sel != null)
sel.wakeup(); // Get out of sel.select()
}
public void doWrite(byte[] buffer) throws IOException { // Or "String message"
sok.getOutputStream().write(buffer); // Or anything else
}
}
The solution is correct, it will exit when done is set to true.
And yes, the readLine will always wait for 100ms, if you don't want to wait you may interrupt the thread by calling thread.interrupt() it but it's not very clean way.
The best way to know when finish a socket connection is to try to read something. If read method return -1 you can end threadling socket connection
byte[] data = new byte[2048];
while (!done) {
int count = input.read(data);
if (count <= 0) {
if (count < 0)
done = true;
continue;
}
String request = new String(data, 0, count);
//do stuff
}
We try to read something in input if count == -1, the socket client is disconnected now we can end the loop, by changing the value of done.

set timeout for user's input

Is it possible to set timer for user's input? Wait 10 seconds - do next operation and etc.
I mean for example
//wait several seconds{
String s = new BufferedReader(new InputStreamReader(System.in)).readLine();
//wait server seconds}
//next operation and etc.
A slightly easier way to do this than Benjamin Cox's answer would be to do something like
int x = 2; // wait 2 seconds at most
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
long startTime = System.currentTimeMillis();
while ((System.currentTimeMillis() - startTime) < x * 1000
&& !in.ready()) {
}
if (in.ready()) {
System.out.println("You entered: " + in.readLine());
} else {
System.out.println("You did not enter data");
}
This will, however consume more resources than his solution.
Not right out of the box, no. Normally the Reader only breaks out of a read() call when another thread closes the underlying stream, or you reach the end of the input.
Since read() is not all that interruptible this becomes a bit of a concurrent programming problem. The thread that knows about the timeout will need to be able to interrupt the thread that's trying to read the input.
Essentially, the reading thread will have to poll the Reader's ready() method, rather than getting locked in read() when there's nothing to read. If you wrap this polling and waiting operation in a java.util.concurrent.Future, then you call the Future's get() method with a timeout.
This article goes into some detail: http://www.javaspecialists.eu/archive/Issue153.html
BufferedReader inputInt = new BufferedReader(new InputStreamReader(System.in));
Robot enterKey = new Robot();
TimerTask task = new TimerTask() {
public void run() {
enterKey.keyPress(KeyEvent.VK_ENTER);
}
};
Timer timer = new Timer();
timer.schedule(task, 30 * 1000);
userInputanswer = inputInt.read();
timer.cancel();

Categories