I am using a multi threaded environment were one Thread is constantly listening for user input by repeatedly calling scanner.nextLine()
.
To end the application, this runloop is stopped by another thread, but the listening thread won't stop until a last user input was made (due to the blocking nature of nextLine()
).
Closing the stream seems not to be an option since I am reading from System.in
, which returns an InputStream
that is not closable.
Is there a way to interrupt the blocking of scanner, so that it will return?
thanks
Sure. Use a nuke. Call
System.exit(0)
at the end of your main thread. This will murder everything. Even the active thread waiting in System.in.The problem is that System.in is a traditional input stream with blocking, and when it's blocking the thread is marked as running. You cannot interrupt it. So whatever thread you are using to read the System.in is calling read and the read will block the thread. You can coax some of this stuff with a bunch of tricks avoid calling read except in those cases when we can be sure there will be no block and then constantly poll. But, there's no real way around the problem that any attempt to read that will lock your thread and no amount of closing underlying streams or interrupting or stopping the thread will save you. But, if you murder the entire vm... the thread will die.
Obviously you need to make sure the rest of the threads have properly exited and it's just that one stupid I want to be able to respond to typed input thread that is the last hanger-on. But, if that's totally the case the correct answer is to exit, or at least, basically the only answer that'll work without burning clock-cycles for no reason and let the program terminate.
To start off with: this will not solve the issue that, to close the whole program, requires a System.exit() call if there has been an unfulfilled input request (even if canceled). You could potentially circumvent this by spoofing a keystroke into console, but that's a whole other ball park.
If you want to do it in console, is impossible to do without polling, as it's impossible to actually un-block a thread waiting for input from System.in, as System.in itself does not have interruptible get() methods. Because of this, without using polling to only request input if you know it will not be blocking.
If you truely want something that will act as an interruptible nextLine() for a console, you should probably look into making a Swing window, or the like, and making a simple input interface for it. This isn't really difficult, and would have all the functionality you're asking for, outside of some edge cases.
However, I was working on this myself, as I wanted a way for a thread to stop waiting for input from System.in, without closing the program (and while avoiding polling), and this is what I came up with, before switching to my own window.
I can't say with any confidence it's best-practice, but it should be thread-safe, seems to be working fine, and I can't think of any immediate issues. I would like to switch failures from alternate (albeit, otherwise unobtainable) outputs, to actual errors though. You can cancel active requests for input either by interrupting the thread, or by calling cancel(), which canceles the currently waiting request.
It uses Semaphores and threads to create a blocking nextLine() method that can be interrupted/canceled elsewhere. Canceling is not perfect - you can only cancel the currently waiting thread's request, for instance, but interrupting threads should work fine.
This article describes an approach to avoiding blocking when reading. It gives the code snippet, which you could amend as I indicate in a comment.
You could either use this code directly, or write a new closable InputStream class, wrapping up the logic described in this article.