【问题标题】:Is a Java socket's PrintWriter thread safe?Java 套接字的 PrintWriter 线程安全吗?
【发布时间】:2009-04-03 14:53:27
【问题描述】:

所以,我有两个线程。

线程一管理客户端连接。 (只有一个客户端和一个服务器)
我称它为我的服务器线程。

线程二管理向客户端发送消息。我称它为我的消息处理器线程。

线程一负责定期向客户端发送心跳。

在编程时,我假设套接字不是线程安全的,但缓冲区是,只要我为服务器和处理器线程使用单独的缓冲区就可以了。

我还假设“PrintWriter”类似于 Java 中的套接字缓冲区。

在这些假设下,我编写了这个函数来发送心跳:

public void sendHeartBeat(){
        logger.info("Sending a hearbeat!");
        PrintWriter printWriter=null;
        try {
            printWriter = new PrintWriter(clientSocket.getOutputStream());
        } catch (IOException e) {
            logger.info(e.toString());
        }
        if(printWriter!=null){
            printWriter.print("HEARTBEAT#");
            printWriter.flush();
        }
    }

另一个线程,“处理器”线程做了类似的事情:

printWriter=new PrintWriter(theServer.getClientSocket().getOutputStream());

以这种方式,我每次希望发送心跳时都会创建一个新的“缓冲区”,并且我的消息永远不会被覆盖。

不幸的是,情况似乎并非如此。我通过管道收到一条消息,如下所示: dsgdsbHEARTBEAT#sdg

这会导致稍后发生核心转储。

这是我的问题:

1) 套接字显然不是线程安全的,但是我从它们那里得到的 PrintWriters 是线程安全的吗?还是只是返回相同的 PrintWriter?

2) 什么类似于 Java 中的套接字缓冲区?我应该如何看待这个问题?

3) 如何使这些线程不写入套接字上的同一个缓冲区?

【问题讨论】:

    标签: java multithreading sockets


    【解决方案1】:

    将这些多个PrintWriters 放在同一个流上是一个糟糕的设计。实际上,您至少希望调用它们的对象是同步的(或线程受限的)。

    但是,假设出于某种原因您确实需要多个 PrintWriters:

    第一个问题:Writers 不要使用this 作为锁。 PrintWriterBufferedWriter 默认都使用 Writer 作为锁。这显然是彻底坏掉了。他们应该使用Writer 的锁,而不是Writer 本身。考虑到锁定Object 的功能会消除静态类型安全性,这是一个简单的错误。因此,您需要构造一个PrintWriter,并将套接字OutputStream(或其他一些常见对象)作为锁。

    其次,我们在PrintWriter 中有缓冲。所以在缓冲区结束时,一半被写入,一半等待下一次写入。为防止这种情况发生,要么在外部锁定以组合 printflush,要么使用自动刷新并添加换行符。

    所以,它不是有意义地线程安全的,但你可以破解它。或者你可以使用更好的设计。

    【讨论】:

    • 为此我查看了 Java SE 1.6.0_31 src。 'PrintWriter(Writer out)' 最终调用'protected Writer(Object lock)' 并且在那里,'Writer' 将这个'lock' 分配给它的内部'lock',它在'Writer' 中用于同步。你能请。解释一下为什么你认为这里的锁定被破坏了?
    • @shrini1000 PrintWritersuper(out); 调用Writer(Object lock)。所以lockout,而不是out.lock。 (这是一个实施问题 - 似乎缺少规范。)
    • 在 Java 8 中似乎仍然是这种情况—— PrintWriter 调用 super(out) 并且 lock is out 而不是 out.lock。
    【解决方案2】:

    您需要一种在线程之间使用相同PrintWriter 的方法(t1.writer == t2.writer,而不仅仅是从相同OutputStream 创建的PrintWriters)。同一个PrintWriter,所有的写操作都是同步的。

    【讨论】:

    • 你是说 PrintWriters 是线程安全的,但 OutputStreams 不是?
    • 我认为 Chris 说 PrintWriter 是线程安全的,但同一流上的两个线程安全并没有意义。因此使用一个。
    猜你喜欢
    • 1970-01-01
    • 2012-11-12
    • 2016-05-16
    • 2016-02-22
    • 2011-01-22
    • 2021-06-20
    • 2011-03-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多