Java面试题总结(乱序版,来自大厂面试官的MySQL灵魂十连问

  • Synchronized是java语言的关键字,是原生语法层面的互斥,需要JVM实现;ReentrantLock 是JDK1.5之后提供的API层面的互斥锁,需要lock和unlock()方法配合try/finally代码块来完成。

  • Synchronized使用较ReentrantLock 便利一些;

  • 锁的细粒度和灵活性:ReentrantLock强于Synchronized;

3、性能区别

Synchronized引入偏向锁,自旋锁之后,两者的性能差不多,在这种情况下,官方建议使用Synchronized。

(1)Synchronized

Synchronized会在同步块的前后分别形成monitorenter和monitorexit两个字节码指令。

在执行monitorenter指令时,首先要尝试获取对象锁。如果这个对象没被锁定,或者当前线程已经拥有了那个对象锁,把锁的计数器+1,相应的执行monitorexit时,计数器-1,当计数器为0时,锁就会被释放。如果获取锁失败,当前线程就要阻塞,知道对象锁被另一个线程释放为止。

(2)ReentrantLock

ReentrantLock是java.util.concurrent包下提供的一套互斥锁,相比Synchronized,ReentrantLock类提供了一些高级功能,主要有如下三项:

  1. 等待可中断,持有锁的线程长期不释放的时候,正在等待的线程可以选择放弃等待,这相当于Synchronized避免出现死锁的情况。通过lock.lockInterruptibly()来实现这一机制;

  2. 公平锁,多个线程等待同一个锁时,必须按照申请锁的时间顺序获得锁,Synchronized锁是非公平锁;ReentrantLock默认也是非公平锁,可以通过参数true设为公平锁,但公平锁表现的性能不是很好;

  3. 锁绑定多个条件,一个ReentrantLock对象可以同时绑定多个对象。ReentrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像Synchronized要么随机唤醒一个线程,要么唤醒全部线程。

五、ReentrantLock 是如何实现可重入性的?


1、什么是可重入性

一个线程持有锁时,当其他线程尝试获取该锁时,会被阻塞;而这个线程尝试获取自己持有锁时,如果成功说明该锁是可重入的,反之则不可重入。

2、synchronized是如何实现可重入性

synchronized关键字经过编译后,会在同步块的前后分别形成monitorenter和monitorexit两个字节码指令。每个锁对象内部维护一个计数器,该计数器初始值为0,表示任何线程都可以获取该锁并执行相应的方法。根据虚拟机规范要求,在执行monitorenter指令时,首先要尝试获取对象的锁,如果这个对象没有被锁定,或者当前线程已经拥有了对象的锁,把锁的计数器+1,相应的在执行monitorexit指令后锁计数器-1,当计数器为0时,锁就被释放。如果获取对象锁失败,那当前线程就要阻塞等待,直到对象锁被另一个线程释放为止。

3、ReentrantLock如何实现可重入性

ReentrantLock使用内部类Sync来管理锁,所以真正的获取锁是由Sync的实现类控制的。Sync有两个实现,分别为NonfairSync(非公公平锁)和FairSync(公平锁)。Sync通过继承AQS实现,在AQS中维护了一个private volatile int state来计算重入次数,避免频繁的持有释放操作带来的线程问题。

4、ReentrantLock代码实例


// Sync继承于AQS

abstract static class Sync extends AbstractQueuedSynchronizer {

  ...

}

// ReentrantLock默认是非公平锁

public ReentrantLock() {

        sync = new NonfairSync();

 }

// 可以通过向构造方法中传true来实现公平锁

public ReentrantLock(boolean fair) {

    sync = fair ? new FairSync() : new NonfairSync();

}

protected final boolean tryAcquire(int acquires) {

    // 当前想要获取锁的线程

    final Thread current = Thread.currentThread();

    // 当前锁的状态

    int c = getState();

    // state == 0 此时此刻没有线程持有锁

    if (c == 0) {

        // 虽然此时此刻锁是可以用的,但是这是公平锁,既然是公平,就得讲究先来后到,

        // 看看有没有别人在队列中等了半天了

        if (!hasQueuedPredecessors() &&

            // 如果没有线程在等待,那就用CAS尝试一下,成功了就获取到锁了,

            // 不成功的话,只能说明一个问题,就在刚刚几乎同一时刻有个线程抢先了 =_=

            // 因为刚刚还没人的,我判断过了

            compareAndSetState(0, acquires)) {



            // 到这里就是获取到锁了,标记一下,告诉大家,现在是我占用了锁

            setExclusiveOwnerThread(current);

            return true;

        }

    }

      // 会进入这个else if分支,说明是重入了,需要操作:state=state+1

    // 这里不存在并发问题

    else if (current == getExclusiveOwnerThread()) {

        int nextc = c + acquires;

        if (nextc < 0)

            throw new Error("Maximum lock count exceeded");

        setState(nextc);

        return true;

    }

    // 如果到这里,说明前面的if和else if都没有返回true,说明没有获取到锁

    return false;

} 



 5、代码分析



1.  当一个线程在获取锁过程中,先判断state的值是否为0,如果是表示没有线程持有锁,就可以尝试获取锁。

2.  当state的值不为0时,表示锁已经被一个线程占用了,这时会做一个判断current==getExclusiveOwnerThread(),这个方法返回的是当前持有锁的线程,这个判断是看当前持有锁的线程是不是自己,如果是自己,那么将state的值+1,表示重入返回即可。



六、简述 tcp 和 udp的区别?

------------------



1.  TCP是传输控制协议,UDP是用户数据表协议;

2.  TCP长连接,UDP无连接;

3.  UDP程序结构较简单,只需发送,无须接收;

4.  TCP可靠,保证数据正确性、顺序性;UDP不可靠,可能丢数据;

5.  TCP适用于少量数据,UDP适用于大量数据传输;

6.  TCP速度慢,UDP速度快;



七、在 Java 中,什么叫观察者设计模式(observer design pattern)?

-----------------------------------------------



1、观察者模式是一种一对多的依赖关系,让多个观察者同时监听某一主题对象。当这个主题对象发生变化时,会通知所有观察者对象,使它们能够自动更新自己。



2、JAVA提供的对观察者模式的支持



在JAVA语言的java.util库里面,提供了一个Observable类以及一个Observer接口,构成JAVA语言对观察者模式的支持。



*   Observer接口



这个接口只定义了一个方法,即update()方法,当被观察者对象的状态发生变化时,被观察者对象的notifyObservers()方法就会调用这一方法。



public interface Observer {

void update(Observable o, Object arg);

}




*   Observable类



被观察者类都是java.util.Observable类的子类。java.util.Observable提供公开的方法支持观察者对象,这些方法中有两个对Observable的子类非常重要:一个是setChanged(),另一个是notifyObservers()。第一方法setChanged()被调用之后会设置一个内部标记变量,代表被观察者对象的状态发生了变化。第二个是notifyObservers(),这个方法被调用时,会调用所有登记过的观察者对象的update()方法,使这些观察者对象可以更新自己。



八、请解释 Spring Bean 的生命周期?

------------------------



1.  通过构造器或工厂方法创建bean实例;

2.  为bean的属性赋值;

3.  调用bean的初始化方法;

4.  使用bean;

5.  当容器关闭时,调用bean的销毁方法;



九、Spring Bean 的作用域之间有什么区别?

--------------------------



Spring容器中的bean可以分为5个范围:



1.  singleton:这种bean范围是默认的,这种范围确保不管接受多少请求,每个容器中只哟一个bean的实例,单例模式;

2.  prototype:为每一个bean提供一个实例;

3.  request:在请求bean范围内为每一个来自客户端的网络请求创建一个实例,在请求完毕后,bean会失效并被垃圾回收器回收;

4.  session:为每个session创建一个实例,session过期后,bean会随之消失;

5.  global-session:global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet公用全局的存储变量的话,那么全局变量需要存储在global-session中。



十、如何在 Spring Boot 中禁用 Actuator 端点安全性?

-------------------------------------



默认情况下,所有敏感的HTTP端点都是安全的,只有具有Actuator角色的用户才能访问它们。安全性是使用标准的HTTPServletRequest.isUserInRole方法实施的。我们可以使用management.security.enable = false来禁用安全性。只有在执行机构端点在防火墙后访问时,才建议禁用安全性。



十一、什么是 YAML?

------------



YAML是JSON的一个超集,可以非常方便地将外部配置以层次结构形式存储起来。YAML可以作为properties配置文件的替代。



YAML使用的注意事项:



1.  在properties文件中是以"."进行分割的,在yml中是用"."进行分割的;

2.  yml的数据格式和json的格式很像,都是K-V格式,并且通过":"进行赋值;

3.  每个冒号后面一定要加一个空格;



十二、hibernate 有几种查询方式?

---------------------



1、导航对象图查询:根据已加载的对象,导航到其他对象。



例如,对于已经加载的Customer对象,调用它的getOrders().iterator()方法就可以导航到所有关联的Order对象,假如在关联级别使用了延迟加载检索策略,那么首次执行此方法时,hibernate会从数据库中加载关联的Order对象,否则就从缓存中获得Order对象。



2、OID方式:按照对象的OID来检索对象



Session的get()和load()方法提供了这种功能,如果在应用程序中先知道了OID,就可以使用这种方式检索对象。



get()和load()的用法完全一样,都需要两个参数,一个是持久化对象类名class,一个是行号OID,返回固定的某一行的数据,但是需要注意的是,当输入的OID不存在时,get()会返回一个空对象,load()则直接报错。



3、HQL检索方式:(hibernate query language)



使用面向对象的HQL查询语言,session的find()方法用于执行HQL查询语句。此外,hibernate还提供了query接口,它是hibernate提供的专门的HQL查询接口,能够执行各种复杂的HQL查询语句。



它具备以下功能:



1.  在查询语句中设定各种查询条件;

2.  支持投影查询,即仅检索出对象的部分属性;

3.  支持分页查询;

4.  支持连接查询;

5.  支持分组查询;

6.  提供内置函数;

7.  能够调用用户自定义的SQL函数;

8.  支持子查询;

9.  支持动态绑定参数;



例如:



Query query = session.createQuery(“from UserPo”);



获得一个query对象,注意参数字符串中不是一个SQL语句,from后面的是持久化对象名称;



List list = query.list();



就可以获取数据库中对应表的数据集合。



4、QBC检索方式:Query By Criteria的API来检索对象



这种API封装了基于字符串形式的查询语句,提供了更加面向对象的接口。




# 总结

蚂蚁面试比较重视基础,所以Java那些基本功一定要扎实。蚂蚁的工作环境还是挺赞的,因为我面的是稳定性保障部门,还有许多单独的小组,什么三年1班,很有青春的感觉。面试官基本水平都比较高,基本都P7以上,除了基础还问了不少架构设计方面的问题,收获还是挺大的。

**[资料领取方式:戳这里](https://gitee.com/vip204888/java-p7)**

* * *

**经历这次面试我还通过一些渠道发现了需要大厂真实面试主要有**:蚂蚁金服、拼多多、阿里云、百度、唯品会、携程、丰巢科技、乐信、软通动力、OPPO、银盛支付、中国平安等初,中级,高级Java面试题集合,附带超详细答案,希望能帮助到大家。




4、QBC检索方式:Query By Criteria的API来检索对象



这种API封装了基于字符串形式的查询语句,提供了更加面向对象的接口。




# 总结

蚂蚁面试比较重视基础,所以Java那些基本功一定要扎实。蚂蚁的工作环境还是挺赞的,因为我面的是稳定性保障部门,还有许多单独的小组,什么三年1班,很有青春的感觉。面试官基本水平都比较高,基本都P7以上,除了基础还问了不少架构设计方面的问题,收获还是挺大的。

**[资料领取方式:戳这里](https://gitee.com/vip204888/java-p7)**

* * *

**经历这次面试我还通过一些渠道发现了需要大厂真实面试主要有**:蚂蚁金服、拼多多、阿里云、百度、唯品会、携程、丰巢科技、乐信、软通动力、OPPO、银盛支付、中国平安等初,中级,高级Java面试题集合,附带超详细答案,希望能帮助到大家。

![蚂蚁金服5面,总结了49个面试题,遇到的面试官都是P7级别以上](https://img-blog.csdnimg.cn/img_convert/a8bc86de3c451c2e1fab0dcc16a5839f.png)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值