El problema fue que cuando algo se escribe en el PipedWriter, no notifica automáticamente el PipedReader que hay algunos datos a leer. Cuando uno intenta leer PipedReader y el búfer está vacío, el PipedReader hará un bucle y esperará usando una llamada wait(1000)
hasta que el búfer tenga algunos datos.
La solución es llamar al PipedWriter.flush()
siempre después de escribir algo en la tubería. Todo lo que hace la descarga es llamar al notifyAll()
en el lector. La solución al código en la pregunta looks like this.
(Para mí, la implementación PipedReader/PipedWriter se parece mucho a un caso de optimización prematura, ¿por qué no notificar todo en cada escritura? También los lectores esperan en un bucle activo, despertando cada segundo, en lugar de despertarse solo cuando es algo para leer. El código también contiene algunos comentarios pendientes, que la detección de hilos del lector/escritor que no es lo suficientemente sofisticada)
Este mismo problema parece estar también en PipedOutputStream. En mi proyecto actual, llamar al flush()
manualmente no es posible (no puedo modificar Commons IO's IOUtils.copy()), así que lo solucioné creando low-latency wrappers para las clases de tuberías. Funcionan mucho mejor que las clases originales. :-)
Esto puede no ser lo que quieres, pero ¿podría tu hilo de escritura notificar el hilo de lectura después de haber escrito algo? Y el hilo de lectura seguirá leyendo mientras 'ready()' es verdadero, y luego dormirá cuando no lo esté? – Phil
¿Podría mostrarnos su código, por favor?La 'espera (1000)' no debería ser el problema, porque el escritor notifica al lector cuando algo está escrito. El lector se escapa de su espera(). – tangens
Gracias, Phil. Ahora mismo no estoy en casa, así que no puedo probarlo, pero basado en el código fuente PipedWriter.flush() parece notificar a los lectores. Lo intentaré más tarde hoy. –