是一个Java套接字';什么是PrintWriter线程安全?

是一个Java套接字';什么是PrintWriter线程安全?,java,multithreading,sockets,Java,Multithreading,Sockets,所以,我有两条线 线程1管理客户端连接。(只有一台客户端和一台服务器) 我称之为我的服务器线程 线程2管理向客户端发送消息。我称之为我的消息处理器线程 线程一负责定期向客户机发送心跳信号 编程时,我假设套接字不是线程安全的,但缓冲区是,只要我为服务器和处理器线程使用单独的缓冲区,我就可以了 我还假设“PrintWriter”类似于Java中的套接字缓冲区 在这些假设下,我编写了这个函数来发送心跳: public void sendHeartBeat(){ logger.info(

所以,我有两条线

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

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

线程一负责定期向客户机发送心跳信号

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

我还假设“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());
以这种方式,每当我希望发送心跳时,我都会创建一个新的“缓冲区”,我的消息永远不会被覆盖

不幸的是,情况似乎并非如此。我从管道里得到一个信息,像这样: DSGDSBG#sdg

这将导致稍后发生堆芯转储

以下是我的问题:

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

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


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

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

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

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

第一个问题:
Writer
s不使用
作为锁<默认情况下,code>PrintWriter和
BufferedWriter
都使用
Writer
作为锁。这显然是完全失败的。他们应该使用
Writer
的锁,而不是
Writer
本身。考虑到锁定
对象
的功能会消除静态类型安全性,这是一个很容易犯的错误。因此,您需要使用套接字
OutputStream
(或其他一些公共对象)作为锁来构造一个
PrintWriter

其次,我们在
PrintWriter
中有缓冲。所以当缓冲区结束时,一半被写入,一半等待下一次写入。为了防止出现这种情况,可以从外部锁定以组合
打印
刷新
,或者使用自动刷新并添加新行字符


因此,它不是线程安全的,但您可以破解它。或者你可以使用更好的设计。

你是说PrintWriter是线程安全的,但OutputStreams不是?我认为Chris说PrintWriter是线程安全的,但同一个流上的两个线程不是线程安全的。为此,我查看了JavaSE1.6.0Ĺsrc。”PrintWriter(Writer out)最终调用“受保护的Writer(对象锁)”,在那里,“Writer”将此“锁”分配给其内部“锁”,该“锁”在“Writer”中用于同步。那么,你能解释一下为什么你认为锁定在这里被打破了吗?@shrini1000
PrintWriter
super(out)调用
Writer(对象锁定)
。所以
lock
out
,而不是
out.lock
。(这是一个实现问题-规范似乎缺失。)Java 8中的情况似乎仍然如此——PrintWriter调用super(out)并且lock是out而不是out.lock。