1

This is related to some other questions on here, but I haven't yet seen an answer that helps. (EDIT by JWW: per the comments, the cited duplicate doe not handle the EOF as expected or desired).

In this example, the main() function starts a Thread, which blocks on a Scanner's nextLine() function. I then wait for 0.2 s, and after that time I want to force this Thread to terminate, even though nothing's been typed in. I can't get the Thread to stop on its own, without hitting a key to satisfy its Scanner.

import java.util.*;

class sandbox {
    public static void main(String[] args) {
        BlockingThread thread = new BlockingThread();
        thread.start();

        trySleep(200); // wait 0.2 s
        thread.closeScanner(); // try to close the Scanner, to terminate the Thread
    }

    public static void trySleep(int time) {
        try { Thread.sleep(time); }
        catch (InterruptedException e) {}
    }

    static class BlockingThread extends Thread {
        private Scanner scanner = new Scanner(System.in);

        public void run() {
            System.out.println("Running!");
            scanner.nextLine();
            System.out.println("Stopping!");
        }

        public void closeScanner() {
            System.out.println("\tTrying to close the Scanner...");
            scanner.close();
            System.out.println("\tScanner is now closed.");
        }
    }
}

Some notes:

  • It's definitely blocking on the Scanner's underlying stream. If you download and run this code, it'll halt right after printing "Trying to close the Scanner..." If you remove the call to thread.closeScanner(), it'll stop immediately after "Running!"
  • I've seen some answers claiming that I want to call the Thread's interrupt() method. But that doesn't work, because the Thread is blocked.
  • I've seen other answers claiming that I want to close the stream that the Scanner is reading. But that doesn't seem to work either—Scanner docs indicate that its close() method closes the underlying stream, so that should be what I'm doing in the above toy code.
  • I'd even be willing to use a deprecated method like stop(), but even that appears to have no effect.

Any ideas? Thanks.

(If you're curious, the underlying motivation is to create an automated grader for my students' work. The stream will ultimately be the stdout of a process being executed by a thread. But some of my students will have infinite loops, and I want the thread to terminate after n seconds, even if the process hasn't completed. So deadlock isn't really a concern, since I'm really not doing much in the way of synchronization.)

AgileDan
  • 363
  • 2
  • 21
Adam Smith
  • 358
  • 6
  • 19
  • The Thread doesn't stop! (I just edited the original to indicate this.) – Adam Smith Sep 09 '14 at 21:36
  • The problem is the nextLine is locking on the scanner's InputStream. I'm not sure how to fix it, yet. – Daniel Kaplan Sep 09 '14 at 21:43
  • Yes, I had that much figured out. I'll mod the original to indicate that. (Thanks for pointing out the little things that I missed in the original post.) – Adam Smith Sep 09 '14 at 21:45
  • The question is much the same as the other one, but the answer given doesn't solve the problem, since it's not capable of detecting an EOF. (I'm unsure where to go for help now, since I don't have the reputation to comment on the other one and make it live again. Can someone suggest a path forward? Thanks.) – Adam Smith Sep 10 '14 at 02:16
  • @JimGarrison Given Adam's comment to my answer, maybe this should be reopened? – Daniel Kaplan Sep 10 '14 at 21:00
  • Not sure what you mean by "not capable of detecting EOF". That doesn't seem to be mentioned in the post at all. You should edit the post to reflect all current requirements. – Jim Garrison Sep 10 '14 at 21:36

1 Answers1

0

I think that Scanner is the wrong tool for the job. The documentation says:

A scanning operation may block waiting for input.

Oh, and more importantly:

A Scanner is not safe for multithreaded use without external synchronization.

You should use the code in this answer instead: How to interrupt java.util.Scanner nextLine call

Community
  • 1
  • 1
Daniel Kaplan
  • 54,448
  • 39
  • 189
  • 282
  • 1
    You're right that a Scanner is the wrong tool for the job. However, the solution given on that other answer doesn't work. If the input is empty, it will sleep forever. The underlying BufferedReader is incapable of telling the difference between EOF, and an empty stream that might have more data later. (Is it preferable to continue conversation on the other page, or this one?) – Adam Smith Sep 10 '14 at 01:01
  • @AdamSmith (1) It will *block,* and not forever. (2) your claim about BufferedReader is nonsense. Of course it can tell the difference. The issue here has nothing to do with BufferedReader whatsoever. There is no EOF from the console until Ctrl/d or Ctrl/z has been pressed, so there is no difference there to distinguish. – user207421 Sep 10 '14 at 23:17
  • Blocking, not sleeping. You're right about that. But I don't see how a BufferedReader can tell the difference between EOF and an open stream with no data waiting in it. This was covered in this question: http://stackoverflow.com/questions/2124102/how-to-determine-the-exact-state-of-a-bufferedreader . If you can think of a way, I'd love to hear it. – Adam Smith Sep 10 '14 at 23:36