所以,我有两个线程。

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

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

线程一负责,除其他外,定期向客户端发送心跳。

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

我还假设“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)我如何做到这些线程不写到套接字上的同一缓冲区?

最佳答案

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

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

第一个问题:Writer不使用this作为锁。默认情况下,PrintWriterBufferedWriter都使用它们构造为锁的Writer。这显然完全被打破了。他们应该使用Writer的锁,而不是Writer本身。鉴于锁定Object功能会消除静态类型安全性,这是一个容易犯的错误。因此,您需要使用套接字PrintWriter(或其他一些常见对象)作为锁来构造OutputStream

其次,我们在PrintWriter中进行缓冲。因此,缓冲区的末尾来了,一半被写入,一半等待下一次写入。为防止这种情况,请在外部锁定以组合printflush,或使用自动刷新功能并添加新的换行符。

因此,它并不是真正意义上的线程安全的,但是您可以对其进行修改。或者您可以使用更好的设计。

关于java - Java套接字的PrintWriter线程安全吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/714287/

10-11 23:14
查看更多