2012-06-07 3 views
1

Я столкнулся с странной проблемой, когда этот поток, который читается из входного потока, в частности, readObject. Поток блокирует вызов, как это предполагается, потому что я попытался поставить заявления на отладку журнала, и он показывает его блокировку. Проблема в том, что этот поток по-прежнему отмечен как работающий в профилировщике, и он занимает 50% от моего использования процессора. У меня есть аналогичный поток, который блокирует правильно и когда блокируется занимает 0% процессора. Я озадачен тем, что здесь может быть не так.Java readObject из Inputstream занимает 50% CPU

Поскольку я новый пользователь, я не могу отправить изображение, пожалуйста, смотрите. Зеленый на изображении означает бег, желтый заблокирован или ждет.

http://i.imgur.com/5FPyZ.png Изображение также немасштабированная 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

одна нота, вы должны переместить 'IoTcpReadRunnable.init()' взывать конструктора и в начале 'пробега)' метода (. – jtahlborn

ответ

2
  1. Профиль. Это, вероятно, многое вам скажет.

  2. Да - сериализация и десериализация объектов с использованием Java ObjectIOStreams относительно интенсивный процессор.

  3. Вы не используете BufferedInputStream/BufferedOutputStream в своих IO-конвейерах, поэтому вполне возможно, что данные считываются и записываются по одному байту за раз. Это, вероятно, значительно увеличит использование вашего процессора.


Я говорю это поток должен быть заблокирован, и принимать до 0% от центрального процессора, когда ReadObject называется.

Я думаю, что вы принципиально не понимаете, как работают I/O вообще и readObject в частности работает. Когда вы вызываете метод, он делает один (или, возможно, многие) системные вызовы для извлечения байтов из сокета. Затем он декодирует эти байты, чтобы выяснить, какие объекты нужно создать, а затем создает и инициализирует их. Вся эта работа требует процессорного времени, которое учитывается для обработки как «пользовательское время» или «системное время». Единственный момент, когда CPU не учитывается в процессе, - это когда/если в режиме ожидания read требуется ждать появления сетевого пакета.

Я также не верю этим результатам «профилирования». Для начала прямое чтение вашего кода говорит о том, что метод main создает новый поток, запускает его и сразу же возвращает. Тем не менее эти результаты, похоже, говорят о том, что «основной» поток работает непрерывно. Это бессмысленно ... и вызывает сомнения в методологии, которую вы используете для профилирования и/или того, как вы их интерпретируете.


Еще одна вещь, чтобы ее проверить. Вы посмотрели файл журнала? Правильно ли настроен журнал?

+0

1. Я сделал, посмотрю снимок экрана. 2. Да, но это другая проблема. Я говорю, что этот поток должен быть заблокирован и занять 0% от процессора при вызове ReadObject. (Я не отправляю никаких данных с сервера) 3. Полезно знать. спасибо – scrubalub

+1

@scrubalub - «профилирование» не означает, какие потоки активны. «Профилирование» означает запуск кода под инструментом, который отслеживает, сколько времени занимает каждый вызов метода, и показывает вам _exactly_, где узкое место. В jvisualvm есть плагин, который может сделать это за вас. – jtahlborn

1

Возможно, вы можете посмотреть этот способ, чтобы улучшить его.

  1. Попробуйте использовать пользовательские writeObject и readObject()

  2. Try Google протокол Буферы

  3. сжимающих поток

  4. При сериализации объекта, обеспечивают сериализации только для искомых attributes.Do не сериализуйте весь объект. Используйте переходный процесс.

Worth смотрит эту дискуссию: Java Object Serialization Performance tips

Смежные вопросы