当前位置:网站首页 > Java基础 > 正文

java基础在线题库



一、Java 基础

1.1、java 面向对象特征

  • 封装

封装类内部的实现结构,保护数据,增加代码可维护性,不需要关心内部实现。

  • 继承

从已有的类中派生出新的类。新的类拥有已有类的的属性和行为。并能扩展新的能力。

  • 多态

父类的引用指向子类的对象。三要素:继承,重新,父类引用指向子类对象

1.2、Java 中的引用类型有哪几种

强引用

 

在这里 o 就是引用,在 Java 中,引用类型有 强、软、若、虚四种引用

强引用内存模型:
在这里插入图片描述
没有任何引用指向时被删除

软引用

 

软引用内存模型:
在这里插入图片描述
二流引用,当空间不足时会被清理(一般利用在缓存)

弱引用

 

内存模型
在这里插入图片描述
当垃圾回收器发现时就会被回收(使用完就会被删除(spring中 数据库连接对象放在 ThreadLocal 中))

ThreadLocal

 

ThreadLocal set()模型
在这里插入图片描述
这里需要看 set()方法源码,在 Entry 中的 key 弱引用指向 ThreadLocal 防止内存泄漏

虚引用
虚引用指向的对象不是给业务人员用的,是给垃圾回收用的(跟踪堆外内存),get 是拿不到的

1.3、hashMap 和 HashTable的区别

  • 1、HashTable线程同步,HashMap非线程同步
  • 2、HashTable不允许<键,值>有空置,HashTable允许<键,值>有空置
  • 3、HashTable使用Enumeration,HashMap使用 Iterator
  • 4、HashTable 中 hash 数组的默认大小是11,增加方式 old*2+1 ,HashMap 中hash数组的默认值大小是16,增长方式是2的指数倍
  • 5、HashTable 继承Dictionary类,hashMap继承自AbstractMap类

1.4、hashMap 有那些线程安全的方式

1.5、Java线程中线程的实现方式

  • 继承 Thread 类,重 run 方法(缺点,不能多继承)
  • 实现 Runnable 接口,实现 run 方法(缺点,没有返回值)
  • 实现 Callable 接口,有返回值
  • 通过线程池创建

1.6、工作中如何创建线程池

为什么不建议使用 Executors 创建线程池

 
 

1.7、线程池中有哪几种状态,每种状态表示什么意思

线程池中对应的源码

 

是用 ctl 这一个变量存储(int是32位,高三位存储状态,后29位代表线程数量)

  • RUNNING(运行)线程池新建就会或者调用 execute 方法时就会是此状态,代表运行,能够接受新的任务。
  • SHUTDOWN(关闭)调用shutdown()方法后,线程池状态会变成 SHUTDOWN,此时线程池不会在接收新的任务,但会执行已提交等待队列中的任务
  • STOP (停止)调用shutdownNow()方法后,线程池状态会变成 STOP ,此时线程池不会在接收新的任务, 不会执行已提交等待队列中的任务
  • TIDYING (中间状态)用来给子类扩展
  • TERMINATED (终止状态)线程池内的线程都已经终止,线程池进入TERMINATED 状态

1.8、synchronized 和 ReentrantLock 有哪些不同点

以下是对比,前面是synchronized ,后面是 ReentrantLock:
在这里插入图片描述

1.9、ThreadLocal底层是如何实现的,有那些应用场景?

介绍: hreadLocal 是Java中所提供的的线程本地存储机制,可以利用该机制将数据,该线程可以在任意时刻、任意方法中获取缓存数据
在这里插入图片描述
底层原理: ThreadLocal 底层是通过ThreadLocalMap来实现的,每个Thread对象(注意不是ThreadLocal对象)中都有一个ThreadLocalMap,Map的key为ThreadLocal对象,Map的value为需要缓存的值
在这里插入图片描述
问题: 如果在线程池中使用ThreadLocal 可能会造成内存泄漏,因为ThreadLocal对象使用完之后,应该把设置的key,value,也就是Entry对象进行回收,但线程池中的线程不会回收,而线程对象是通过强引用指向ThreadLocalMap,ThreadLocalMap也是通过强引用指向Entry对象,线程不被回收,Entry对象也就不会被回收,从而出现内存泄漏,解决办法,在使用ThreadLocal对象之后java基础在线题库,手动调用ThreadLocal的remove方法,手动清除Entry对象
应用:
1、跨层传递信息的时候。
2、隔离线程,存储一些线程不安全对象,如(SimpleDateFormat)
3、spring中的事务管理器就是用的是ThreadLocal。
4、springmvc 的 HttpSesion,HttpServletRequest、HttpServletResponse都是放在ThreadLocal中,因为Servlet是单例的,而springmvc中允许在controller中通过@Autowired配置requestmresponse以及requestcontext等实例对象,就是搭配ThreadLocal实现线程安全

1.10、ReentrantLock是公平锁还是非公平锁?底层如何实现?

ReentrantLock 可以是公平锁( new ReentrantLock(true)),也可以是非公平锁(new ReentrantLock())
不管是公平锁还是非公平锁,它们的底层实现都会使用AQS来进行排队,它们的区别在于线程使用lock()方法时加锁:
1、如果是公平锁,会检查AQS是否存在线程排队,如果有线程排队,则当前线程也排队
2、如果是非公平锁,不会检查AQS是否存在线程排队,直接竞争锁
注意: 不管是公平锁还是非公平锁,一旦没有竞争到锁,都会进行排队,当锁释放时,都是唤醒排在最前面的线程,所以非公平锁只是体现在了加锁阶段,而没有体现在线程被唤醒阶段。

1.11、synchronized的锁升级过程是怎样的

1、无锁
2、偏向锁: 在锁对象的对象头中记录当前该锁的线程ID,该线程下次如果又来获取该锁姐可以直接获取到,也就是支持
3、轻量级锁: 当两个或以上线程,但并没有在对象上并发的获取锁时,偏向锁升级为轻量级锁,线程采用CAS的自旋方式尝试获取锁,避免阻塞线程造成 cpu 在用户态和内核态转换的消耗
4、重量级锁: 两个或以上线程并发的在同一个对象上竞争时,为了避免无用自旋消耗cpu,轻量级锁会升级成重量级锁

1.12、Tomcat中为什么要使用自定义类加载器

应用隔离:
Tomcat作为一个Web容器,能够同时部署和运行多个Web应用程序。每个应用可能依赖不同的库版本或者包含同名类。为了确保每个应用的类库相互独立,避免类冲突,Tomcat为每个Web应用提供了一个独立的类加载器实例,即WebAppClassLoader。这样,即使不同应用中存在相同的类名,它们也是被各自的应用类加载器加载,互不影响。这种机制保证了应用的隔离性,使得不同应用可以独立运行而不会相互干扰。

1.13、对象创建过程(Object o = new Object() )

  • 对象创建过程

在这里插入图片描述new 申请空间,半初始化状态,invokespecial 属性赋值,astore_1 o 和 Object建立关联。

  • DCL单例到底需不需要 volatile(线程可见,禁止指令重排序)
    必须要加volatile,防止指令重排序,拿到半初始化对象(invokespecial ,astore_1 这两条指令有可能发生重排序,导致对象初始化,也就是对象的属性都是默认值没有完成赋值)

1.14、对象在内存中的存储布局

普通对象

在这里插入图片描述

  • markword
    包括,锁信息,GC信息,hashcode
  • class pointer
    指向对应的class文件,前两个叫对象头
  • instance data
    实例数据
  • padding
    对齐(空间换取时间,和计算机的64为有关系,会补齐成8的倍数)

数组
在这里插入图片描述
这里会多一个 length(数组长度)

对象怎么定位

在这里插入图片描述
两种方式,第一种句柄(方便GC),第二种直接指针(效率比较高),hotspot用的是直接指针

对象怎么分配

分代模型

在这里插入图片描述
TLAB(线程在伊甸园区分配的空间)

1.15、线程状态

 

以上是 jdk 源码中的线程状态。一共有六种 NEW(新建,cpu无法调度),RUNNABLE(线程启动(对应cpu的就绪/运行)),BLOCKED(获取synchronized锁失败),WAITING(等待,需要手动唤醒),TIMED_WAITING(不需要手动唤醒,执行了sleep等方法),TERMINATED(结束)

1.15、如何停止线程

  • stop方法(不用),强制线程停止
  • 共享变量停止
  • interrupt 方法(Thread.currentThread().interrupt();)

1.16、wait 和 sleep的区别

  • sleep属于Thread类的static方法,wait属于Object类的方法
  • sleep属于TERMINATED,自动被唤醒,wait 属于 WAITING,需要手动唤醒
  • sleep 方法在持有锁时,执行,不会释放锁资源,wait 在执行后会释放锁资源
  • sleep可以在持有锁或者不持有锁时执行,wait 必须持有锁时执行

1.17、并发编程三大特性

1、原子性

保证方法:

  • synchronized
  • CAS
  • Lock锁
  • ThreadLocal

2、可见性

  • volatile
  • synchronized
  • Lock
  • final

3、有序性
`有序性指的是程序执行的顺序按照代码的先后顺序执行,即程序中的指令执行顺序与代码中的书写顺序一致,不会出现乱序执行的情况

  • volatile关键字:除了保证可见性外,volatile关键字还可以保证有序性。它禁止了编译器和处理器对volatile变量周围的代码进行重排序优化,从而确保程序执行的顺序性。
  • 锁机制:与可见性类似,锁机制(如synchronized关键字或显式锁Lock)也可以保证有序性。在同步块或同步方法中,所有的操作都几乎是串行化执行的,从而避免了指令重排序导致的问题。
  • Happens-Before规则:Java内存模型(JMM)定义了一系列的Happens-Before规则,用于规范哪些操作之间的执行顺序是确定的。这些规则包括了程序顺序规则、volatile变量规则、锁规则等,它们共同保证了在并发编程中的有序性。`

1.18、什么是CAS

CAS是Compare and Swap的缩写,即比较并交换,它是一种实现无锁数据结构的关键技术。CAS操作包含三个参数:要更新的内存位置(V)、预期值(E)和新值(N)。仅当V值等于E值时,才会将V的值设为N。如果V值和E值不同,则说明已经有其他线程做了更新,则当前线程不进行操作。

1.19、@Contended 注解

@Contended注解是Java 8中引入的一个注解,其主要作用在于减少多线程环境下的“伪共享”现象,从而提高程序的性能。

伪共享(False Sharing):

伪共享是多线程环境中的一种现象,它源于CPU的缓存机制和缓存行的概念。现代CPU为了提高访问效率,会在CPU内部设计快速存储区域,称为缓存(Cache)。缓存不是直接对单个字节进行操作的,而是以块(通常称为“缓存行”)为单位操作的。一个缓存行通常包含64字节的数据。在多线程环境下,如果两个或更多的线程在同一时刻分别修改存储在同一缓存行的不同数据,CPU为了保证数据一致性,会使得其他线程必须等待一个线程修改完数据并写回主内存后,才能继续执行,这种现象就称为伪共享。伪共享会导致不必要的线程等待和性能损耗。

@Contended注解的作用

@Contended注解被设计用来解决伪共享问题。当这个注解被用于类或字段时,它向JVM(Java虚拟机)发出一个提示,表明被注解的类或字段可能存在内存竞争,因此应该尽量将它们放在与其他对象或字段位置隔离的位置。具体来说,这个注解会促使JVM在分配内存时,尽量确保被注解的字段或类的实例独占缓存行,从而避免伪共享现象的发生。

1.20、什么是AQS

AQS全称为AbstractQueuedSynchronizer,是一个用于构建锁和其他同步器的框架。它提供了一个基础的同步原语,允许开发者通过继承AQS并实现其内部定义的抽象方法来实现自定义的同步器。
概述:
AQS在Java并发编程中扮演着重要角色,是构建各种同步机制的基础。它通过一个FIFO(先进先出)的等待队列来管理多线程对共享资源的访问,从而避免了竞态条件和死锁等问题。AQS的核心思想是将多线程的进入和退出操作都放入一个等待队列中,通过对这个队列的管理来控制线程对共享资源的访问。
核心原理:

  • 状态变量:AQS内部维护了一个表示同步状态的volatile变量(通常是int类型),通过CAS(Compare-And-Swap)操作来保证这个变量的原子性修改。这个状态变量用于表示锁的状态(如是否被占用)或其他同步器的同步状态。
  • 等待队列:AQS还维护了一个FIFO的双向链表,用于存放等待获取资源的线程。当某个线程尝试获取资源失败时,它会被加入到这个队列中等待。当资源被释放时,AQS会按照FIFO的顺序唤醒等待队列中的线程。

二、数据库

2.1、ACID 是靠什么保证的

  • 原子性:由 undolog 日志来保证,他记录需要回滚的日志信息,事务回滚时撤销已执行的 sql
  • 一致性:有其他三大特性保证
  • 持久性:由 redolog 来保证,mysql 修改数据时会在redolog中记录一份日志数据,就算没有保存成功,只要日志保存成功,数据任然不会丢失
  • 隔离性:由mvcc来保证

三、spring

3.1、BeanFactory 和 ApplicationContext 的区别
  • 相同点:
    1、都是Java接口,ApplicationContext 继承 BeanFactory (ListableBeanFactory )
    2、他们都可以用来配置XML,也支持属性的自动注入
    3、都提供getBean(“beanName”) 来获取Bean
  • 不同点
  • 1、BeanFactory 调用getBean 时实例化bean,ApplicationContext 容器启动时实例化
  • 2、BeanFactory不支持国际化, ApplicationContext 支持
  • 3、如果使用自动注入并使用 BeanFactory ,则需要使用 API 注册 AutoWiredBeanPostProcess,如果使用 ApplicationContext 可以使用XML

四、微服务

4.1、微服务有什么好处

单体项目的缺点:
1、可扩展性差:
随着业务的增长,单体项目的规模会不断增大,导致代码库变得庞大且复杂。
当需要扩展系统的某个特定功能时,往往需要对整个系统进行扩展,这会造成资源的浪费。
难以进行局部优化,因为所有组件都紧密耦合在一起。
2、维护困难:
单体项目中的代码往往相互依赖,修改一个组件可能会影响到其他组件。
随着时间的推移,代码库会变得难以理解和维护。
新加入的开发者需要花费大量时间来熟悉整个系统的架构和代码。
3、高风险:
单体项目中的所有组件都运行在同一个进程中,如果某个组件出现故障,可能会导致整个系统崩溃。
难以进行故障隔离,因为所有组件都共享相同的资源(如内存、数据库连接等)。
4、技术栈受限:
单体项目通常使用统一的技术栈,这限制了开发者在选择新技术时的灵活性。
如果需要引入新技术或框架,可能需要对整个系统进行重构。
5、团队协作难题:
在大型单体项目中,多个团队可能需要同时工作在不同的组件上。
这可能导致代码冲突、依赖关系混乱以及团队协作困难。
微服务项目的优点:
1. 灵活性和可扩展性
独立开发部署和扩展:微服务架构允许每个服务独立开发、测试和部署,这意味着开发团队可以专注于特定服务的实现,而不需要等待整个应用程序的发布周期。
弹性设计:微服务架构能够实现弹性设计,即在面对高并发请求或异常情况时,能够自动调整服务实例数量,以保证系统的可用性和性能。
2. 易于维护
代码复杂度降低: 由于微服务架构将应用程序拆分成多个小型服务,每个服务的功能相对单一,代码复杂度降低,使得服务更易于理解和维护。
独立更新和修复: 如果某个服务出现问题,只需要修复该服务并重新部署,不会影响其他服务的运行,降低了修复和更新的风险。
高效的测试: 每个服务都可以独立进行单元测试和集成测试,提高了测试的效率和准确性,有助于快速发现和修复问题。
3. 技术多样性
选择合适的技术栈: 微服务架构允许开发团队为每个服务选择最适合的技术栈和编程语言,这有助于充分利用各种技术和工具的优势,提高开发效率。
易于尝试新技术: 在微服务架构中,如果某个新技术在某个服务中表现良好,可以逐步推广到其他服务中,降低了尝试新技术的风险和成本。
4. 高可用性和容错性
故障隔离: 微服务架构中的服务之间通过轻量级通信机制进行交互,单个服务的故障通常不会影响其他服务的运行,提高了系统的容错性和可用性。
快速恢复: 由于微服务架构中的服务相对较小且独立,故障排查和修复相对容易,可以快速定位问题并进行修复,减少故障对系统的影响时间。
5. 团队协作
小型团队: 每个服务可以由一个小型的团队负责开发、维护和部署,团队成员之间的沟通和协作更加高效。
明确职责: 每个团队对自己负责的微服务有明确的职责和所有权,这有助于提高团队的责任感和工作效率。

文章并不完整,我将持续更新。写的不合适的地方还请大家指出,希望与您共同进步

版权声明


相关文章:

  • java基础教程强制类型转换2024-11-16 21:42:04
  • java基础3原码反码补码转换2024-11-16 21:42:04
  • java后端零基础2024-11-16 21:42:04
  • java基础文件处理包2024-11-16 21:42:04
  • java第一章java语言基础2024-11-16 21:42:04
  • 只会java基础怎么找工作2024-11-16 21:42:04
  • java基础教程第2版答案2024-11-16 21:42:04
  • java基础入门详解2024-11-16 21:42:04
  • java基础入门图片2024-11-16 21:42:04
  • 有js基础学java2024-11-16 21:42:04