较劲大厂面试题一---2021年BAT考核趋势JUC-AQS

简介: 较劲大厂面试题一---2021年BAT考核趋势JUC-AQS

一、Java


1.1 58同城java字符串常量池《深入理解JAVA虚拟机》


20210201140003420.png

运行结果:

58tongcheng  
58tongcheng  
true  
java  
java  
false  

面试解析:

系统初始化JDK自带的java,不是同一个java。

是加载sun.misc.Version这个类的时候进入常量池中的。

202102011408440.png


20210201135754649.png


20210201141704642.png


1.2 字节跳动两数求


1.给定一个数m,求大于该数的最小2的n次密,返回n

2.给定一个数组nums和一个目标值target,请你在数组中找出和为目标值的哪两个整数,并返回数组下标

数组暴力破解:


class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] result = new int[2];   //定义返回结果数组
        for (int i = 0; i < nums.length; i++) {
            for (int j = 0; j < nums.length; j++) {
                if (nums[j] == target - nums[i]) { //用target-nums[i]作为查询条件来判断结果
                    if (i != j) {
                        result[0] = j;
                        result[1] = i;
                        break;
                    }
                }
            }
        }
        return result;  //如果没有返回的是空数组
    }
}

HashMap数据结构解法:

    Map<Integer, Integer> map = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        int complement = target - nums[i];
        if (map.containsKey(complement)) {//满足条件直接返回结果,不继续遍历存数据
            return new int[] { map.get(complement), i };
        }
        map.put(nums[i], i);
    }
    throw new IllegalArgumentException("No two sum solution");
}

二、JUC


2.1 可重入锁【递归锁】


在同一个线程在外层方法获取的锁的时候,在即进入该线程的内层方法会自动获取锁,不会阻塞。

ReentrantLock synchronzied 都是可重入锁【同步锁】。

Synchronzied: 隐式锁 JVM控制 【自动挡】

ReentrantLock: 显示锁Lock ,手动来写 【手动挡】


2021020116545558.png


也是说,同一个线程可以多次获得同一把锁。

ReentrantLock 也是一样的。


2.2 唤醒线程的3种方法


1.Object中的wait() notify()

20210201173321823.png

notify()放于wait 之前无法执行,无法唤醒,程序一直等待下去。


必须成对,先wait再notify


2.JUC包中的Condition的 await() signal()


20210201173918154.png

限制条件和上面如法炮制。

3.LockSupport类park() unpark() 可以阻塞当前线程,以及指定被阻塞的线程

20210201175032736.png

单纯的唤醒和阻塞线程,不需要再锁里面


2.3 LockSupport【wait/notify的改良版park/unpark】


用于创建锁和其他基本线程阻塞原语。

每一个线程都有一个许可证,permit 不是1就是0,可以看成信号量Semaphore,与其不同的是累加的上限为1.

先等待后唤醒 先唤醒后等待 都是可以的。park()形同虚设。


三、AQS【2021年重点】

20210201200051632.png

抽象的队列同步器 ,构建锁,其他同步器组件及整个JUC体系的基石框架。

FIFO队列来完成排对工作,并通过一个int类型表示锁的持有状态。

ReentrantLock

CountDownLantch

ReentrantReadWriteLock

Semaphore

与区别于CAS比较并交换,自旋锁。


20210202094430304.png

3.1 锁与同步器的关系?


锁:面向使用者,定义了程序员与锁交互的应统API,隐藏了实现的细节。

同步器:面向所的实现者,java并发大神DougLee,提出了一种规范并简化了锁的实现,屏蔽了同步状态的管理,阻塞线程排对和通知,唤醒机制等。


20210201192739263.png


AQS = State变量+CLH变种的双端队列

头尾前后指针全部都有

20210202085744970.png

非公平锁为例,银行办理业务的案例,模拟AQS如何进行现成的管理和通知唤醒机制:


20210202093035467.png

public class Demo01 {
    public static void main(String[] args) {
        ReentrantLock lock = new ReentrantLock();
        /**
         * 3 个线程模拟银行网点,受理顾客
         */
        // 第一个顾客办理业务,没有人等待,A直接办理20分钟
        new Thread(()->{
            lock.lock();
            try{
                System.out.println("-----A线程进入-----");
                // 暂停20分钟
                TimeUnit.MINUTES.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        },"A").start();
        // 第二个顾客办理业务,受理的窗口只有一个,B只能等待
        new Thread(()->{
            lock.lock();
            try{
                System.out.println("-----B线程进入-----");
            } finally {
                lock.unlock();
            }
        },"B").start();
        // 第三个顾客办理业务,受理的窗口只有一个,C只能等待
        new Thread(()->{
            lock.lock();
            try{
                System.out.println("-----C线程进入-----");
            } finally {
                lock.unlock();
            }
        },"C").start();
    }
}

1.A线程首先上锁,需要执行的:


20210202092459641.png

2.BC线程抢不到,修改不了Status的状态,抢占失败,准备进行排队,执行acquire()方法,模板方法设计模式,抛出异常,


20210202092720288.png

20210202092936297.png


3.B尝试抢占锁,失败,继续尝试addWaiter()这个方法,准备入队候客区进行补位,


20210202093531629.png


4.新建一个新的节点,并不是当前的节点B,而是一个null,作用就是哨兵节点,进行占位。

20210202093859884.png


此时,就是成了如下的情况:

20210202094117481.png


5.C线程开始准备加入队列,重复B线程的流程,入队执行addWaiter()方法,抢不到,C与B不同的是,有一个哨兵节点和B节点,


20210202093859884.png

20210202095111345.png


6.B开始进行阻塞,此时才真正的被阻塞,完全入队。


20210202101243405.png


7.A线程办完业务,开始走人,执行unLock()方法

20210202102100393.png

h为头指针,-1不为0,开始进行出队操作。unpark()。




20210202102100393.png

20210202102110883.png


开始进行状态变换,1-1=0,设置当前线程占有为null。释放锁,设置状态Status=0。

20210202102141627.png

20210202103753435.png

2021020210392293.png


总结


1.lock方法

2.AQS====调用tryAcquire()---->调用addWaiter()---->调用acquireQueued()方法


20210202095459666.png


image.png

四、Spring

五、Redis

六、JVM


目录
相关文章
|
缓存 NoSQL 算法
会会大厂面试官三-----Redis【5大基本数据类型应用场景】考核趋势
会会大厂面试官三-----Redis【5大基本数据类型应用场景】考核趋势
128 0
会会大厂面试官三-----Redis【5大基本数据类型应用场景】考核趋势
|
缓存 Java Spring
较劲大厂面试题二-----Spring-AOP、循环依赖考核趋势
较劲大厂面试题二-----Spring-AOP、循环依赖考核趋势
117 0
较劲大厂面试题二-----Spring-AOP、循环依赖考核趋势
|
Java
Java面试题答案解析: 基础考核-拆箱装箱, 数据类型, MAP
Java面试题答案解析: 基础考核-拆箱装箱, 数据类型, MAP
119 1
|
Java
Java面试题: 基础考核-拆箱装箱, 数据类型, MAP
Java面试题: 基础考核-拆箱装箱, 数据类型, MAP
104 0
|
3月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
30天前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
59 2
|
1月前
|
JSON 安全 前端开发
第二次面试总结 - 宏汉科技 - Java后端开发
本文是作者对宏汉科技Java后端开发岗位的第二次面试总结,面试结果不理想,主要原因是Java基础知识掌握不牢固,文章详细列出了面试中被问到的技术问题及答案,包括字符串相关函数、抽象类与接口的区别、Java创建线程池的方式、回调函数、函数式接口、反射以及Java中的集合等。
27 0
|
3月前
|
存储 安全 Java
这些年背过的面试题——Java基础及面试题篇
本文是技术人面试系列Java基础及面试题篇,面试中关于Java基础及面试题都需要了解哪些内容?一文带你详细了解,欢迎收藏!
|
3月前
|
XML 存储 JSON
【IO面试题 六】、 除了Java自带的序列化之外,你还了解哪些序列化工具?
除了Java自带的序列化,常见的序列化工具还包括JSON(如jackson、gson、fastjson)、Protobuf、Thrift和Avro,各具特点,适用于不同的应用场景和性能需求。
|
3月前
|
Java
【Java基础面试三十七】、说一说Java的异常机制
这篇文章介绍了Java异常机制的三个主要方面:异常处理(使用try、catch、finally语句)、抛出异常(使用throw和throws关键字)、以及异常跟踪栈(异常传播和程序终止时的栈信息输出)。