如何在等待控制台输入时使用Thread.sleep()创建计时器?

时间:2016-10-29 17:13:19

标签: java multithreading

我正在尝试编写一个程序,询问带有时间限制的简单问题。

到目前为止,我有以下内容:

public static void main(String[]args) throws IOException, InterruptedException{
    Thread thread = new Thread();
    Scanner scan = new Scanner(System.in);

    System.out.println("1. What is 1+1?");
    System.out.println("a. 2\tb. Cannot Be.\tc. 3\td. All of the above."); 
    String question1 = scan.next();
    for(int i = 3; i>=0; i--){
        System.out.print("\b"+i);
        Thread.sleep(1000);
    }
}   

这正确地询问了问题并得出了答案,但它没有对输入设置时间限制,并在输入后给出从3到0 的倒计时。我做错了什么?

4 个答案:

答案 0 :(得分:0)

我会创建单独的函数来在循环期间调用,因此你不会有一个冗长的全局变量声明等等。如果你需要控制随机调用的东西,那么你可以在一个函数中放一个rand并使用一个全局的方式,或者你可以简单地将它们按照你希望它被调用和完成的顺序。

答案 1 :(得分:0)

正如你猜对了,你需要运行两个独立的线程,如下面的解释&代码。

以下说明将为您提供有关如何以及如何处理这两个线程的更多详细信息。

(1)线程1: Timer线程(内部类实现Runnable)在单独的线程中运行,并在等待用户输入时计算秒数。一旦用户输入输入,该线程需要使用信号停止(stopTimer变量充当信号),确保stopTimer变量是易失性的(接收由Thread2写入的数据),否则此线程会无限期地等待。

(2)线程2 :这是等待用户输入的main thread。一旦用户输入数据,该主线程就会发出信号,使用单独的方法调用来停止Timer线程 - signalStopTimer()

public class TimerTest {    

        public static class Timer implements Runnable {

            private volatile boolean stopTimer = false;

            private long timerMilliSeconds =0;

            @Override
            public void run() {
                try {
                    while(!stopTimer) {
                        Thread.sleep(1000);
                        timerMilliSeconds = timerMilliSeconds+1000;
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            public void signalStopTimer() {
                stopTimer = true;
            }

            //this method will be helpful to find the elapsed time in seconds
            public long getTotalTimeInSeconds() {
                return timerMilliSeconds/1000;
            }

        }

        public static void main(String[] args) {

                 TimerTest.Timer timer = new TimerTest.Timer();
                 //Start the Timer Thread now
                 Thread thread = new Thread(timer);
                 thread.start();

                 Scanner scan = new Scanner(System.in);

                System.out.println("1. What is 1+1?");
                System.out.println("a. 2\tb. Cannot Be.\tc. 3\td. All of the above."); 
                String input = scan.next();

                //received the input, signal to stop timer
                timer.signalStopTimer();
                System.out.println(" input is:"+input+" seconds");
                System.out.println(" total time :"+timer.getTotalTimeInSeconds());


        }

    }

答案 2 :(得分:0)

这可以使用一点黑色多线程魔法来完成。

首先,你需要两个这样的线程:

Thread thread1 = Thread.currentThread();
Thread thread2 = new Thread(() -> {
    try {
        for (int seconds = 3; seconds > 0; seconds--) {
            System.out.println(seconds+" second"+(seconds == 1 ? "s" : "")+" left");
            Thread.sleep(1000);
        }
        System.out.println("Time's up!");
        thread1.stop();
    }catch(InterruptedException weCanIgnoreThisException){}
});

其中thread1是询问问题的线程,thread2是倒计时。

然后剩下的就是问这个问题。 在收到输入之前不要忘记start() thread2,并在收到输入后忘记stop()

System.out.println("1. What is 1+1?");
System.out.println("a. 2\tb. Cannot Be.\tc. 3\td. All of the above.");
thread2.start();
String answer = scan.next();
thread2.stop();

好的,这就是为什么我使用弃用的方法Thread#stop()

The official documentation of java.lang.Thread解释了为什么stop()已被弃用以及在什么情况下会使程序搞砸:

  

使用Thread.stop停止某个线程会导致它解锁所有已锁定的监视器(这是未经检查的ThreadDeath异常向上传播的自然结果)。如果先前受这些监视器保护的任何对象处于不一致状态,则受损对象将对其他线程可见,可能导致任意行为。

简而言之,如果一个线程stop()使用synchronized块或方法锁定在一个对象上,则会以危险的突然方式释放对象上的锁定。由于询问多项选择题并对输入设置时间限制并不需要某个帖子synchronized,我们可以忽略它。

答案 3 :(得分:0)

如果您只需要计算用户输入的时间,那么更好的方法和最简单的方法是使用System.currentTimeMillis()。

在扫描代码之前你可以将当前时间保存在变量(Long)中,然后在while循环中(当用户输入他的输入时循环条件将停止)在循环结束时只需保存相同的方式上面提到的当前时间以毫秒为单位,然后全部左边是减法。

如果这是你的指示,请告诉我,我可以提供相应的代码;)