中断等待用户输入的线程然后退出应用程序

时间:2013-12-09 18:32:13

标签: java multithreading input concurrency thread-safety

我有两个线程在运行,userInputThread等待命令行的用户输入,interrupterThread在启动后1秒尝试中断userInputThread。显然,您无法中断被System.in阻止的线程。另一个答案建议在中断线程之前用System.in关闭System.in.close()。但是,当我运行以下代码时,userInputThread永远不会被中断,应用程序只会挂起而不会关闭。

class InputInterruptionExample {

    private Thread userInputThread;
    private Thread interrupterThread;

    InputInterruptionExample() {
        this.userInputThread = new Thread(new UserInputThread());
        this.interrupterThread = new Thread(new InterrupterThread());
    }

    void startThreads() {
        this.userInputThread.start();
        this.interrupterThread.start();
    }
    private class UserInputThread implements Runnable {
        public void run() {
            try {
                System.out.println("enter your name: ");
                String userInput = (new BufferedReader(new InputStreamReader(System.in))).readLine();
            } catch (IOException e) {
                System.out.println("Oops..somethign went wrong.");
                System.exit(1);
            }
        }
    }
    private class InterrupterThread implements Runnable {
        public void run() {
            try {
                sleep(1000);
                System.out.println("about to interrupt UserInputThread");
                System.in.close();
                userInputThread.interrupt();
                userInputThread.join();
                System.out.println("Successfully interrupted");
            } catch (InterruptedException e) {
            } catch (IOException ex) {
                System.out.println("Oops..somethign went wrong.");
                System.exit(1);
            }
        }
    }
    public static void main(String[] args) {
        InputInterruptionExample exampleApp = new InputInterruptionExample();
        exampleApp.startThreads();
    }
}

已经有类似的question,但没有明确的答案。

2 个答案:

答案 0 :(得分:3)

这解决了这个问题:

class InputInterruptionExample {

    private UserInputThread userInputRunnable;
    private Thread userInputThread;
    private Thread interrupterThread;

    InputInterruptionExample() {
        this.userInputRunnable = new UserInputThread();
        this.userInputThread = new Thread(userInputRunnable);
        this.interrupterThread = new Thread(new InterrupterThread());
    }

    void startThreads() {
        this.userInputThread.start();
        this.interrupterThread.start();
    }
    private class UserInputThread implements Runnable {
        private InputStreamReader isr;
        private BufferedReader br;

        UserInputThread() {
            InputStreamReader isr = new InputStreamReader(System.in);
            BufferedReader br = new BufferedReader(isr);
        }

        public void run() {
            try {
                System.out.println("enter your name: ");
                try{
                    String userInput = br.readLine();
                } catch(NullPointerException e) {}
            } catch (IOException e) {
                System.out.println("Oops..somethign went wrong.");
                System.exit(1);
            }
        }
        public void closeBufferdReader() {
            try {
                System.in.close();
            } catch (IOException e) {
                System.out.println("Oops..somethign went wrong in closeBufferdReader() method");
                System.exit(1);
            }
        }
    }
    private class InterrupterThread implements Runnable {
        public void run() {
            try {
                sleep(1000);
                userInputRunnable.closeBufferdReader();                 
                userInputThread.interrupt();
                userInputThread.join();
                System.out.println("Successfully interrupted");
            } catch (InterruptedException e) {}
        }
    }
    public static void main(String[] args) {
        InputInterruptionExample exampleApp = new InputInterruptionExample();
        exampleApp.startThreads();
    }
}

更新:仅当BufferedReader以这种方式拆分时才有效:

InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String userInput = br.readLine();

由于某些原因,当readLine()结构被写为oneliner时,中断似乎不起作用:

this.userInput = (new BufferedReader(new InputStreamReader(System.in))).readLine();

因此,虽然可以在拆分的BufferedReader结构中中断线程,但现在无法读取用户的输入。

如果有人能够显示出能够获得用户输入的方法以及在用户未及时提供任何输入时中断UserInputThread(当中断器正在休眠时),请执行此操作。

答案 1 :(得分:0)

我的所有研究都让我相信.readLine()调用中的基础.read()不会被中断(至少不会破坏System.in附加到的进程)。此时唯一的其他选择是使用轮询IO方案或切换到NIO。

这是一个快速(非常脏/丑陋)的代码适应轮询IO方案。这不是一个中断的解决方案,所以它不是直接回答你的问题,而是希望能让你获得你想要的行为。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.atomic.AtomicBoolean;

public class InputInterruptionExample {

    private UserInputThread uiThreadObj = null;
    private Thread inputThread = null;
    private Thread interrupThread = null;

    public InputInterruptionExample() {
        this.uiThreadObj = new UserInputThread();
        this.inputThread = new Thread(this.uiThreadObj);
        this.interrupThread = new Thread(new InterrupterThread());
    }

    void startThreads() {
        this.inputThread.start();
        this.interrupThread.start();
    }

    private class UserInputThread implements Runnable {
        private final AtomicBoolean runCmd = new AtomicBoolean(true);

        public void run() {
            try {
                final BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

                System.out.println("enter your name: ");
                while (this.runCmd.get()) {
                    if (System.in.available() > 0) {
                        String userInput = br.readLine();
                        System.out.println("You typed: " + userInput);
                        System.out.println("enter your name: ");
                    } else {
                        Thread.sleep(5); //minimal sleep to prevent CPU peg
                    }
                }
                System.out.println("Finishing normally.");

            } catch (IOException e) {
                System.out.println("Oops..somethign went wrong.");
                System.exit(1);
            } catch (Exception e) {
                System.out.println("What'd you do?!");
                e.printStackTrace();
            }
        }

        public final void requestStop() {
            this.runCmd.set(false);
        }
    }
    private class InterrupterThread implements Runnable {
        public void run() {
            try {
                Thread.sleep(1000 * 10);
                System.out.println("Requesting that UserInputThread stop.");
                uiThreadObj.requestStop();
                System.out.println("Request made.");
            } catch (InterruptedException e) {
                System.out.println("Oops..somethign went wrong.");
                System.exit(1);
            }
        }
    }
    public static void main(String[] args) {
        InputInterruptionExample exampleApp = new InputInterruptionExample();
        exampleApp.startThreads();
    }
}