除非我包含println或断点,否则代码不起作用

时间:2013-11-17 14:53:03

标签: java multithreading sockets networking udp

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

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

我很困惑。

1 个答案:

答案 0 :(得分:2)

  

奇怪的是,除非我做两件事之一,否则这一切都无效:

     

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

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

  

然后,客户端通过另一个类

中的TCP分别接收它的clientId

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

volatile Integer clientId;

此外,纺纱非常糟糕。也许放入Thread.sleep(10)或其他东西来减慢它的速度?