我遇到了一个奇怪的问题,这个线程从输入流读取,特别是readObject。该线程在调用时阻塞,因为我试图将日志调试语句放入并显示其阻塞。问题是这个线程仍然标记为在探查器中运行,它占用了我的CPU使用率的50%。我有一个类似的线程,它正确阻塞,当阻塞占用0%的CPU。我对这里可能出现的问题感到困惑。
由于我是新用户,我无法发布图片,请参阅。 图像中的绿色表示正在运行,黄色被阻止或等待。
图片也可以取消缩放here:
主要
{
SocketFactory factory = SocketFactory.getDefault();
Socket tcpSocket = factory.createSocket("localhost", 5011);
IoTcpReadRunnable ioTcpReadRunnable = new IoTcpReadRunnable(new MessageProcessor()
{
@Override
public void enqueueReceivedMessage(Object message)
{
System.out.println("MessageReceived Enqueued.");
}
@Override
public void enqueueMessageToWrite(Envelope message)
{
System.out.println("Message Enqueued to Write.");
}
}, tcpSocket);
new Thread(ioTcpReadRunnable, "ClientExample IoTcpRead").start();
}
TcpRead Runnable
public final class IoTcpReadRunnable implements Runnable {
public static final Logger logger = LoggerFactory.getLogger(IoTcpReadRunnable.class);
protected MessageProcessor<MessageType> messageProcessor = null;
protected Socket tcpSocket = null;
protected ObjectOutputStream outputStream = null;
protected ObjectInputStream inputStream = null;
protected boolean connected = false;
public IoTcpReadRunnable(MessageProcessor<MessageType> messageProcessor, Socket tcpSocket)
{
this.messageProcessor = messageProcessor;
this.tcpSocket = tcpSocket;
this.init();
}
protected void init()
{
try
{
this.outputStream = new ObjectOutputStream(tcpSocket.getOutputStream());
this.outputStream.flush();
this.inputStream = new ObjectInputStream(tcpSocket.getInputStream());
}
catch (IOException ex)
{
logger.error("Tcp Socket Init Error Error ", ex);
}
}
public boolean isConnected()
{
return connected;
}
protected synchronized Object readObject() throws IOException, ClassNotFoundException
{
Object readObject = null;
//blocks here
logger.trace("{} About to block for read Object");
readObject = this.inputStream.readObject();
logger.trace("{} Read Object from Stream: {} ", "", readObject);
return readObject;
}
public void close()
{
try
{
//todo
this.connected = false;
this.outputStream.flush();
this.outputStream.close();
this.inputStream.close();
synchronized (tcpSocket)
{
this.tcpSocket.close();
}
}
catch (IOException ex)
{
logger.error("Error closing Socket");
}
}
@Override
public void run()
{
this.connected = true;
while (this.connected)
{
try
{
Object readObject = readObject();
if (readObject != null)
{
this.messageProcessor.enqueueReceivedMessage((MessageType) readObject);
}
else
{
logger.error("Read Object is null");
}
}
catch (IOException ex)
{
logger.error("TcpRecieveThread IOException", ex);
}
catch (ClassNotFoundException ex)
{
logger.error("TcpRecieveThread ClassnotFound", ex);
}
}
this.close();
}
}
答案 0 :(得分:2)
简介。这可能会告诉你很多。
是 - 使用Java ObjectIOStreams 序列化和反序列化对象相对来说是CPU密集型的。
您似乎没有在IO管道中使用BufferedInputStream / BufferedOutputStream,因此很可能一次读取和写入一个字节的数据。这可能会大大增加您的CPU使用率。
我说这个线程应该被阻塞,并在调用ReadObject时占用0%的cpu。
我认为你从根本上误解了I / O的一般情况,特别是readObject
的工作原理。当您调用该方法时,它会进行一次(或可能很多次)系统调用以从套接字中获取字节。然后,它解码这些字节以找出需要创建的对象,然后创建并初始化它们。所有这些工作都将占用的CPU时间视为“用户时间”或“系统时间”。 CPU没有计入进程的唯一时间是/ read
系统调用必须等待网络数据包到达。
我也不相信那些“剖析”结果。首先,直接读取代码表示main
方法创建一个新线程,启动它然后立即返回。然而,这些结果似乎在说“主”线程在不断运行。这是荒谬的......并且怀疑您用于分析的方法和/或您向我们解释它们的方式。
还有一件事需要检查。你看过日志文件了吗?是否正确配置了日志记录?
答案 1 :(得分:1)
可能你可以通过这种方式来改进它。
尝试使用自定义writeObject和readObject()
尝试使用Google协议缓冲区
压缩流
序列化对象时,仅为其提供序列化 必需的属性。不要序列化整个对象。所以使用瞬态。