This question already has an answer here:
Loop doesn't see value changed by other thread without a print statement
                                
                                    (1个答案)
                                
                        
                4年前关闭。
            
        

我正在制作基本的多人射击游戏,作为大学计算机图形学课程的一部分。

对于客户端->服务器通信,我使用UDP。每个客户端都有一个ClientController线程,该线程处理用户输入并将其通过套接字发送到服务器。服务器正在运行ServerClientManager,后者处理消息并在游戏状态下更新玩家的对象。

这是ClientController的代码:

/**
 * A class that handles communication from client to server.
 */
public class ClientController implements Runnable {
    private String serverAddress;
    int serverPort;
    Integer clientId;
    @SuppressWarnings("unused")
    private boolean forward, backward, left, right, fire, up, down;

    public ClientController (String serverAddress, int serverPort) {
        System.out.println("ClientController started");
        this.serverAddress = serverAddress;
        this.serverPort = serverPort;
        clientId = null;
        reset();
    }

    public synchronized void forward() {
        forward = true;
    }
    ...

    private synchronized void reset() {
        forward = false;
        backward = false;
        left = false;
        right = false;
        fire = false;
        up = false;
        down = false;
    }

    @Override
    public void run() {
        System.out.println("ClientController thread is running");
        while (true) {
            //System.out.println("tick");
            if (clientId != null) {
                try {
                    ClientUpdate update = new ClientUpdate(forward, backward, left, right, fire, up, down, clientId);
                    ClientUDPSender sender = new ClientUDPSender(serverAddress, 1233, update.toJson());
                    Thread worker = new Thread(sender);
                    worker.start();
                    Thread.sleep(15);
                    reset();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public synchronized void setClientId(int clientId) {
        this.clientId = clientId;
    }
}


这会将更新发送到服务器。在启动时,客户端启动此线程。然后,客户端在另一个类中通过TCP单​​独接收其clientId(初始游戏状态和连接信息通过TCP发送)。一旦设置了clientId,UDP客户端便开始通信。

奇怪的是,除非我执行以下两项操作之一,否则所有这些都不起作用:

1)取消注释System.out.println(“ tick”)行。

2)在try语句中放置一个断点,然后从那里继续。

如果仅按原样运行该程序,则它永远不会到达try语句的内部。如果我包含println或breakpoint,它运行得很好,并且更新将按预期方式传播到服务器。

我很困惑。

最佳答案

奇怪的是,除非我执行以下两项操作之一,否则所有这些都不起作用:
  
  1)取消注释System.out.println(“ tick”)行。


PrintStream.println(...)synchronized方法,因此我怀疑您的问题与内存同步有关。


  然后,客户端通过另一个类中的TCP单独接收其clientId


如果我理解的话,似乎clientId是由另一个线程设置的。如果为true,则必须将其标记为volatile,否则旋转的线程将看不到更新。即使setClient(...)方法是synchronized,在您的while(true)循环中也没有任何东西可以跨越内存障碍并更新旋转线程的内存缓存中的clientId值。将clientId标记为volatile后,可以删除设置器上的synchronized关键字。

volatile Integer clientId;


另外,旋转非常麻烦。也许放入Thread.sleep(10)或使其减慢一点?

关于java - 除非我包含println或断点,否则代码不起作用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20032093/

10-12 16:15