Java: how to abort a thread reading from System.in

前端 未结 6 2041
梦谈多话
梦谈多话 2020-12-01 14:35

I have a Java thread:

class MyThread extends Thread {
  @Override
  public void run() {
    BufferedReader stdin =
        new BufferedReader(new InputStream         


        
相关标签:
6条回答
  • 2020-12-01 15:10

    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...
        }
      }
    }
    
    0 讨论(0)
  • 2020-12-01 15:13

    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.

    0 讨论(0)
  • 2020-12-01 15:17

    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.

    0 讨论(0)
  • 2020-12-01 15:28

    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).

    0 讨论(0)
  • 2020-12-01 15:31

    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.

    0 讨论(0)
  • 2020-12-01 15:31

    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.

    0 讨论(0)
提交回复
热议问题