12

对于学校的一个项目,我们正在用 Java 5.0 制作一个多线程服务器。该项目以服务器的并发方面为中心。

我们有一些线程专门用于处理请求。为此,他们调用 ServerSocket.accept() 来接受新连接。我们的选择是启动一堆它们,让它们以两个线程不能同时接受()同一个连接的假设来处理传入的连接。

但现在主要的问题是我们在 API 中找不到任何东西来保证我们的这种行为(或者我们看起来不正确),除了“它有效”的证明之外,我们什么也没有。

有没有人在java方法上寻找这种信息的来源?

4

2 回答 2

27

简短的回答:如果文档没有指定某些东西是线程安全的,那么您必须假设它不是。您需要自己进行线程之间的协调,以确保没有两个线程同时使用服务器套接字。

这一点尤其重要,因为其他一些代码可能已经使用ServerSocket.setSocketFactory. 即使默认套接字实现是线程安全的,自定义实现也不必如此。文档中没有任何内容这么说。

长答案:默认 Windows 实现

您可以下载并检查java SE 1.6 源代码

我从那里开始,\j2se\src\share\classes\java\net\ServerSocket.java从那里开始通往PlainSocketImpl.java. 该PlainSocketImpl.Accept方法标记为native

Windows 的本机 C++ 代码位于\j2se\src\windows\native\java\net\PlainSocketImpl.c. 它使用winsock 接受函数。来自关于 WinSock 的 MSDN 文章(重点是我的):

在 Windows NT 和 Windows 2000 下,对 16 位应用程序的 Windows 套接字支持基于 WINSOCK.DLL。对于 32 位应用程序,支持在 WSOCK32.DLL 中。提供的 API 是相同的,只是 32 位版本的参数扩展为 32 位。在 Win32 下,提供了线程安全。

所以至少在 Windows 上,Socket.Accept是线程安全的,因为它不会让两个线程接受相同的连接。实现中还有基础设施ServerSocket(例如 Close() 方法使用锁),这表明它是线程安全的。

于 2009-05-22T14:44:39.597 回答
10

这并不能完全回答您的问题,但是在多个线程上运行 accept() 听起来服务器的设计有问题。

通常不需要从多个线程运行 accept() 。

您的代码应如下所示:

while (serverIsUpAndRunning())
{
    // Wait for an incoming connection.
    Socket s = serverSocket.accept();
    // Spawn a thread to handle the socket,
    // so that we don't block new connections.
    SocketHandlerThread t = new SocketHandlerThread(s);
    t.start();
}
于 2009-05-22T08:06:04.673 回答