Pregunta

Tengo el clásico problema de un hilo que empuja eventos a la cola entrante de un segundo hilo. Solo que esta vez, estoy muy interesado en el rendimiento. Lo que quiero lograr es:

  • Quiero acceso concurrente a la cola, el productor empujando, el receptor apareciendo.
  • Cuando la cola está vacía, quiero que el consumidor bloquee la cola, esperando al productor.

Mi primera idea fue usar un LinkedBlockingQueue , pero pronto me di cuenta de que no es concurrente y el rendimiento se vio afectado. Por otro lado, ahora uso un ConcurrentLinkedQueue , pero sigo pagando el costo de wait () / notify () en cada publicación . Como el consumidor, al encontrar una cola vacía, no se bloquea, tengo que sincronizar y wait () en un candado. Por otro lado, el productor debe obtener ese bloqueo y notify () en cada publicación. El resultado general es que estoy pagando el costo de sycnhronized (lock) {lock.notify ()} en cada publicación, incluso cuando no es necesario.

Lo que supongo que se necesita aquí, es una cola que sea bloqueadora y concurrente. Me imagino que una operación push () funciona como en ConcurrentLinkedQueue , con un notify () adicional al objeto cuando el elemento empujado es el primero en la lista. Tal verificación considero que ya existe en el ConcurrentLinkedQueue , ya que empujar requiere conectarse con el siguiente elemento. Por lo tanto, esto sería mucho más rápido que la sincronización cada vez en el bloqueo externo.

¿Hay algo como esto disponible / razonable?

¿Fue útil?

Solución

Creo que puede apegarse a java.util.concurrent.LinkedBlockingQueue independientemente de sus dudas. Es concurrente. Sin embargo, no tengo idea de su rendimiento. Probablemente, otra implementación de BlockingQueue le convenga mejor. No hay demasiados, así que realice pruebas de rendimiento y mida.

Otros consejos

Similar a esta respuesta https://stackoverflow.com/a/1212515/1102730 pero un poco diferente .. Terminé usando un ExecutorService . Puede crear una instancia usando Executors.newSingleThreadExecutor () . Necesitaba una cola simultánea para leer / escribir imágenes almacenadas en los archivos, así como la atomicidad con lecturas y escrituras. Solo necesito un solo subproceso porque el archivo IO es un orden de magnitud más rápido que el origen, IO neto. Además, estaba más preocupado por la atomicidad de las acciones y la corrección que el rendimiento, pero este enfoque también se puede hacer con múltiples hilos en el grupo para acelerar las cosas.

Para obtener una imagen (Try-Catch-Finalmente se omite):

Future<BufferedImage> futureImage = executorService.submit(new Callable<BufferedImage>() {
    @Override
        public BufferedImage call() throws Exception {
            ImageInputStream is = new FileImageInputStream(file);
            return  ImageIO.read(is);
        }
    })

image = futureImage.get();

Para guardar una imagen (Try-Catch-Finalmente se omite):

Future<Boolean> futureWrite = executorService.submit(new Callable<Boolean>() {
    @Override
    public Boolean call() {
        FileOutputStream os = new FileOutputStream(file); 
        return ImageIO.write(image, getFileFormat(), os);  
    }
});

boolean wasWritten = futureWrite.get();

Es importante tener en cuenta que debe limpiar y cerrar sus transmisiones en un bloque finalmente. No sé cómo funciona en comparación con otras soluciones, pero es bastante versátil.

Sugeriría que mire ThreadPoolExecutor newSingleThreadExecutor. Se encargará de mantener sus tareas ordenadas para usted, y si envía Callables a su ejecutor, también podrá obtener el comportamiento de bloqueo que está buscando.

Puede probar LinkedTransferQueue desde jsr166: http : //gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166y/

Cumple sus requisitos y tiene menos gastos generales para las operaciones de oferta / encuesta. Como puedo ver en el código, cuando la cola no está vacía, utiliza operaciones atómicas para los elementos de sondeo. Y cuando la cola está vacía, gira durante un tiempo y estaciona el hilo si no tiene éxito. Creo que puede ayudar en su caso.

Uso el ArrayBlockingQueue siempre que necesito pasar datos de un hilo a otro. Usando los métodos de poner y tomar (que bloqueará si está lleno / vacío).

Aquí hay un lista de clases que implementan BlockingQueue .

Recomendaría revisar SynchronousQueue .

Como @Rorick mencionó en su comentario, creo que todas esas implementaciones son concurrentes. Creo que sus inquietudes con LinkedBlockingQueue pueden estar fuera de lugar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top