Programación concurrente de Java: la versión de cola de bloqueo del modelo de consumidor productor

Modelo productor consumidor

El modelo productor-consumidor consiste en resolver el problema del fuerte acoplamiento entre productores y consumidores a través de un contenedor . Los productores y los consumidores no se comunican directamente entre sí, sino que se comunican a través de una cola de bloqueo . Por lo tanto, una vez que el productor termina de producir los datos, no espera a que el consumidor los procese y los arroja directamente a la cola de bloqueo. El consumidor no solicita los datos al productor, sino Tomada directamente de la cola de bloqueo, la cola de bloqueo es equivalente a un búfer, que equilibra las capacidades de procesamiento de productores y consumidores. Esta cola de bloqueo se utiliza para desacoplar productores y consumidores .

Edición tradicional

Date cuenta con ReentrantLock.

package mytest;
/**
 * 共享资源类
 */
class ShareData {
    
    
    private int num = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void increment() throws Exception {
    
    
        lock.lock();
        try {
    
    
            //判断
            while (num != 0) {
    
    
                //等待 不生产
                condition.await();
            }
            //干活
            num++;
            System.out.println(Thread.currentThread().getName() + "\t" + num);
            //通知唤醒
            condition.signalAll();
        } finally {
    
    
            lock.unlock();
        }
    }

    public void deIncrement() throws Exception {
    
    
        lock.lock();
        try {
    
    
            //判断
            while (num == 0) {
    
    
                //等待 不生产
                condition.await();
            }
            //干活
            num--;
            System.out.println(Thread.currentThread().getName() + "\t" + num);
            //通知唤醒
            condition.signalAll();
        } finally {
    
    
            lock.unlock();
        }
    }
}
/**
 * Description
 * 一个初始值为0的变量 两个线程交替操作 一个加1 一个减1来5轮
 *
 * @author [email protected]
 * @version 1.0
 * @date 2019-04-13 14:01
 **/
public class ProdConsumerTraditionDemo {
    
    
    public static void main(String[] args) {
    
    
        ShareData shareData = new ShareData();
        new Thread(() -> {
    
    
            for (int i = 1; i <= 5; i++) {
    
    
                try {
    
    
                    shareData.increment();
                } catch (Exception e) {
    
    
                    e.printStackTrace();
                }
            }
        }, "AA").start();
        new Thread(() -> {
    
    
            for (int i = 1; i <= 5; i++) {
    
    
                try {
    
    
                    shareData.deIncrement();
                } catch (Exception e) {
    
    
                    e.printStackTrace();
                }
            }
        }, "BB").start();
    }
}
 

Versión de cola de bloqueo

La cola de bloqueo, como su nombre lo indica, es ante todo una cola, y el papel de una cola de bloqueo en la estructura de datos es aproximadamente como se muestra en la figura:
Inserte la descripción de la imagen aquí
Cuando la cola de bloqueo está vacía, la operación de obtención de elementos de la cola se bloqueará.
Cuando se bloquee. Cuando la cola esté llena, se bloqueará la operación de agregar elementos a la cola.
Del mismo modo
, los subprocesos que intenten agregar una nueva redondez a la cola bloqueada completa también se bloquearán, sabiendo que otros subprocesos eliminan uno o más de la cola Después de que el elemento o todos vacíen la cola, la cola se vuelve a liberar y posteriormente se agrega.

¿Por qué usarlo? ¿Cuál es el beneficio?

En el campo del multiproceso: el llamado bloqueo, en algunos casos se suspenderá el hilo (es decir, bloqueo del hilo), una vez que se cumpla la condición, el hilo suspendido se despertará automáticamente

Por que necesita usar BlockingQueue

La ventaja es que no es necesario que nos preocupemos de cuándo debemos bloquear el hilo y cuándo necesitamos reactivarlo, porque BlockingQueue ya está hecho.

Antes del lanzamiento del paquete concurrente, en un entorno multiproceso, cada uno de nuestros programadores debe controlar estos detalles por sí mismo, especialmente teniendo en cuenta la eficiencia y la seguridad de los subprocesos, y esto traerá mucha complejidad a nuestros programas.

El método principal de BlockingQueue

Hay cuatro formas de insertar elementos en BlockingQueue, cuatro para eliminar y dos para verificar.
Inserte la descripción de la imagen aquí
Acciones de diferentes tipos de métodos.

Tipo de método acción
Lanzar una excepción Cuando la cola de bloqueo está llena, agregar un elemento a la cola arrojará IllegalStateException: Queue full
cuando la cola de bloqueo está vacía, y luego lanzará NoSuchElementException al eliminar elementos de la cola
Valor especial Insertar método, devolver verdadero en caso de éxito, devolver falso en caso de error,
eliminar método, devolver elemento en caso de éxito, devolver nulo si no hay ninguno en la cola
Sigue bloqueando Cuando la cola de bloqueo está llena, el productor continúa colocando elementos en la cola, y la cola se bloqueará hasta que se coloquen datos o salga en respuesta a la interrupción.
Cuando la cola de bloqueo está vacía, el consumidor intenta tomar elementos de la cola y la cola bloqueará el hilo del consumidor hasta que la cola esté disponible. .
Salida del tiempo de espera Cuando la cola de bloqueo está llena, la cola bloqueará el hilo del productor durante un cierto período de tiempo, y el hilo del productor saldrá después de que se exceda el límite de tiempo.

Introducción a la arquitectura

Inserte la descripción de la imagen aquí

Análisis de especies

ArrayBlockingQueue: Una cola de bloqueo limitada compuesta por una estructura de matriz.
LinkedBlockingDeque: Una cola de bloqueo limitada (pero el valor predeterminado de tamaño Entero> MAX_VALUE) compuesta por una estructura de lista vinculada.
PriorityBlockingQueue: una cola de bloqueo ilimitada que admite la clasificación de prioridad.
DelayQueue: Utilice una cola de prioridad La cola de bloqueo ilimitada de retardo implementada.
SynchronousQueue: Una cola de bloqueo que no almacena elementos, es decir, una cola de un solo elemento.
LinkedTransferQueue: Una cola de bloqueo ilimitada compuesta por una estructura de lista vinculada.
LinkedBlockingDeque: Una cola de bloqueo bidireccional compuesta por una estructura de comprensión.

Código

class MyResource {
    
    
    /**
     * 默认开启 进行生产消费的交互
     */
    private volatile boolean flag = true;
    /**
     * 默认值是0
     */
    private AtomicInteger atomicInteger = new AtomicInteger();

    private BlockingQueue<String> blockingQueue = null;

    public MyResource(BlockingQueue<String> blockingQueue) {
    
    
        this.blockingQueue = blockingQueue;
        System.out.println(blockingQueue.getClass().getName());
    }

    public void myProd() throws Exception {
    
    
        String data = null;
        boolean returnValue;
        while (flag) {
    
    
            data = atomicInteger.incrementAndGet() + "";
            returnValue = blockingQueue.offer(data, 2L, TimeUnit.SECONDS);
            if (returnValue) {
    
    
                System.out.println(Thread.currentThread().getName() + "\t 插入队列数据" + data + "成功");
            } else {
    
    
                System.out.println(Thread.currentThread().getName() + "\t 插入队列数据" + data + "失败");
            }
            TimeUnit.SECONDS.sleep(1);
        }
        System.out.println(Thread.currentThread().getName() + "\t 停止 表示 flag" + flag);
    }

    public void myConsumer() throws Exception {
    
    
        String result = null;
        while (flag) {
    
    
            result = blockingQueue.poll(2L, TimeUnit.SECONDS);
            if(null==result||"".equalsIgnoreCase(result)){
    
    
                flag=false;
                System.out.println(Thread.currentThread().getName()+"\t"+"超过2m没有取到 消费退出");
                System.out.println();
                System.out.println();
                return;
            }
            System.out.println(Thread.currentThread().getName() + "消费队列" + result + "成功");

        }
    }
    public void stop() throws Exception{
    
    
        flag=false;
    }
}

/**
 * Description
 * volatile/CAS/atomicInteger/BlockQueue/线程交互/原子引用
 *
 * @author [email protected]
 * @version 1.0
 * @date 2019-04-13 14:02
 **/
public class ProdConsumerBlockQueueDemo {
    
    
    public static void main(String[] args) throws Exception {
    
    
        MyResource myResource = new MyResource(new ArrayBlockingQueue<>(10));
        new Thread(()->{
    
    
            System.out.println(Thread.currentThread().getName()+"\t生产线程启动");
            try {
    
    
                myResource.myProd();
            } catch (Exception e) {
    
    
                e.printStackTrace();
            }
        },"Prod").start();

        new Thread(()->{
    
    
            System.out.println(Thread.currentThread().getName()+"\t消费线程启动");
            try {
    
    
                myResource.myConsumer();
            } catch (Exception e) {
    
    
                e.printStackTrace();
            }
        },"consumer").start();
        try {
    
     TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) {
    
     e.printStackTrace(); }
        System.out.println();
        System.out.println();
        System.out.println();
        System.out.println("时间到,停止活动");
        myResource.stop();
    }
}

Referencia

Modelo de consumidor productor: explicación detallada e implementación de código versión c ++

Supongo que te gusta

Origin blog.csdn.net/e891377/article/details/108731232
Recomendado
Clasificación