【问题标题】:Code doesn't work unless I include a println or breakpoint [duplicate]除非我包含 println 或断点,否则代码不起作用 [重复]
【发布时间】:2013-11-30 16:14:42
【问题描述】:

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

对于客户端->服务器通信,我使用的是 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 或断点,它运行得很好,并且更新会按预期传播到服务器。

我很困惑。

【问题讨论】:

    标签: java multithreading sockets networking udp


    【解决方案1】:

    奇怪的是,除非我做以下两件事之一,否则这些都不起作用:

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

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

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

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

    volatile Integer clientId;
    

    此外,旋转非常恶心。或许可以输入Thread.sleep(10) 或其他东西来减慢速度?

    【讨论】:

    • 是的,做到了!阅读 volatile 变量,然后将 clientId 标记为 volatile。现在可以了。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多