【问题标题】:Determining first client to press a button确定第一个客户按下按钮
【发布时间】:2014-03-02 01:38:58
【问题描述】:

我正在制作一个控制台游戏,其中用户通过 telnet 连接到服务器,并且在看到特定数字时必须按空格键。 每个客户端连接都有一个线程。 我正在询问最佳实践解决方案,以确定哪个客户端是第一个按空格键的。 目前我正在这样做:

public class Player {

    public Socket socket;
    public PrintWriter output;
    public BufferedReader input;
    public Player opponent;
    public boolean isPlaying;

这就是玩家所知道的一切。

在我拥有的客户端线程的run 方法中:

    while (player.isPlaying == true && player.opponent.isPlaying == true)
        {
            player.isPlaying = listenAnswers();
        }               

        player.socket.close();
        player.opponent.socket.close();

我在 listenAnswers 方法中有这个:

    int answer = view.receiveAnswer(player);
    if (answer == model.getWinningAction() )
    {
        view.sendWinMessage(player, isWinConditionMet);
        view.sendLoseMessage(player.opponent, isWinConditionMet);
        player.opponent.isPlaying = false;
        return false;
    }

receiveAnswer 方法基本上只返回player.input.read();

当我运行我的服务器时,将客户端连接到它,其中一个按下空格键一切看起来都不错,但是在receiveAnswer 方法中执行read 时,我在第二个客户端线程中成为异常。当然我可以忽略它,但我认为应该有更好的解决方案,我正在寻求它们。 基本上我在获胜线程中完成了所有工作,但是当每个客户只为自己做某事时,是否有可能?赢家写赢信息,输家写输信息。

【问题讨论】:

  • 任何时候您从另一个线程访问一个线程中的信息,都必须进行内存同步。在这种情况下,您需要使isPlaying 至少为volatile。如果有测试/设置操作,您可能想使用AtomicBoolean

标签: java multithreading


【解决方案1】:

您可以拥有一个所有线程都可以看到的布尔值,当您从其中一个客户端获得空格键时,您可以检查它的值。如果为真,则表示当前线程丢失。如果它是假的,你把它设置为真,这个线程就赢了。

请注意,您必须同步对该布尔值的访问,因为您将有明显的竞争条件。

无论如何,这将给你第一个抓住空格键的线程。

如果你想让它变得更好,客户端应该发送一些时间戳,这样你就可以检查哪个是第一个被按下的(但你应该添加某种完整性检查以确保客户端没有更改实际时间戳,或发送虚假时间戳)。

【讨论】:

  • 我曾尝试为此使用player.isPlaying 变量,但问题是:每个客户端线程首先检查此布尔值,然后等待客户端输入。第一次我们检查它是true,我们一直等到false,但是我们不能再检查一次,直到我们从inputStream中读取一些东西,所以两个客户端都必须在他们知道结果之前输入一些东西
  • 但是玩和赢是不一样的。你想读取输入,一旦你找到一个空格键,你检查是否有任何客户赢了。如果没有人有,那么这个线程就赢了,否则它就输了
  • 你看,我只能在每个客户按下空格键后才能确定谁赢了,但我的目标是在第一个客户按下空格键而第二个客户还没有按下它时找到它
  • 没问题...我假设每个客户端的 io 操作发生在不同的线程中。因此,每当第一个客户端按下空格键时,winnerFound 布尔值将为 false,那么您就知道这个客户端赢了,只是因为之前没有人设置过。您不需要每个客户都按空格键
  • 哦,你想唤醒其他线程。然后你必须在其他线程上调用 Thread.interrupt() 并捕获 InterruptedException。或者,您可以使用非阻塞输入输出(Java nio),这也可以让您在一个线程中完成所有这些操作
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-17
  • 1970-01-01
  • 2015-12-11
  • 1970-01-01
  • 2018-04-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多