所以,我有两个主题.
线程1管理客户端连接.(只有一个客户端和一个服务器)
我称之为我的服务器线程.
线程二管理向客户端发送消息.我称之为消息处理器线程.
线程1负责,除其他外,定期向客户端发送心跳.
在编程时我假设套接字不是线程安全的,但缓冲区是,并且只要我使用单独的缓冲区用于服务器和处理器线程我就没问题了.
我还假设"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
s放在同一个流上是一种糟糕的设计.真的,你至少想要调用它们的对象(或线程受限).
但是,假设由于某种原因你确实需要多个PrintWriter
s:
第一个问题:Writer
s不用this
作锁.PrintWriter
并且BufferedWriter
默认情况下都使用Writer
它们构造为锁.这显然完全被打破了.他们应该使用Writer
锁,而不是Writer
自己.一个容易出错的错误,因为锁定一个特征Object
可以消除静态类型的安全性 因此,您需要PrintWriter
使用套接字OutputStream
(或其他一些常见对象)构造一个锁作为锁.
其次,我们内部有缓冲PrintWriter
.因此,缓冲区结束,写入一半,等待下一次写入.为了防止这种情况,或者是通过外部锁定到结合了print
和flush
,或使用自动冲洗,并添加一个新行字符.
因此,它没有任何有意义的线程安全,但你可以破解它.或者你可以使用更好的设计.