终端中的数据循环打印可由用户输入终止



我的任务是在终端中打印货币汇率表,每分钟延迟打印一次表。在用户输入时,我将结束循环并返回海关终端菜单。如何实现这一点?

一般来说,我有一个问题需要弄清楚如何获得无缝的用户体验。我需要在终端中输入用户,如果没有用户操作,我仍然每分钟打印一次数据。最终,如果用户决定终止打印,如何终止整个数据打印循环? -> 运行标志 = ????;

这真的是正确的方法吗?

我已经尝试了几种方法,不幸的是没有工作。

有人可以帮助我吗?

到目前为止,我只有以下代码。循环打印汇率的自定义方法:

private void printExchangeRateTable(final Map<String, Integer> storedExchangeRates){
    boolean runFlag = true;
    do {
        printExchangeRates(storedExchangeRates);
        println("Hit any key to stop loop");
        Thread threadDelayer = new Thread(new Delayer());
        Thread threadListeningUserInput = new Thread(new UserInputListener());
        threadDelayer.start();
        threadListeningUserInput.start();
        runFlag = ????;
    } while (runFlag);
}

分层对象

final class Delayer implements Runnable {
    public static final long MILISECONDS = 1000L;
    @Override
    public void run(){
        try {
            Thread.sleep(60 * MILISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

用户输入侦听器

class UserInputListener implements Runnable {
    @Override
    public void run()  {
        Scanner scanner = new Scanner(System.in);
        val userInput = scanner.nextLine();
        if(userInput != null) {
            Thread.currentThread().interrupt();
        }
    }
}
您可以使用

ScheduledExecutorService设置重复任务,但在这里,将用户输入的读数发送到后台任务要容易得多

public static void main(String[] args) {
    Scanner s = new Scanner(System.in);
    CompletableFuture<String> userInput = CompletableFuture.supplyAsync(s::nextLine);
    while(!userInput.isDone()) {
        printData();
        try {
            userInput.get(1, TimeUnit.MINUTES);
        }
        catch(ExecutionException|InterruptedException ex) {} // handled after the loop
        catch(TimeoutException ex) {
            continue;
        }
    }
    String input = userInput.join();
    // handle input
}
private static void printData() {
    System.out.println("data");
}

CompletableFuture.supplyAsync(s::nextLine)会将s.nextLine()的执行提交到后台任务。然后,循环将一直运行,直到后台任务完成,每分钟执行一次printData()。这是通过userInput.get(1, TimeUnit.MINUTES)实现的,如果在指定时间后没有可用的结果,它将抛出TimeoutException。这里不需要continue,因为循环无论如何都会继续,但我明确表示。

其他可能的异常是内在处理的。中断不应该发生,但通过进入下一次迭代,它可以用作甚至在时间之前刷新打印数据的信号。当发生ExecutionException时,当我们在循环后的 join() 语句中获取实际用户输入时,将报告错误状态。

这个循环也可以合并到一个更大的循环中。

Scanner s = new Scanner(System.in);
for(boolean quit = false; !quit; ) {
    CompletableFuture<String> userInput = CompletableFuture.supplyAsync(s::nextLine);
    while(!userInput.isDone()) {
        printData();
        try {
            userInput.get(1, TimeUnit.MINUTES);
        }
        catch(ExecutionException|InterruptedException ex) {} // handled implicitly
        catch(TimeoutException ex) {
            continue;
        }
    }
    String input = userInput.join();
    // handle input
    if(input.equals("exit")) quit = true;
}
你可以

试试这个。我使用相同的逻辑来读取用户输入,但对于打印,我将使用计时器(此处计划每 1 秒运行一次,但您可以更改它(。管理计时器更容易,并且可以从另一个线程取消。

public class Main {
public static void main(String[] args) {
    Thread inputListener = new Thread(new UserInputListener());
    inputListener.start();
}
static class MyTimerTask extends TimerTask
{
    public void run()
    {
        System.out.println("some output");
    }
}
static class UserInputListener implements Runnable {
    @Override
    public void run()  {
        Timer timer = new Timer();
        TimerTask task = new MyTimerTask();
        timer.schedule(task, 0, 1000);
        Scanner scanner = new Scanner(System.in);
        scanner.nextLine();
        timer.cancel();
    }
  }
}

首先,您需要两个线程,但您不必创建两个线程 - 您可以使用主线程进行用户输入,并在程序开始时启动另一个线程,该线程将每分钟打印一次货币汇率。

每个线程内部都有一个无限(或标志控制的(循环。但是,与其自己管理,我建议使用 ScheduledExecutorService ,否则您将很难中断线程。

下面是一个示例:

import java.util.Scanner;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Example {
    public static void main(String[] args) {
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        executor.scheduleWithFixedDelay(Example::printData, 1, 1, TimeUnit.MINUTES);
        Scanner scanner = new Scanner(System.in);
        while (true) {
            String userInput = scanner.nextLine();
            if (userInput.equals("exit")) {
                break;
            }
        }
        executor.shutdown();
    }
    private static void printData() {
        System.out.println("data");
    }
}

如果没有其他用户输入要处理,并且它仅用于停止后台线程,则根本不需要此线程中的循环,您可以将其简化为:

public static void main(String[] args) {
    ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
    executor.scheduleWithFixedDelay(Example::printData, 1, 1, TimeUnit.MINUTES);
    Scanner scanner = new Scanner(System.in);
    scanner.nextLine();
    executor.shutdown();
}

最新更新