1

我遇到了一个奇怪的问题,这个线程从输入流中读取,特别是 readObject。线程正在阻塞调用,就像假设的那样,因为我尝试放置日志调试语句并且它显示了它的阻塞。问题是这个线程仍然被标记为在分析器中运行,它占用了我 50% 的 cpu 使用率。我有一个与此类似的线程,它可以正确阻塞,阻塞时占用 0% cpu。我对这里可能出现的问题感到困惑。

由于我是新用户,我无法发布图片,请参阅。图中绿色表示运行,黄色表示阻塞或等待。

http://i.imgur.com/5FPyZ.png此处 还提供未缩放的图像:

主要的

  {
    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 可运行

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();

}
}
4

2 回答 2

2
  1. 剖析它。这可能会告诉你很多。

  2. 是的 - 使用 Java ObjectIOStreams 序列化和反序列化对象相对 CPU 密集型的。

  3. 您似乎没有在 IO 管道中使用 BufferedInputStream / BufferedOutputStream ,因此很有可能一次读取和写入一个字节的数据。这可能会显着增加您的 CPU 使用率。


我是说这个线程应该被阻塞并在调用 ReadObject 时占用 0% 的 cpu。

我认为您从根本上误解了 I/O 的一般readObject工作方式,特别是工作方式。当您调用该方法时,它会进行一次(或可能多次)系统调用以从套接字中获取字节。然后,它解码这些字节以确定需要创建哪些对象,然后创建并初始化它们。所有这些工作都占用了被视为“用户时间”或“系统时间”处理的 CPU 时间。CPU 不计入进程的唯一时间是/如果read系统调用必须等待网络数据包到达。

我也不相信那些“分析”结果。首先,直接阅读您的代码表明该main方法创建了一个新线程,启动它,然后立即返回。然而,这些结果似乎表明“主”线程正在连续运行。那是荒谬的......并且让人怀疑您用来进行分析的方法和/或您向我们解释它们的方式。


还有一件事要检查。你看过日志文件吗?日志记录是否正确配置?

于 2012-06-07T03:36:12.180 回答
1

也许你可以看看这种方式来改进它。

  1. 尝试使用自定义 writeObject 和 readObject()

  2. 试用 Google 协议缓冲区

  3. 压缩流

  4. 当你序列化一个对象时,只为需要的属性提供序列化。不要序列化整个对象。所以使用瞬态。

值得一看的讨论: Java 对象序列化性能提示

于 2012-06-07T04:25:59.027 回答