2024年java基础 面经

java基础 面经Java 基础 什么是字节码 jvm 可以理解的代码 class 文件 Java 代码从源代码到运行过程 java 代码 gt javac 编译器 gt class 字节码文件 gt 解释器 amp JIT 运行时编译器 gt 机器码 JIT 编译器会将热点代码的机器码保存下来

大家好,我是讯享网,很高兴认识大家。



Java基础

  • 什么是字节码?
    jvm可以理解的代码(.class文件)
    Java代码从源代码到运行过程:
    java代码 -> javac编译器->.class字节码文件 -> 解释器&JIT(运行时编译器)->机器码
    JIT编译器会将热点代码的机器码保存下来
  • 什么是AOT编译模式
    直接将字节码编译成机器码,避免了JIT预热的时间,为什么不全部使用AOT,和Java语言的动态特性有关,有些技术需要修改.class文件
  • Java执行过程
  • 在这里插入图片描述
  • 成员变量和局部变量
    成员变量如果没有赋初始值会自动赋默认值,局部变量如果没有赋初始值则不会自动赋值
  • 重载和重写的区别
  1. 重载同一个类(或者子类和父类之间),方法名相同,参数类型不同,个数不同,顺序不同,放回值和修饰符可以不同
  2. 重写发生在运行期,是子类对父类允许访问的方法的实现过程重写,方法名、参数列表必须相同。返回值比重写前的更小或相同,异常范围更小或相同,访问修饰符更大或相同
  3. private/final/static方法不能被重写
  4. 构造方法不能被重写
  • 面向对象三大特征
    封装、继承、多态
  1. 多态的具体表现为父类的引用指向子类的实例
  • 接口和抽象类有什么共同点和区别?
    共同点:
  1. 都不能被实例化
  2. 都可以包含抽象方法
    区别:
    接口主要是对类的行为进行约束,提供一种规范。抽象类主要用于代码复用,强调所属关系。
    一个类只能继承一个抽象类,但可以实现多个接口
Java中只有值传递
  • 如果参数是基本类型的话,传递基本类型字面量值的拷贝
  • 如果参数是引用类型,传递的是实参引用对象在堆地址之中的拷贝

Java序列化和反序列化

在这里插入图片描述
序列化协议对应于应用层

Java代理模式

使用代理对象来代替对真实对象(real object)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

动态代理机制

jdk动态代理机制:invocationHandler接口和proxy类是核心
invocationHandler接口定义jdk动态代理类,重写invoke调用原生方法,自定义处理逻辑
proxy获取代理对象的工厂类
缺点:只能代理实现了接口的类

CGLIB动态代理机制:MethodInterceptor 接口和 Enhancer 类是核心。
自定义 MethodInterceptor 并重写 intercept 方法,
通过 Enhancer 类的 create()创建代理类

java集合

在这里插入图片描述

collection

list

ArrayList是list主要实现类,底层使用object[],线程不安全
Vector,底层使用object[],线程安全
LinkedList,底层使用双向链表,线程不安全

set
treeset底层排序原理
comparable和comparator
  1. compareble: 在java.lang,compareTo()
  2. comparator:java.util compare()
queue

arrayDeque底层通过循环数组实现,是非线程安全的

MAP

hashmap 和hashtable hashmap线程不安全,table线程安全
基本不用hashtable
线程安全可以使用concurrenthashmap

hashmap默认大小16,扩容变为原来两倍,hashmap的扩容标准,阈值等于容量×加载因子,加载因子默认值是0.75
创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为 2 的幂次方大小
HashMap 总是使用 2 的幂作为哈希表的大小

HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)时,将链表转化为红黑树(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)

treemap:拥有集合内元素搜索的能力以及根据键排序的能力

concurrenthashmap实现线程安全的方式:1.7的时候采用segment的方式,每把锁只锁一部分数据,segment继承了reentrantlock,可重入锁,segmengt的个数确定不可变在这里插入图片描述

1.8的时候 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 synchronized 和 CAS 来操作
在这里插入图片描述

java IO

设计模式

装饰器模式:在不改变原有对象的情况下拓展其功能
装饰器模式很重要的一个特征,那就是可以对原始类嵌套使用多个装饰器。
适配器模式:主要用于接口互不兼容的类的协调工作

常见的IO模型
  1. BIO同步阻塞IO模型
    在这里插入图片描述
  2. NIO
    同步非阻塞IO
    在内核准备数据和数据就绪阶段中,应用程序会一直read调用,不过在数据拷贝阶段中,线程依然阻塞。不过应用程序不断进行 I/O 系统调用轮询数据是否已经准备好的过程是十分消耗 CPU 资源的。
    在这里插入图片描述
    IO多路复用
    线程发起select调用,等到内核数据准备好之后再发起read调用,read调用的过程依然阻塞,通过减少无效的系统调用,减少了对CPU资源的消耗
    在这里插入图片描述
  3. AIO
    异步IO基于事件和回调机制实现
    在这里插入图片描述

并发编程

线程的生命周期和状态

在这里插入图片描述
sleep 和wait 方法对比
sleep()方法没有释放锁,wait释放锁
sleep是thread类的静态方法,wait是object类的本地方法,因为wait方法操作的的是对象实例

反复调用一个线程的start()方法是否可行

不行,threadStatus的变量。如果它不等于0,调用start()是会直接抛出异常的。,在调用一次start()之后,threadStatus的值会改变(threadStatus !=0),此时再次调用start()方法会抛出IllegalThreadStateException异常。

可以直接调用 Thread 类的 run 方法吗?
线程组和线程优先级
线程安全问题
活跃性问题
  1. 死锁
  2. 活锁
  3. 饥饿问题

java基础 面经

性能问题

线程创建和上下文切换

java内存区域和内存模型

Java使用共享内存并发模型
1.内存可见性
针对共享变量,堆,为什么会有内存不可见问题,因为会在缓存区缓存共享变量
在这里插入图片描述
JMM通过控制主内存与每个线程的本地内存之间的交互,来提供内存可见性的保证。
指令重排:
编译器优化重排
指令并行重排
内存系统重排

线程池

通过threadPoolExecutor的方式创建线程池,不建议使用executors创建。
核心参数:
corePoolSize:线程池的核心线程数量
maximumPoolSize:最大线程数量
keepAliveTime:线程数大于核心线程数时的空闲线程最长存活时间
workQueue:等待队列

线程池饱和策略:
AbortPolicy:抛出异常RejectedExecutionException来拒绝新任务的处理
CallerRunsPolicy:调用执行线程运行任务
discardPolicy:不处理新任务,直接丢掉
discardOldestpolicy:丢弃最早的未处理任务

线程池提交一个任务的流程原理

在这里插入图片描述

几个对比
  1. runnable和callable:runnable不会返回结果或抛出异常,callable可以
  2. execute和submit:execute用于提交不需要返回值的任务,无法判断任务是否被线程池执行成功与否。submit会返回一个future类型对象,通过这个对象可以判断任务是否执行成功,通过future的get方法获取返回值
AQS

核心思想:
AQS 核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制 AQS 是用 CLH 队列锁 实现的,即将暂时获取不到锁的线程加入到队列中。在 CLH 同步队列中,一个节点表示一个线程,它保存着线程的引用(thread)、 当前节点在队列中的状态(waitStatus)、前驱节点(prev)、后继节点(next)。
核心原理图:
在这里插入图片描述
AQS使用state变量表示同步状态

semaphore

semaphore会默认构造state为许可的数量,然后state>=0的时候可以获取,小于0的时候不行,加入阻塞队列

一般用来限流

countdownlatch

CountDownLatch 允许 count 个线程阻塞在一个地方,直至所有线程的任务都执行完毕。CountDownLatch 是一次性的,计数器的值只能在构造方法中初始化一次,之后没有任何机制再次对其设置值,当 CountDownLatch 使用完毕后,它不能再次被使用

CLH队列锁

CLH是一个虚拟的双向队列,AQS将每个请求共享资源的线程封装成CLH锁队列的节点实现锁分配。
在这里插入图片描述

乐观锁的实现

版本号机制或CAS算法

常见并发容器
ConcurrentHashMap

线程安全的hashmap
无论是读操作还是写操作都能保证很高的性能:在进行读操作时(几乎)不需要加锁,而在写操作时通过锁分段技术只对所操作的段加锁而不影响客户端对其它段的访问。
初始化的时候table数组的长度为2的幂次方。
调用构造器方法的时候并未构造出table数组(可以理解为ConcurrentHashMap的数据容器),只是算出table数组的长度,当第一次向ConcurrentHashMap插入数据的时候才真正的完成初始化创建table数组的工作。
从整体而言,为了解决线程安全的问题,ConcurrentHashMap使用了synchronzied和CAS的方式。

copyonwriteArrayList
ConcurrentLinkedQueue

非阻塞队列,使用CAS,适应于加锁成本较高的场景

BlockingQueue

是一个接口,被广泛用来生产者消费者模型
常见实现类:ArrayBlockingQueue、LinkedBlockingQueue 、PriorityBlockingQueue
arrayblockingQueue:底层使用数组实现和reentrantlock锁,容量不能改变。
linkedblockingqueue:使用单向链表实现,可以当作有界队列和无界队列使用,可以传入最长长度
PriorityBlockingQueue 是一个支持优先级的无界阻塞队列。默认情况下元素采用自然顺序进行排序,无界队列,会默认扩容

ConcurrentSkipListMap
小讯
上一篇 2024-12-28 22:37
下一篇 2024-12-28 16:41

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/8134.html