2022年同花顺Java面试 前言 最近疫情期间抽空面试了一家互联网公司,很多问题都很常见,但是很长时间没有看这方面的知识了,所以回答的确实很不好,于是周末抽空把涉及的问题整理一下,希望对大家有用 。
正文 Java基础 1.一个java文件中有几个类,编译后有几个class文件?
在一个源文件中用class关键字定义了几个类,编译的时候就会产生几个字节码文件
2. Java是否可以同时使用abstract和fInal声明方法?
final的四种用法:
final修饰的是引用不可修改,但是引用地址指向的数据可以改变 。final可以修饰方法 方法不可被覆盖 (继承类之间的关系)final修饰类 表示该类不能被继承final修饰成员变量,该成员变量不可被修改
abstract,则需要重写abstract方法,所以我们在方法不能同时使用abstract和fInal声明方法.其他相关问题:
-a.Java是否可以同时使用abstract和static声明方法?
static与abstract不能同时使用, 用static声明方法表明这个方法在不生成类的实例时可直接被类调用, 而abstract方法不能被调用,两者矛盾 。b. Java是否可以同时使用abstract和native声明方法?
native与abstract不能同时使用,因为 native 暗示这些方法是有实现体的,只不过这些实现体是非java 的,但是abstract却显然的指明这些方法无实现体 。c.Java是否可以同时使用abstract和 synchronized声明方法?
synchronize与abstract不能同时使用,synchronize(经常结合static)声明方法,我们称作类锁,用来确保多线程下的线程安全 。- 用
synchronized的前提是该方法可以被直接调用,所以不能和abstract一起使用.
- 使用
Thread,重写run()方法 - 实现
Runnable接口,重写run()方法 - 实现
Callable接口,相对于Runnable是有返回值,重写call()方法 - 使用
Executor框架来创建线程池
Future通常与Callable结合使用,Future可以对Callable任务的执行结果进行取消、查询是否完成、获取结果 。必要时可以通过get方法获取执行结果,该方法会阻塞直到任务返回结果 。- 但是
Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了FutureTask。 - 在
JDK1.8中提供了CompletableFuture,提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以通过回调的方式处理计算结果,并且提供了转换和组合CompletableFuture的方法 。
实现线程同步的6种方式:
- 使用
Synchronized标记临界区 - 对变量使用
volatile进行标记,可以实现原子操作的线程安全 - 使用锁机制
- 使用局部变量
ThreadLocal实现线程同步 - 使用阻塞队列
SyschronousQueue实现线程同步 - 使用原子变量实现线程同步
- 公平锁和非公公平锁的区别在于公平锁会保证先来的线程会先获取资源(其内部实现时
AQS原理),而非公平不能保证 。 - 公平锁的实现是通过
FIFO先进先出的队列来实现的,非公平锁会由JVM就近安排线程获取资源的顺序,所以非公平锁的性能是优于公平锁的 。 sychronized是非公平锁,ReenterLock(默认也是非公平锁)可以实现公平锁 。
ReentrantLock主要利用CAS+AQS队列来实现的:- 先通过
CAS尝试获取锁,如果此时已经有线程占据了锁,那就加入AQS队列并且被挂起; - 当锁被释放之后,公平锁的情况下:排在队首的线程会被唤醒
CAS再次尝试获取锁,非公平锁下由JVM就近决定哪个线程获取资源 。
AQS是将每一条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node),来实现锁的分配 。AQS就是基于CLH队列,用volatile修饰共享变量state,线程通过CAS去改变状态符,成功则获取锁成功,失败则进入等待队列,等待被唤醒 。CLH队列是一个虚拟的双向队列(FIFO先进先出),虚拟的双向队列即不存在队列实例,仅存在节点之间的关联关系 。
public ThreadPoolExecutor(int corePoolSize,#核心线程数int maxinmumPoolSize,#线程总数非核心数=总数-核心数long keepAliveTime,#当前线程数大于核心线程数时线程的等待新任务的等待时间(核心线程也会面临死亡)TimeUnit unit,#时间单位BlockingQueue workQueue #任务队列RejectedExecutionHandler #(选填) 拒绝处理器) 8.当一个新的任务进来,线程池怎么处理线程池处理线程的过程:
- 当前运行线程数 小于
corePoolSize任务直接交给核心线程进行执行 - 当前运行线程数 大于或等于
corePoolSize任务且满足队列未满,那么任务将进入任务队列进行等待,并且任务队列都具有阻塞性,所以只有当核心线程数的任务执行完了,才会从任务队列中获取任务 。 - 当前运行线程数 大于或等于
corePoolSize任务且队列已满,那么 任务进入非核心线程 。 - 当核心线程、等待队列、非核心线程都被占用的时候线程会被拒绝器处理 。
适用:那些既不能进入核心线程、等待队列,也无法使用非核心线程来处理,或者线程异常的线程:
- CallerRunsPolicy:直接运行该任务的
run方法,但不是在线程池内部,适合处理业务比较重要且数量不多的场景 。 - AbortPolicy:
RejectedExecutionException异常抛出 。适用对业务非常重要的完全不能不执行的场景 。(默认) - DiscardPolicy:不会做任何处理 。适合处理丢失对业务影响不大的场景 。
- DiscardOldestPolicy:检查等待队列 强行取出队列头部任务(并抛弃该头部任务)后再进行执行该任务 。适合新数据比旧数据重要的场景 。
方式一:使用join
Thread类中的join方法的主要作用就是同步,它可以使得线程之间的并行执行变为串行执行 。方式二:CountDownLatch(线程计数器)+Semaphore信号量
CountDownLatch用于主线程等待其他子线程任务都执行完毕后再执行;Semaphore信号量是java.util.concurrent包下用来:限制线程并发的数量的工具类,基于AQS实现的,在构造的时候会设置一个值,代表着资源数量 。
CyclicBarrier用于一组线程相互等待大家都达到某个状态后,再同时执行;11.Java的引用类型,并且举例说明其使用场景
- 强引用:
A a=new A()只要引用a存在,垃圾回收器不会回收 。 - 软引用:
SoftReference类似于缓存的方式,不影响垃圾回收,可以提升速度,节省内存 。若对象被回收,此时可以重新new,主要是用来缓存服务器中间计算结果以及不需要实时保存的用户行为 。通常放在用在对缓存比较敏感的应用中 。 - 弱引用:
WeakReference用于监控对象是否被垃圾回收器回收 。 - 虚引用:
PhantomReference,每次垃圾回收的时候都会被回收 。主要用于判断对象是否已经从内存中删除 。
- 单例模式(默认):
Spring创建Bean的原则是不等bean创建完成就将beanFactory提早放到缓存中,如果其他bean依赖这个bean可以直接使用,这种三级缓存的机制很好地解决了循环依赖的问题 。 - 多例模式(原型模式):每次使用时都会创建新的
Bean实例,Bean调用setAllowCircularReferences(false)来禁止循环依赖,否则出现循环依赖会直接抛异常 。 - Request模式:一次
request一个实例, 当前Http请求结束,该bean实例也将会被销毁. - Session模式:在一次
Http Session中,容器会返回该 Bean 的同一实例 。而对不同的Session请求则会创建新的实例,该bean实例仅在当前Session内有效 。 - global Session模式(不常使用):在一个全局的
Http Session中,容器会返回该Bean的同一个实例,仅在 使用portlet context时有效 。
xml配置文件中添加配置属性scope= prototype使用,或者使用注解@Scope("prototype")单例模式和多例模式的线程问题
多例模式:每次创建一个新对象,也就是线程之间并不存在
Bean共享,自然是不会有线程安全的问题 。单例模式下的线程安全问题:
- 对于类似于
DAO这种只有查询的无状态Bean在单例情况下是可以保证线程安全
- 在
@Controller/@Service等容器中,默认单例模式是线程不安全的 。
- 即使
@Controller/@Service使用多列模式下,如果使用静态变量,它也不是线程安全的
- 一定要定义变量的话,用
ThreadLocal来封装,这个是线程安全的
循环依赖指的是
Spring Bean之间相互依赖的情况 。解决循环依赖的前置条件:
- 出现循环依赖的
Bean必须要是单例,都是多例模会直接报错 - 依赖注入的方式不能全是构造器注入的方式
Spring在创建Bean的时候默认是按照自然排序来进行创建的,IOC容器先创建A,再创建B:- A、B均采用
setter方式相互注入 - A采用
setter方式获取B,B采用构造器方式获取A
解决循环依赖的流程:
- 当A完成了实例化并添加进了
Bean的缓存池(一级缓存)中 。 - 为A进行属性注入了,在注入时发现A依赖了B,会去实例化B 。
- 在创建B的时候,因为A已经放在
Bean的缓存池(一级缓存)当中了,所以无论B采用的setter方式还是构造器方式都可以获取A 。
- 如果A采用的是构造器方式,创建A时发现依赖于B,于是会先去创建B,但是B又依赖于A,并且缓存没有A,所以会直接因为循环依赖,导致启动异常 。
-
@Autowired、@Resources实际上都是setter方式注入依赖 。
- singletonObject:一级缓存,这里的
bean是已经创建完成的,一旦进行getBean操作时,我们第一时间就会寻找一级缓存 - earlySingletonObjects:二级缓存,该缓存所获取到的
bean是提前曝光出来的,是还没创建完成的 。 - singletonFactories:三级缓存为早期曝光对象工厂,这个工厂的目的在于延迟对实例化阶段生成的对象的代理,只有真正发生循环依赖的时候,才去提前生成代理对象 。
- 添加单例缓存,当
bean被创建完以后进行的操作 。这时候说明bean已经创建完,删除二三级缓存,直接留下一级缓存,并且注册该bean。 - 二级缓存可以提前曝光被其他
Bean所引用,它可以解決循环依赖 。但是二级缓存无法解决AOP+循环依赖的问题,因为不可能每次执行singleFactory.getObject()方法都给我产生一个新的代理对象,所以还要借助另外一个缓存来保存产生的代理对象 。 - 三级缓存是用来来保存产生的代理对象,但它并没有所谓性能上的“提升” 。
用户发送请求和返回响应的流程:
- 发送请求至
DispatcherServlet - 映射处理器获取处理器映射至
DispatcherServet HandlerAdapter进行处理器适配- 调用处理器相应功能处理方法(获得
View和model至DispatcherServlet) ViewResolver接收View进行视图解析Model加入到View中进行视图渲染DispatcherServlet返回响应
使用场景:资源共享的情况
描述:单例模式自行实例化且实例化一次 构造函数必须是私有的
懒汉单例模式和饥汉单例模式
- 懒汉单例模式:在调用资源时,如果没有进行实例化的话,就进行一次实例化 。
- 饥汉单例模式:在没有调用时就已经自行实例化了 。
使用
synchronized方法(类锁)+ synchronized块(对象锁)外部加了一个判空的逻辑,确保线程安全;synchronized两种锁:
- 对象锁:用
sychronized修饰代码块 (手动去指定锁对象) - 类锁:用
sychronized修饰普通方法(类锁只能在同一时刻被一个对象拥有 通过方法的ACC_SYNCHRONIZED标志符是否被设置,这里会隐形调用monitorenter、monitorexit这两个指令 )
singleton属性被volatile修饰,其作用:
- 可见性:线程A实例化属性之后,
Volatile刷入主存 - 防止指令重排: 防止多线程下指令重排,进而实例化两次或者获取一个null
- volatile变量规则:对
volatile修饰的变量的写操作 先行发生于后面对这个变量的读操作;
/*** 单例模式-双重校验锁** @author szekinwin*/public class SingleTon3 {//私有化构造方法private SingleTon3() {}//通过volatile,实现添加内存屏障,防止指令重排序private static volatile SingleTon3 singleTon = null;public synchronized static SingleTon3 getInstance() {//第一次校验if (singleTon == null) {synchronized (SingleTon3.class) {//第二次校验if (singleTon == null) {singleTon = new SingleTon3();}}}return singleTon;}} 总结 很多时候我都觉得自己挺菜的,真的有很多东西需要去学,上面很多的知识很多其实都学过,可是真的面试的时候总是不能完整清晰的回答出来,学习真是一直习惯,不能荒废 。【2022年同花顺Java面试】
- 春季老年人吃什么养肝?土豆、米饭换着吃
- 三八妇女节节日祝福分享 三八妇女节节日语录
- 老人谨慎!选好你的“第三只脚”
- 校方进行了深刻的反思 青岛一大学生坠亡校方整改校规
- 脸皮厚的人长寿!有这特征的老人最长寿
- 长寿秘诀:记住这10大妙招 100%增寿
- 春季老年人心血管病高发 3条保命要诀
- 眼睛花不花要看四十八 老年人怎样延缓老花眼
- 香槟然能防治老年痴呆症? 一天三杯它人到90不痴呆
- 老人手抖的原因 为什么老人手会抖
