阻塞队列的学习

1:阻塞队列首先是一个队列,有先进先出,后进后出的原则
2:阻塞队列非常符合生产者消费者模式,生产者将生产的物品放入阻塞队列,如果阻塞队列满了就放 不进去,生产者的线程就会阻塞等待,消费者从阻塞队列中取出,如果没有数据的话也会进入阻塞状 态,进入等待;
3:如果没有阻塞队列的话,可能多个生产者线程不断的生产,但是消费者并没有去消费,就浪费了资源,也可能消费者一直去消费,但是没有东西消费;

阻塞队列的继承结构如下
阻塞队列继承结构
主要有俩个实现类
ArrayBlockingQueue: 底层是数组,有界的,可以在创建的时候指定阻塞队列的大小
LinkedBlockingQueue: 底层是链表,无界.但不是真正的无界,最大为int的最大值

先上代码

/**
 * 生产者类
 */
public class Cooker implements Runnable {

    private ArrayBlockingQueue<String> arrayBlockingQueue;

    public Cooker(ArrayBlockingQueue<String> arrayBlockingQueue) {
        this.arrayBlockingQueue = arrayBlockingQueue;
    }

    public Cooker() {
    }

    @Override
    public void run() {
        while (true) {
            try {
                arrayBlockingQueue.put("生产的物品");
                System.out.println("生产的物品放入阻塞队列-------");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


/**
 * 消费者类
 */
public class Consumer implements Runnable {
    private ArrayBlockingQueue<String> arrayBlockingQueue;

    public Consumer(ArrayBlockingQueue<String> arrayBlockingQueue) {
        this.arrayBlockingQueue = arrayBlockingQueue;
    }

    public Consumer() {
    }


    @Override
    public void run() {
        while (true) {
            try {
                String take = arrayBlockingQueue.take();
                Thread.sleep(5000);
                System.out.println("消费者正在消费---------");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class TestDemo {
    public static void main(String[] args) {
    	// 指定一个大小为1的阻塞队列
        ArrayBlockingQueue<String> bd = new ArrayBlockingQueue<>(1);

        Consumer consumer = new Consumer(bd);
        Cooker cooker = new Cooker(bd);
        Thread c = new Thread(cooker);
        Thread f = new Thread(consumer);

        f.start();
        c.start();
    }
}

运行结果
运行结果
这里就可以看到生产者生产一次,消费者就消费一次

BlockingQueue中的核心方法

//将给定元素设置到队列中,如果设置成功返回true, 否则抛出异常。如果是往限定了长度的队列中设置值,推荐使用offer()方法。
    boolean add(E e);

    //将给定的元素设置到队列中,如果设置成功返回true, 否则返回false. e的值不能为空,否则抛出空指针异常。
    boolean offer(E e);

    //将元素设置到队列中,如果队列中没有多余的空间,该方法会一直阻塞,直到队列中有多余的空间。
    void put(E e) throws InterruptedException;

    //将给定元素在给定的时间内设置到队列中,如果设置成功返回true, 否则返回false.
    boolean offer(E e, long timeout, TimeUnit unit)
        throws InterruptedException;

    //从队列中获取值,如果队列中没有值,线程会一直阻塞,直到队列中有值,并且该方法取得了该值。
    E take() throws InterruptedException;

    //在给定的时间里,从队列中获取值,如果没有取到会抛出异常。
    E poll(long timeout, TimeUnit unit)
        throws InterruptedException;

    //获取队列中剩余的空间。
    int remainingCapacity();

    //从队列中移除指定的值。
    boolean remove(Object o);

    //判断队列中是否拥有该值。
    public boolean contains(Object o);

    //将队列中值,全部移除,并发设置到给定的集合中。
    int drainTo(Collection<? super E> c);

    //指定最多数量限制将队列中值,全部移除,并发设置到给定的集合中。
    int drainTo(Collection<? super E> c, int maxElements);
}

阻塞队列实际上是使用了Condition来模拟线程间协作。 
Condition是用来替代传统的Object的wait()、notify()实现线程间的协作,相比使用Object的wait()、notify(),使用Condition的await()、signal()这种方式更加安全和高效。

这是ArrayBlockingQueue的关于put和take方法的小部分源码源码

 private final Condition notEmpty;
 private final Condition notFull;
 
 public void put(E e) throws InterruptedException {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == items.length)
                notFull.await();
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }

public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == 0)
                notEmpty.await();
            return dequeue();
        } finally {
            lock.unlock();
        }
    }

如果需要了解的更深入,就继续学习这个大佬的文章
北极猩球Java 阻塞队列–BlockingQueue

越学越觉得自己越无知,如果有错误,请指出,谢谢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值