并发队列

并发队列Queue:阻塞队列
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
队列:底层由链表实现;
BlockingQueue:阻塞队列,当要取一个数据时,如果队列中没有,就会一直等待。
当要存一个数据时,如果数据满了,也会一直等待,直到队列有空出来为止。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
方法介绍:put,往队列中添加一个数,如果队列已经满了,就堵塞住;
take 在队列中拿出一个数,如果队列是空的,就堵塞住;
add 往队列中添加一个数,如果队列已经满了,会抛出异常
remove 往队列中移除一个数,如果队列空了,会抛出异常
element 查看队列中第一个数,不移除,如果是空的,抛出异常
offer 往队列中添加一个数,如果队列是满的,返回false
poll 在队列中拿出一个数,并进行移除,如果队列是空的,返回null
peek 查看队列中一个数,如果空,返回为null
下面是BlockingQueue的子类
在这里插入图片描述
在这里插入图片描述
代码分析:

package collections.queue;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class ArrayBlockingQueueDemo {


    public static void main(String[] args) {
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(3);
        Interviewer r1 = new Interviewer(queue);
        Consumer r2 = new Consumer(queue);
        new Thread(r1).start();
        new Thread(r2).start();
    }

}

// 充当生产者
class Interviewer implements Runnable {
    BlockingQueue queue;

    public Interviewer(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        System.out.println("十个候选人都来了");
        for (int i = 0; i < 10; i++) {
            String candidate = "Candidate" + i;
            try {
                queue.put(candidate);
                System.out.println("安排好了" + candidate);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        try {
            queue.put("stop");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

// 充当消费者
class Consumer implements Runnable {
    BlockingQueue<String> queue;

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

    @Override
    public void run() {
        try {
            String msg;
            while (!(msg = queue.take()).equals("stop")) {
                System.out.println(msg + "到了");
                Thread.sleep(1000);
            }
            System.out.println("所有候选人都结束了");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println();
    }
}

结论如下:
在这里插入图片描述
在这里插入图片描述

put方法的源码分析:

在这里插入图片描述
这是BlockingQueue里的put实现方式,但是,我们想看的是ArrayBlockingQueue中的put方法。对此,我们可以使用ctrl + Alt + 鼠标左键 来进行查看;
在这里插入图片描述
在这里插入图片描述
checkNotNull字面理解就是对e的非空检查,如果是空的话,就会报错;
下面加锁,方法是lockInterruptible();说明是可以暂停的
如果队列中已经满了,就等待;
如果没有满,就入队;
通过查询源码
ArrayBlockingQueue队列底层是Object[] ;
LinkedBlockingQueue
点击ctrl + shift + N
在这里插入图片描述

首先看到的Node代表的是它的节点,所以,LinkedBlockingQueue底层是由链表实现的。
然后,我们会发现它有两把锁
在这里插入图片描述
在这里插入图片描述
先获取put锁,如果队列中元素已经满了,就阻塞,如果队列中没满,就去加入,然后进行判断,如果还有空的,就再唤醒一个线程。
在这里插入图片描述
它是无界的,所以,put的时候不会塞满。自己思考:上面的LinkedBlockQueue 会堵塞,因为代码中有体现。而这里的PriorityQueue是不会堵塞的。
在这里插入图片描述
它是直接进行传递的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
其add的代码如下:如果p.casNext是成功的,那么就进行增加。如果失败了,跳回for语句进行二次加入。
在这里插入图片描述
第一:根据需求,有边界的和无边界的,就像LinkedBlockingQueue,和priorityBlockingQueue是无边界的。像ArrayBlockingQueue,SynchronousQueue是有边界的。
第二:空间,像synchronousQueue,都不占空间,ArrayBlockingQueue其内部是Object[]从内存上将,它比较整齐,而LinkedBlockingQueue其底层是由链表实现的,所以,相对来说就会乱一些。
第三:吞吐量,从性能角度来讲,LinkedBlockingQueue的吞吐量一般优于ArrayBlockingQueue,因为它有两把锁。它锁的粒度更加的细致,他有takelock,和putlock两把锁。而ArrayBlockingQueue是一种基础的能适应大多数情况的,稳定的选择。
SynchronousQueue,如果直接交换,而不需要存储,就可以选择这个。
在这里插入图片描述
Concurrent的特点是大部分通过CAS实现,比如说,ConcurrentHashMap,就是通过比较交换的CAS实现的。
CopyOnWrite
的特点是大部分通过赋值一份实现的,
Blocking*的特点所示通过AQS实现的,等会会进行说明
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值