生产者消费者模式

142 阅读2分钟

BlockingQueue(阻塞队列)是java中常见的容器,在多线程编程中被广泛使用。 当队列容器已满时生产者线程被阻塞,直到队列未满后才可以继续put; 当队列容器为空时,消费者线程被阻塞,直至队列非空时才可以继续take。

阻塞队列,顾名思义就是线程使用队列时会阻塞当前线程;BlockingQueue 继承了Collection,具有一般集合所具有的数据存取功能;是线程安全的队列,多线程访问时不会出现同一个数据集中的数据被多次取出,或者覆盖存放的事件。使用场景,可用于一个快速反馈的消息队列,无消息时阻塞线程让出CPU,有数据存入时通知线程取出数据,取完后继续阻塞。

内部通过ReentrantLock实现。 ReentrantLock,通常翻译为再入锁,是 Java 5 提供的锁实现,它的语义和 synchronized 基本相同。再入锁通过代码直接调用 lock() 方法获取,代码书写也更加灵活。与此同时,ReentrantLock 提供了很多实用的方法,能够实现很多 synchronized 无法做到的细节控制,比如可以控制 fairness,也就是公平性,或者利用定义条件等。但是,编码中也需要注意,必须要明确调用 unlock() 方法释放,不然就会一直持有该锁。

package interviews.patterns;

public class Task {
    public String id;
    public Task(String name){
        this.id = name;
    }
}
package interviews.patterns;

import java.util.concurrent.BlockingQueue;

public class Consumer implements Runnable{
    private BlockingQueue<Task> blockingQueue;

    public Consumer(BlockingQueue<Task> queue){
        this.blockingQueue = queue;
    }

    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(200);
                Task task = blockingQueue.take();
                System.out.println("consumer get one task " + task.id);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}
package interviews.patterns;

import java.util.UUID;
import java.util.concurrent.BlockingQueue;

public class Producer implements Runnable {
    BlockingQueue<Task> blockingQueue;

    public Producer(BlockingQueue<Task> queue) {
        this.blockingQueue = queue;

    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(200);
                if(blockingQueue.remainingCapacity() > 0) {
                    Task task = new Task(UUID.randomUUID().toString());
                    blockingQueue.add(task);
                    System.out.println("producer add a new task = " + task.id);
                }else{
                    System.out.println("producer is full");
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

public class Test {
    public static void test(){
        BlockingQueue<Task> blockingQueue = new ArrayBlockingQueue<Task>(10);
        Thread producerThread = new Thread( new Producer(blockingQueue));
        Thread consumerThread = new Thread( new Consumer(blockingQueue));
        producerThread.start();
        consumerThread.start();
    }
}