El consumidor no funciona en mi código simple de productor / consumidor / cola en Java

Estoy tratando de implementar un sistema simple de productor / consumidor en Java 11. Básicamente, tomo dos hilos para cada uno, más una cola global, simplemente de la siguiente manera:

  • Una cola de prioridad global.
  • El primer subproceso, productor, ejecuta un servidor HTTP, escucha los mensajes http entrantes y, al recibir un mensaje, pusheslo hace como un trabajo en la cola ( queue.sizeincrementos)
  • El segundo hilo, el consumidor, continuamente peeksla cola. Si hay un trabajo ( job ! = null), envía una solicitud HTTP en algún lugar y, una vez recibida con éxito, la sondea desde la cola ( queue.size()decrementos).

El esqueleto es el siguiente:

Clase principal:

public class Manager
{
    private Consumer consumer;
    private Producer producer;
    Queue queue;

    public static void main (String args[])
    {
        consumer = new Consumer();
        producer = new Producer();
    }
} 

Clase de productor:

public class Producer implements Runnable
{
    public Producer()
    {
        Thread producer = new Thread(this);
        producer.start();
    }

    public void run()
    {
            //HTTP server starts, listens, and adds to the queue upon receiving a Job
            server.start();
            Manager.queue.add(new Job());
    }
}

Clase de consumidor:

public class Consumer implements Runnable
{
    public Consumer()
    {
        Thread consumer = new Thread(this);
        consumer.start();
    }

    public void run()
    {
    // Thread.sleep(1);

        while(true)
        {
            //get an object off the queue
            Job job= Manager.queue.peek();
            //do some stuff with the object
        }
    }
}

Producery funciona, queuetodo bien. Pero el problema es con el Consumer. El código del consumidor anterior (con while(true)bucle) no mira el artículo. Pero cuando agrego un bucle Thread.sleep(x)antes while(true), incluso si x=1 msfunciona, y toma el elemento con éxito.

¿Cuál es el problema? ¡Teóricamente, el while(true)bucle no debería ser un problema! ¿Por qué no puede ver y peekel artículo?

Respuesta 1

La causa del problema: lectura y escritura no sincronizadas desde y hacia una cola.

Lo que sucede aquí es que ambos subprocesos, que se ejecutan en diferentes núcleos de CPU, funcionan con su propia copia de la cola, por lo que el productor podría estar agregando cosas y estos cambios probablemente incluso se propaguen a la RAM, pero el consumidor nunca comprueba nada en la RAM, Como tiene su propia copia en caché de esa cola, la bruja permanece vacía.

La Thread.sleep()cosa funciona, porque al despertar, el hilo tiene que obtener todas sus cosas de la RAM, donde probablemente cambió.

La forma correcta de hacerlo es solo acceder a la Cola, cuando se sincroniza de la siguiente manera:

En productor:

synchronized(Manager.queue) {
     Manager.queue.add(new Job());
}

y en consumidor:

boolean continue = true;
while (continue) {
    synchronized(Manager.queue) {
        Job job=Manager.queue.pop();
    }
}

Y como toque final: todo while (true)es increíblemente ineficiente, podrías hacer algo usando Object.wait()yObject.notify()

En productor:

synchronized(Manager.queue) {
     Manager.queue.add(new Job());
     Manager.queue.notify();
}

y en consumidor:

boolean continue = true;
while (continue) {
    synchronized(Manager.queue) {
        while (Manager.queue.peek() == null) {
            Manager.queue.wait();
        }
        Job job=Manager.queue.pop();
    }
}
Respuesta: 2

Encontré un código que reconoce círculos en una imagen en particular y pude convertir el 90% de ese código en javacv. Pero desafortunadamente no pude convertir las siguientes líneas en javacv ...

Título confuso, pero todo lo que quiero saber es cómo divido una larga línea de palabras, o en este caso números. Estoy anotando los códigos postales de un pueblo / ciudad que escribe un usuario. Algunos pueblos / ciudades tienen un ...

He estado investigando durante días para descubrir cómo resolver esto sin suerte. La clase PlayN JavaSound usa la clase javax.sound.sampled.AudioSystem para reproducir sonidos, y el formato mp3 no ...

Tenía un montón de vistas de tabla que tenían código duplicado en ellas. Solían heredar directamente la clase AbstractView. Entonces les hice heredar AbstractListView (que a su vez heredaría de ...