- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我目前正在构建(用java练习)一个基本的命令行多人回合制游戏。在这个游戏中,每个玩家有 5 秒的时间来采取行动。当他采取行动时(或计时器结束时),其他玩家开始轮到他,等等。每次计时器结束时,服务器都会发送一条 TimerEnded
消息。我当前的目标是实现完美的输入读取,当 TimerEnded
消息到达客户端时,可能会被中断。
为了实现这一目标,我创建了一个名为 InputManager
的单例。这个类处理所有输入读取的内容。我创建了一个名为 ask
的方法,它采用回调作为参数。在此方法中,我创建了一个新线程,并在其中等待 Scanner.hasNextInt 的输入。该类还具有 closeInput
方法,该方法向上述线程发送中断消息。这是该类的当前实现:
class InputManager{
private Thread thread;
private InputManager(){}
private static InputManager instance;
private static InputManager getInstance(){
if(instance == null){
instance = new InputManager();
}
return instance;
}
/**
* Ask user to type a number.
* @param onSelected When the user has made his choice, this callback will be executed
*/
public static void ask( Consumer<Integer> onSelected){
getInstance().thread = new Thread(() -> {
System.out.println("Type a number:");
Scanner sc = new Scanner(System.in);
int selection = -1;
while (selection == -1) {
if(Thread.currentThread().isInterrupted()){
return;
}
if(sc.hasNextInt()){
selection = sc.nextInt();
onSelected.accept(selection);
} else {
sc.next();
selection = -1;
}
}
});
getInstance().thread.start();
}
/**
* Reset input stream (?)
*/
public static void closeInput(){
try {
getInstance().thread.interrupt();
} catch(NullPointerException e){
// do nothing
}
}
}
这段代码极其不可靠。我一会儿就会告诉你我的意思。我制作了一个名为 Client 的玩具类,并在 main
中用计时器模拟了 TimerEnd
消息收入。
class Client {
/**
* Ask user to type a number and send it to the server
*/
void makeRequest(){
InputManager.closeInput();
InputManager.ask((selected) -> {
System.out.println("Sent message: " + selected);
});
}
public static void main(String[] args) {
Client client = new Client();
client.makeRequest();
// Simulate Server messages
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println("Message received");
client.makeRequest();
}
}, 5000, 5000);
}
}
以下是它的实际工作原理:
Type a number:
2
Sent message: 2
Message received
Type a number:
3
Sent message: 3
Message received
Type a number: // Here I don't type anything
Message received
Type a number:
Message received
Type a number:
Message received
Type a number: // Here I can send multiple messages on the same "turn"
1
Sent message: 1
2
Message received
目前,我猜想 Scanner 仍在等待输入,因此在给出输入之前不会命中 if(isInterrupted)
语句。如果是这样,我该如何避免这种行为?
我知道这个问题非常长(也许没有必要),既然您阅读了它,请让我感谢您花时间。
package com.company;
import java.util.*;
import java.util.function.Consumer;
class InputManager{
private Thread thread;
private InputManager(){}
private static InputManager instance;
private static InputManager getInstance(){
if(instance == null){
instance = new InputManager();
}
return instance;
}
/**
* Ask user to type a number.
* @param onSelected When the user has made his choice, this callback will be executed
*/
public static void ask( Consumer<Integer> onSelected){
getInstance().thread = new Thread(() -> {
System.out.println("Type a number:");
Scanner sc = new Scanner(System.in);
int selection = -1;
while (selection == -1) {
if(Thread.currentThread().isInterrupted()){
return;
}
if(sc.hasNextInt()){
selection = sc.nextInt();
onSelected.accept(selection);
} else {
sc.next();
selection = -1;
}
}
});
getInstance().thread.start();
}
/**
* Reset input stream (?)
*/
public static void closeInput(){
try {
getInstance().thread.interrupt();
} catch(NullPointerException e){
// do nothing
}
}
}
class Client {
/**
* Ask user to type a number and send it to the server
*/
void makeRequest(){
InputManager.closeInput();
InputManager.ask((selected) -> {
System.out.println("Sent message: " + selected);
});
}
public static void main(String[] args) {
Client client = new Client();
client.makeRequest();
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println("Message received: thread interrupted");
client.makeRequest();
}
}, 5000, 5000);
}
}
最佳答案
据我所知,您可以使用 3 种类型的线程:
所以我将使用 2 个生产者和 1 个消费者,如下所示:
所有这些,这样您就不必费力去中断任何正在运行的线程,也不需要检查扫描仪是否准备就绪...
import java.util.Scanner;
public class Main {
private static final Scanner SCAN = new Scanner(System.in);
//This is the Scanner's input Producer:
private static class UserInputProducer extends Thread {
private final UserInputConsumer uInConsumer;
public UserInputProducer(final UserInputConsumer uInConsumer) {
this.uInConsumer = uInConsumer;
}
@Override
public void run() {
while (true) {
final int input = SCAN.nextInt();
SCAN.nextLine(); //Ignore the new line character.
uInConsumer.userInput(input); //Fire user input event (for the current user).
}
}
}
//This is the time out event Producer:
private static class TimeOutEventProducer {
private final UserInputConsumer uInConsumer;
private int validReportId = Integer.MIN_VALUE; //IDs starting from Integer.MIN_VALUE and
//going step by step to Integer.MAX_VALUE, which means about 4 billion resets can be done
//to this Producer before an unhandled overflow occurs.
public TimeOutEventProducer(final UserInputConsumer uInConsumer) {
this.uInConsumer = uInConsumer;
}
public synchronized void reset() {
new TimerOnce(this, ++validReportId).start(); //Start a new TimerOnce. Could be javax.swing.Timer with "setRepeats(false)".
}
/*sleepDone(...) is called by ALL TimerOnce objects... So we need an up-to-date id (the
reportId) to verify that the LAST one TimerOnce finished, rather than any other.*/
public synchronized void sleepDone(final int reportId) {
if (reportId == validReportId) //Only the last one timeout is valid...
uInConsumer.timedOut(); //Fire time out event (for the current user).
}
}
//This is just a "Timer" object which blocks for 5 seconds:
private static class TimerOnce extends Thread {
private final TimeOutEventProducer timeout;
private final int reportId;
public TimerOnce(final TimeOutEventProducer timeout,
final int reportId) {
this.timeout = timeout;
this.reportId = reportId;
}
@Override
public void run() {
try { Thread.sleep(5000); } catch (final InterruptedException ie) {} //Wait.
timeout.sleepDone(reportId); //Report that the time elapsed...
}
}
//This is the Consumer:
private static class UserInputConsumer {
private final String[] names;
private int input;
private boolean timedOut, hasInput;
public UserInputConsumer(final String[] names) {
this.names = names;
}
public synchronized int play() {
new UserInputProducer(this).start(); //Start scanning any user's input...
final TimeOutEventProducer timeout = new TimeOutEventProducer(this);
int i = -1;
do {
i = (i + 1) % names.length;
hasInput = false;
timedOut = false;
timeout.reset(); //Start the input wait timer...
System.out.print("User " + names[i] + " enter a number: "); //Clarify who's player is the turn.
while (!hasInput && !timedOut)
try { wait(); } catch (final InterruptedException ie) {} //Wait for user input or timeout.
//Interpret notification event (either user input, either timeout):
if (timedOut)
System.out.println("Sorry, out of time.");
else if (!hasInput)
throw new UnsupportedOperationException("Probably messed with the flags in the while-condition.");
}
while (input != 5); //Here you test the win/loss condition.
//Lets say, for example, the user that enters number '5' wins...
return i; //Return the winner's index.
}
public synchronized void timedOut() {
timedOut = true;
notify();
}
public synchronized void userInput(final int input) {
this.input = input;
hasInput = true;
notify();
}
}
public static void main(final String[] args) {
System.out.print("Enter number of players: ");
final int numPlayers = SCAN.nextInt();
SCAN.nextLine(); //Ignore the new line character.
final String[] names = new String[numPlayers];
for (int i=0; i<names.length; ++i) {
System.out.print("User " + (i+1) + " enter your name: ");
names[i] = SCAN.nextLine();
}
//Start the consumer (which in turn starts the producers) and start the main logic:
System.out.println(names[new UserInputConsumer(names).play()] + " wins!");
}
}
注意,程序永远不会终止,因为扫描是无限的。但是您可以通过扰乱 UserInputProducer
的 while (true)
条件来改变此行为。
关于java - 停止扫描仪等待输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51091296/
我在使用 Scanner 类中的 useDelimiter 时遇到一些问题。 Scanner sc = new Scanner(System.in).useDelimiter("-"); while(
我是 Java 新手。 我目前正在做一个业余项目;制作基于文本的游戏。我意识到使用 Switch 语句对于此类游戏非常有用。 这基本上就是它的工作原理。 我问用户,你想做什么? 吃 步行 等等 那么,
我正在尝试使用扫描仪从“p.addPoint(x,y);”形式的字符串中读取代码行 我想要的正则表达式格式是: *任何内容*.addPoint(*空格或无* 或 ,*空格或无* 到目前为止我所尝试的方
我正在使用 java Scanner 尝试从名为 Inventory.txt 的文本文件中提取产品信息。 此文件包含以下格式的产品数据: “Danelectro|Bass|D56BASS-AQUA|3
我是java初学者,我正在努力让这段代码正常工作。我正在尝试读取 CSV 文件,然后使用该数据计算平均值,然后返回平均值的最高最低值和平均值的摘要。 输入如下所示: Alicia Marks,89,9
当我进入/忽略文件 reg.txt 中的最后一个新行时,我需要一些有关退出的帮助。截至目前,当它到达最后一行时,我收到一个错误,其中不包含任何内容。 public String load() {
我的程序应该提示用户输入与参加了多少次考试相关的考试分数。然而,这工作得很好,当用户输入负的考试分数时,应该让他们再次重新进入所有三项考试。我的程序会保存任何非负面的考试,因此当您重新输入三项考试时,
这个问题已经有答案了: Scanner is skipping nextLine() after using next() or nextFoo()? (25 个回答) 已关闭 9 年前。 下面给出的
我想读取用户输入,例如:11 12 13 14 15 16 Scanner sc = new Scanner(System.in); while(sc.hasNext()){
String[] invalidChars = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; Scanner sc = ne
我有一个txt文件,每行包含两个单词,例如: USA 321 France 1009 ... Germany 902 如何在二维数组中逐字读取该文件?我有: List> temps = new Arr
我的 Java 作业有问题。我收到意外异常,特别是: java.util.NoSuchElementException: No line found 我正在使用 Scanner(System.in)
我有一个很大的困惑,当我们有 Sonar 服务器时 Sonar 扫描仪有什么用?当我使用 soarqube 服务器分析一个项目时,它进行了分析并且运行良好。我仍然很困惑为什么我们也需要扫描仪。 与ec
为什么我在递归方法中遇到无限循环,而没有机会输入任何符号来打破它? class Test { int key=0; void meth(){ System.out.println
我在运行此函数时遇到错误。它使用扫描仪在某个文件中查找单词。 这里是: public static boolean VerifyExistWord(File FileToSearch, String
各位程序员大家好。 我有一些代码,spring工具套件编辑器的响应也不同,也许你们中的一些聪明人知道为什么。 File inputFile = new File(System.getProperty(
是否可以从我的网络应用程序中使用 Flash 访问通用 twain 扫描仪,保存文件并将其上传到我的应用程序中? 我已经通过谷歌进行了一些搜索,但无法找到更多细节。是否有任何预制的解决方案,付费/免费
我试图在 float 组中引入一组 float 字: protected float[] a = new float [100]; public void setCoef(){ System.
我一直在做一项充当拼字游戏词典的编程作业。该程序接受用户的输入,并根据用户从菜单中请求的内容输出包含单词列表的文件。我遇到的问题与 Scanner.nextLine() 有关。 我不太清楚为什么,但由
我试图让程序询问百分比(等级),但我希望它在用户进行第一个输入并看到输出后再次询问。我在循环中遇到问题,因为未分配变量 myMark。 import java.util.Scanner; public
我是一名优秀的程序员,十分优秀!