为什么java和go在写之前都要锁定socket?

j8ag8udp  于 2021-06-30  发布在  Java
关注(0)|答案(2)|浏览(344)

go internal/poll/fdïu unix.go代码在这里

// Write implements io.Writer.
func (fd *FD) Write(p []byte) (int, error) {
    if err := fd.writeLock(); err != nil {
        return 0, err
    }
    defer fd.writeUnlock()
    ......
}

java代码java.net.socketoutputstream#socketwrite在这里

private void socketWrite(byte b[], int off, int len) throws IOException {
        if (len <= 0 || off < 0 || len > b.length - off) {
            if (len == 0) {
                return;
            }
            throw new ArrayIndexOutOfBoundsException("len == " + len
                    + " off == " + off + " buffer length == " + b.length);
        }

        FileDescriptor fd = impl.acquireFD();
        try {
            socketWrite0(fd, b, off, len);
        } catch (SocketException se) {
        ......

我不知道我们为什么要锁上它。另一个问题是syscall.write等价于<unistd.h>在c中写入?

6ojccjat

6ojccjat1#

好的,假设没有锁定机制,两个并发线程/进程正在向套接字写入一些数据。让我们举一个过于简单的例子。
java应用程序想写:“你好!“你好吗?”。
去申请要写:“回头见。”
这两个应用程序都试图同时编写。
您期望的输出是:

Hello! How are you?
See you later.

然而,很有可能你会得到这样的东西。

HellSee o! How  See you are later.
 you?

当一个资源在不同的进程/线程之间共享并且没有适当的锁定机制时。遇到不一致和意外行为的可能性很大。

hlswsv35

hlswsv352#

好吧,只回答java部分:
既然我们已经在讨论实现细节,为什么还要停留在java级别呢?本机方法socketwrite0的openjdk实现的c源代码跨越约70行代码,显然不是原子的。它可以使用 malloc 以及 free ,并涉及相当多的非琐碎逻辑。不管 NET_Send 它调用的函数实际上直接发送数据,在每个受支持的平台上都转换成syscall,在这一点上已经不再重要了。
要点是:实现调用 NET_Send -循环中的函数。因此,无论这是否是线程安全的,如果它是由多个线程并发调用的,那么输出将是交错的(最佳情况)。

相关问题