所以,我有两个线程。
线程一管理客户端连接。 (只有一个客户端和一台服务器)
我称它为我的服务器线程。
线程二管理向客户端发送消息。我称它为我的消息处理器线程。
线程一负责,除其他外,定期向客户端发送心跳。
在编程时,我假设套接字不是线程安全的,但是缓冲区是安全的,并且只要我为服务器和处理器线程使用单独的缓冲区,我就可以了。
我还假设“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
作为锁。默认情况下,PrintWriter
和BufferedWriter
都使用它们构造为锁的Writer
。这显然完全被打破了。他们应该使用Writer
的锁,而不是Writer
本身。鉴于锁定Object
功能会消除静态类型安全性,这是一个容易犯的错误。因此,您需要使用套接字PrintWriter
(或其他一些常见对象)作为锁来构造OutputStream
。
其次,我们在PrintWriter
中进行缓冲。因此,缓冲区的末尾来了,一半被写入,一半等待下一次写入。为防止这种情况,请在外部锁定以组合print
和flush
,或使用自动刷新功能并添加新的换行符。
因此,它并不是真正意义上的线程安全的,但是您可以对其进行修改。或者您可以使用更好的设计。
关于java - Java套接字的PrintWriter线程安全吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/714287/