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

Java 如何在等待控制台输入时使用Thread.sleep()创建计时器?,java,multithreading,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.ou

我想写一个程序,问一些有时间限制的简单问题

到目前为止,我有以下几点:

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。我做错了什么?

我会创建单独的函数在循环期间调用,这样就不会有冗长的全局变量声明之类的内容。如果你需要控制什么是随机调用的,那么你可以把一个rand放在一个函数中,然后用一个全局函数,或者你可以简单地把它们按照你想要的顺序来调用和完成

我会创建单独的函数在循环期间调用,这样就不会有冗长的全局变量声明之类的内容。如果你需要控制什么是随机调用的,那么你可以把一个rand放在一个函数中,然后用一个全局函数,或者你可以简单地把它们按照你想要的顺序来调用和完成

正如您正确猜测的那样,您需要两个独立的线程运行,如下面的解释和代码所示

下面的解释将为您提供更多关于如何使用这两个线程的详细信息

(1) 线程1:
计时器
线程(内部类实现Runnable)在单独的线程中运行,并在等待用户输入时计算秒数。用户输入输入后,需要使用信号停止此线程(
stopTimer
变量充当信号),确保
stopTimer
变量是可变的(以接收Thread2写入的数据),否则此线程将无限期等待

(2) 线程2:这是等待用户输入的
主线程。一旦用户输入数据,此主线程将使用单独的方法调用发出停止计时器线程的信号-
signalStopTimer()


正如您正确猜测的那样,您需要两个独立的线程运行,如下面的解释和代码所示

下面的解释将为您提供更多关于如何使用这两个线程的详细信息

(1) 线程1:
计时器
线程(内部类实现Runnable)在单独的线程中运行,并在等待用户输入时计算秒数。用户输入输入后,需要使用信号停止此线程(
stopTimer
变量充当信号),确保
stopTimer
变量是可变的(以接收Thread2写入的数据),否则此线程将无限期等待

(2) 线程2:这是等待用户输入的
主线程。一旦用户输入数据,此主线程将使用单独的方法调用发出停止计时器线程的信号-
signalStopTimer()


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

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

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

解释为什么不推荐使用
stop()

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


简而言之,如果线程在使用
synchronized
块或方法锁定对象时被
stop()
ped锁定,则对象上的锁定会以危险的突然方式释放。由于问多项选择题并对输入设置时间限制并不要求线程在某些事情上同步,因此我们可以忽略这一点。

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

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

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

解释为什么不推荐使用
stop()

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


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

如果您只需要计算用户输入所花费的时间,更好、最简单的方法是使用System.currentTimeMillis()

在扫描代码之前,您可以将当前时间保存在变量(Long)中,然后保存在while循环中(当