第十七讲 BlockingQueue

第十七讲 BlockingQueue

1 阻塞队列

队列:是一种数据结构,先进先出。排队。FIFO
对于普通的队列而言:如果队列空了,还要从队列中移除数据就会抛异常。
这种队列不适合用在高并发场景下。因为高并发场景下,
取数据是一条线程,写数据是另一条线程
取不到数据的时候,也就是队列空了
取线程应该阻塞,等待队列中有数据,一旦有数据,该线程被唤醒。
也就是说,get()不到的时候,应该wait()
一旦另外一条写线程put()成功,notify/notifyAll(),让阻塞的线程醒来去取数据

如果队列满了,写入队列的线程就应该阻塞wait(),等待读线程读取数据,读后通知写线程
进行put操作。

队列这玩意本来效率就差。但是它有序。我们看实现,如果用数组,查询效率高,增删效率差
如果是链表,查效率低,增删效率高。map无序。

2 普通队列线程不安全

public class QueueTest {

    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();

        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                list.push(i);
                /*try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }*/
                System.out.println(Thread.currentThread().getName() + " push" + i);
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + " pop" + list.pop());
            }
        }, "B").start();
    }
}
可能抛出一下异常:
Exception in thread "B" java.util.NoSuchElementException
    
这些线程不安全的队列,在高并发场景下,是不能使用的。
高并发场景下,如果要使用队列,就要使用线程安全的队列。
    方式1:自己写线程安全的队列
    方式2:使用API中线程安全的队列

API中线程安全的队列有哪些?
    首先,我们要去java.util.concurrent下去看,因为这是java并发包
    并发场景下用到的工具基本都在这里。

补充概念:
    Queue:队列。先进先出。单向队列。吃了拉。
    Stack:栈。先进后出。吃了吐。
    Deque:队列。双向队列。上吐下泻。
    Deque和Queue哪个功能更加强大?Deque。
    如果你是SUN公司的java设计者,你会先设计Queue还是先设计Deque?
    先设计强大的,因为复用,所以当要设计Queue的时候,我们可以直接用Deque
    的方法进行适当的改造。(设计思想)
    

3 BlockingQueue

BlockingQueue:接口
1.它的实现类要掌握的主要有三个:
	LinkedBlockingQueue : 链表的方式实现
	ArrayBlockingQueue : 数组的方式实现
	SynchronousQueue : 没有容量,不存储任何元素的阻塞队列。
2.他们实现线程安全的。线程安全涉及到什么?锁!也就是说这个类设计的时候已经考虑了
锁的问题。

3.剖析一下ArrayBlockingQueue
3.1 类结构:实现了BlockingQueue接口,继承AbstractQueue类
3.2 成员属性:
	/** The queued items */
    final Object[] items; 本质上是一个数组
    /** Main lock guarding all access */
    final ReentrantLock lock; // 底层还用到了可重入锁
    /** Condition for waiting takes */
    private final Condition notEmpty;
    // 等待取的条件是不空,队列不空就take,如果空就await()
    /** Condition for waiting puts */
    private final Condition notFull; 
    // 等待存的条件,是不满。如果队列不满,则存入数据。如果满了,则await
    transient Itrs itrs = null;// 这是一个迭代器


take()put()是阻塞。
超时 poll()移除和offer()插入
public class BlockingQueueTest implements Serializable {


    private static final long serialVersionUID = -6267964323673681096L;

    public static void main(String[] args) {
//        BlockingQueue bq = new ArrayBlockingQueue(3);
//        BlockingQueue bq = new LinkedBlockingQueue(3);
        BlockingQueue bq = new SynchronousQueue();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                try {
                    bq.put(i);
                    System.out.println("put 成功" + i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"put").start();

        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    System.out.println(bq.take());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"take").start();
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值