#美团#Java面试题:集合高频要点问题你能答上来吗?( 四 )


4. ArrayBlockingQueue 与 LinkedBlockingQueue 的区别 , 哪个性能好呢?
ArrayBlockingQueue 是有界队列 。 LinkedBlockingQueue 看构造方法区分 , 默认构造方法最大值是 2^31-1 。 但是当 take 和 put 操作时 , ArrayBlockingQueue 速度要快于 LinkedBlockingQueue 。
ArrayBlockingQueue 中的锁是没有分离的 , 即生产和消费用的是同一个锁 。 LinkedBlockingQueue 中的锁是分离的 , 即生产用的是 putLock , 消费是 takeLock;ArrayBlockingQueue 基于数组 , 在生产和消费的时候 , 是直接将枚举对象插入或移除的 , 不会产生或销毁任何额外的对象实例;LinkedBlockingQueue 基于链表 , 在生产和消费的时候 , 需要把枚举对象转换为 Node 进行插入或移除 , 会生成一个额外的 Node 对象 , 这在长时间内需要高效并发地处理大批量数据的系统中 , 其对于 GC 的影响还是存在一定的区别 。
LinkedBlockingQueue 的消耗是 ArrayBlockingQueue 消耗的 10 倍左右 , 即 LinkedBlockingQueue 消耗在 1500 毫秒左右 , 而 ArrayBlockingQueue 只需 150 毫秒左右 。
按照实现原理来分析 , ArrayBlockingQueue 完全可以采用分离锁 , 从而实现生产者和消费者操作的完全并行运行 。 Doug Lea 之所以没这样去做 , 也许是因为 ArrayBlockingQueue 的数据写入和获取操作已经足够轻巧 , 以至于引入独立的锁机制 , 除了给代码带来额外的复杂性外 , 其在性能上完全占不到任何便宜 。
在使用 LinkedBlockingQueue 时 , 若用默认大小且当生产速度大于消费速度时候 , 有可能会内存溢出 。
在使用 ArrayBlockingQueue 和 LinkedBlockingQueue 分别对 1000000 个简单字符做入队操作时 , 我们测试的是 ArrayBlockingQueue 会比 LinkedBlockingQueue 性能好好差不多 50% 起步 。
5. BlockingQueue 的问题以及 ConcurrentLinkedQueue 的问题?
BlockingQueue 可以是限定容量的 。
BlockingQueue 实现主要用于生产者-使用者队列 , 但它另外还支持 collection 接口 。
BlockingQueue 实现是线程安全的 。
BlockingQueue 是阻塞队列(看你使用的方法) , ConcurrentLinkedQueue 是非阻塞队列 。
LinkedBlockingQueue 是一个线程安全的阻塞队列 , 基于链表实现 , 一般用于生产者与消费者模型的开发中 。 采用锁机制来实现多线程同步 , 提供了一个构造方法用来指定队列的大小 , 如果不指定大小 , 队列采用默认大小(Integer.MAX_VALUE , 即整型最大值) 。
ConcurrentLinkedQueue 是一个线程安全的非阻塞队列 , 基于链表实现 。 java 并没有提供构造方法来指定队列的大小 , 因此它是无界的 。 为了提高并发量 , 它通过使用更细的锁机制 , 使得在多线程环境中只对部分数据进行锁定 , 从而提高运行效率 。 他并没有阻塞方法 , take 和 put 方法 , 注意这一点 。
6. 简要概述 BlockingQueue 常用的七个实现类?
ArrayBlockingQueue 构造函数必须传入指定大小 , 所以他是一个有界队列 。
LinkedBlockingQueue 分为两种情况 , 第一种构造函数指定大小 , 它是一个有界队列 , 第二种情况不指定大小他可以称之为无界队列 , 队列最大值为 Integer.MAX_VALUE 。
PriorityBlockingQueue(还有一个双向的 LinkedBlockingDeque)它是一个无界队列 , 不管你使用什么构造函数 。 一个内部由优先级支持的、基于时间的调度队列 。 队列中存放 Delayed 元素 , 只有在延迟期满后才能从队列中提取元素 。 当一个元素的 getDelay() 方法返回值小于等于 0 时才能从队列中 poll 中元素 , 否则 poll() 方法会返回 null 。
SynchronousQueue 这个队列类似于 Golang的channel , 也就是 chan , 跟无缓冲区的 chan 很相似 。 比如 take 和 put 操作就跟 chan 一模一样 。 但是区别在于他的 poll 和 offer 操作可以设置等待时间 。


推荐阅读