阿里P9整理Java 高频面试题聊一聊 JUC 下的 Linke

2022-09-14  本文已影响0人  分布式与微服务

本文聊一下 JUC 下的 LinkedBlockingQueue 队列,先说说 LinkedBlockingQueue 队列的特点,然后再从源码的角度聊一聊 LinkedBlockingQueue 的主要实现~

LinkedBlockingQueue 有以下特点:

LinkedBlockingQueue 队列继承了 AbstractQueue 类,实现了 BlockingQueue 接口,LinkedBlockingQueue 主要有以下接口:

//将指定的元素插入到此队列的尾部(如果立即可行且不会超过该队列的容量)//在成功时返回 true,如果此队列已满,则抛IllegalStateException。 boolean add(E e); //将指定的元素插入到此队列的尾部(如果立即可行且不会超过该队列的容量) // 将指定的元素插入此队列的尾部,如果该队列已满, //则在到达指定的等待时间之前等待可用的空间,该方法可中断 boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException; //将指定的元素插入此队列的尾部,如果该队列已满,则一直等到(阻塞)。 void put(E e) throws InterruptedException; //获取并移除此队列的头部,如果没有元素则等待(阻塞), //直到有元素将唤醒等待线程执行该操作 E take() throws InterruptedException; //获取并移除此队列的头,如果此队列为空,则返回 null。 E poll();//获取并移除此队列的头部,在指定的等待时间前一直等到获取元素, //超过时间方法将结束E poll(long timeout, TimeUnit unit) throws InterruptedException; //从此队列中移除指定元素的单个实例(如果存在)。 boolean remove(Object o); //获取但不移除此队列的头元素,没有则跑异常NoSuchElementException E element(); //获取但不移除此队列的头;如果此队列为空,则返回 null。 E peek(); 

LinkedBlockingQueue 队列的读写方法非常的多,但是常用的是 put()、take()方法,因为它们两是阻塞的,所以我们就从源码的角度来聊一聊 LinkedBlockingQueue 队列中这两个方法的实现。

先来看看 put()方法,源码如下:

public void put(E e) throws InterruptedException {    if (e == null) throw new NullPointerException();    // 预先设置 c 的值为 -1,表示失败    int c = -1;    Node<E> node = new Node<E>(e);    // 获取写锁    final ReentrantLock putLock = this.putLock;    // 获取当前队列的大小    final AtomicInteger count = this.count;    // 设置可中断锁    putLock.lockInterruptibly();    try {        // 队列满了        // 当前线程阻塞,等待其他线程的唤醒(其他线程 take 成功后就会唤醒此处线程)        while (count.get() == capacity) {            // 无限期等待            notFull.await();        }        // 新增到队列尾部        enqueue(node);        // 获取当前的队列数        c = count.getAndIncrement();        // 如果队列未满,尝试唤醒一个put的等待线程        if (c + 1 < capacity)            notFull.signal();    } finally {        // 释放锁        putLock.unlock();    }    if (c == 0)        signalNotEmpty();}

put()方法的源码并不难,非常容易就看懂,put()方法的过程大概如下:

其他的新增方法,例如 offer,可以查看源码,跟put() 方法大同小异,相差不大~

再来看看 take()方法,源码如下:

public E take() throws InterruptedException {    E x;    // 默认负数    int c = -1;    // 当前链表的个数    final AtomicInteger count = this.count;    //获取读锁    final ReentrantLock takeLock = this.takeLock;    takeLock.lockInterruptibly();    try {        // 当队列为空时,阻塞,等待其他线程唤醒         while (count.get() == 0) {            notEmpty.await();        }        // 从队列的头部拿出一个元素        x = dequeue();        //减一操作,C比真实的队列数据大一        c = count.getAndDecrement();        // c 大于 0 ,表示队列有值,可以唤醒之前被阻塞的读线程        if (c > 1)            notEmpty.signal();    } finally {        // 释放锁        takeLock.unlock();    }    // 队列未满,可以唤醒 put 等待线程~    if (c == capacity)        signalNotFull();    return x;}

take()方法跟 put() 方法类似,是一个相反的操作,我就不做过多的说明了~

以上就是 LinkedBlockingQueue 队列的简单源码解析,希望对你的面试或者工作有所帮助,感谢你的阅读~

最后,再附上我历时三个月总结的 Java 面试 + Java 后端技术学习指南,这是本人这几年及春招的总结,目前,已经拿到了大厂offer,拿去不谢!

如何拿下阿里等大厂的offer的呢,今天分享一个秘密武器,资深架构师整理的350页java开发面试真题和开发必备面试题详解(技术+人事),面试时面试官必问的知识点,篇章包括了很多知识点,其中包括了有基础知识、Java集合、JVM、多线程并发、spring原理、微服务、Netty 与RPC 、Kafka、日记、设计模式、Java算法、数据库、Zookeeper、分布式缓存、数据结构等等。

由于整个文档比较全面,内容比较多,篇幅的限制,文章中分享没有全部附上详细的解析需要可以三连支持一下

JAVA面试题手册

一性能优化面试专栏

二微服务架构面试专栏

三并发编程高级面试专栏

四、开源框架面试题专栏

五、分布式面试专栏

java开发必备面试题详解(技术+人事)

数据结构和算法


jvm

Java核心基础

多线程/高并发

集合框架

IO流

数据库

javaWEB

企业级框架

Linux

软件工程与设计模式

人事问题

说明,为了节省大家的时间和提高学习效率,一些过时知识点和被笔试概率极低的题目不再被收录和分析。

回答问题的思路:先正面叙述一些基本的核心知识,然后描述一些特殊的东西,最后再来一些锦上添花的东西。要注意有些不是锦上添花,而是画蛇添足的东西,不要随便写上。把答题像写书一样写。我要回答一个新技术的问题大概思路和步骤是:我们想干什么,怎么干,干的过程中遇到了什么问题,现在用什么方式来解决。其实我们讲课也是这样一个思路。

上一篇下一篇

猜你喜欢

热点阅读