Java中的服务器程序并将引用传递给Socket对象

时间:2011-12-03 15:02:24

标签: java sockets network-programming

我正在用Java编写一个多线程程序,我正在创建一个单独的线程来处理每个新的客户端连接。我有:

Socket s;


while(true)
{
    s = server.accept();
    ClientHandler ch = new ClientHandler(s);
    Thread servingThread = new Thread(ch);
    servingThread.start();
}

在ClientHandler线程中我有:

public class ClientHandler implements Runnable
{
    private Socket s;

public ClientHandler(Socket _Socket, boolean _accepted, BaseStation _bs)
{
    this.s = _Socket;
}

如果在Java中我不能传递一个对象而只是一个对它的引用,那不会导致问题,只要s传递给ClientHandler中的server实例接受新连接? 它是否也不会在ClientHandler内部发生变化并破坏它?如果是这样,那么正确的方法是什么?

3 个答案:

答案 0 :(得分:2)

请参阅Is Java "pass-by-reference" or "pass-by-value"?进行解释。

将新的Socket实例传递给新的ClientHandler实例很好,因为每个ClientHandler都有自己的Socket - 更改了局部变量{{1}的值不影响sSocket实例的副本。

this 之类的东西会导致问题:

ClientHandler

因为ClientHandler ch = new ClientHandler(s); Thread servingThread = new Thread(ch); servingThread.start(); s.someMethod(); // close, read etc. ch.s都指向相同的基础s对象实例。

BTW:在一个while循环中旋转一个全新的线程可能很糟糕,除非你确定这些线程会终止。使用ThreadPool可能更好。

答案 1 :(得分:2)

您的顾虑是正确的,因为Socket对象(与Java中的任何其他对象一样)是通过引用传递的,因此它有可能被不同的模块或不同的线程引用,从而导致不可预测的行为。 / p>

但是,如果你的程序没有问题。原因是:每当服务器接受新连接时,它将创建一个 new Socket对象,然后将其传递给{{1}的 new 实例。 }。因此,来自客户端的每个新连接都将由独立的ClientHandler实例提供服务,因此ClientHandler对象无需担心竞争条件。所以你现在安全了。

作为一个反例,如果您决定创建两个Socket个线程来读取相同的 ClientHandler对象,就像这样......

Socket

...然后您可能遇到麻烦,因为两个s = server.accept(); ClientHandler ch = new ClientHandler(s); ClientHandler ch2 = new ClientHandler(s); new Thread(ch).start(); new Thread(ch2).start(); 将获得与相同的 ClientHandler对象的相同的引用,如果两者都试图从同一个套接字读取它们每个只获得一半的数据。例如。如果您收到字符串Socket,则最终可能会"hello"阅读ch"hel"阅读ch2或任何其他组合。

答案 2 :(得分:1)

这有点令人困惑,但您的代码应该如图所示。 Java首先按值传递,然后按引用传递。 I.E.,您没有传递指向“Socket s”的指针,而是传递“s”时的实际值。

为了简化并消除混淆,我只需删除您的“Socket s;”前向声明,并在循环“Socket s = server.accept();”中设置第一行。