java八股文面试题

本文详细介绍了Java面试中涉及的八大模块:基础、线程、JVM、MySQL、Redis、Spring、计算机网络以及其他。涵盖了接口与抽象类的区别、HashMap原理、线程安全、并发控制、JVM内存管理、数据库事务与索引、缓存机制、Spring的自动装配以及网络通信等内容,旨在帮助读者全面理解和掌握Java面试的重点知识。
摘要由CSDN通过智能技术生成

一、Java基础

1.接口和抽象类的区别

相似点:

(1)接口和抽象类都不能被实例化

(2)实现接口或继承抽象类的普通子类都必须实现这些抽象方法

不同点:

(1)抽象类可以包含普通方法和代码块,接口里只能包含抽象方法,静态方法和默认方法,

(2)抽象类可以有构造方法,而接口没有

(3)抽象类中的成员变量可以是各种类型的,接口的成员变量只能是 public static final 类型的,并且必须赋值

2.重载和重写的区别

重载发生在同一个类中,方法名相同、参数列表、返回类型、权限修饰符可以不同

重写发生在子类中,方法名相、参数列表、返回类型都相同,权限修饰符要大于父类方法,声明异常范围要小于父类方法,但是final和private修饰的方法不可重写

3.==和equals的区别

==比较基本类型,比较的是值,==比较引用类型,比较的是内存地址

equlas是Object类的方法,本质上与==一样,但是有些类重写了equals方法,比如String的equals被重写后,比较的是字符值,另外重写了equlas后,也必须重写hashcode()方法

4.异常处理机制

(1)使用try、catch、finaly捕获异常,finaly中的代码一定会执行,捕获异常后程序会继续执行

(2)使用throws声明该方法可能会抛出的异常类型,出现异常后,程序终止

5.HashMap原理

        1.HashMap在Jdk1.8以后是基于数组+链表+红黑树来实现的,特点是,key不能重复,可以为null,线程不安全

        2.HashMap的扩容机制:

HashMap的默认容量为16,默认的负载因子为0.75,当HashMap中元素个数超过容量乘以负载因子的个数时,就创建一个大小为前一次两倍的新数组,再将原来数组中的数据复制到新数组中。当数组长度到达64且链表长度大于8时,链表转为红黑树

        3.HashMap存取原理:

        (1)计算key的hash值,然后进行二次hash,根据二次hash结果找到对应的索引位置

          如果这个位置有值,先进性equals比较,若结果为true则取代该元素,若结果为false,就使用高低位平移法将节点插入链表(JDK8以前使用头插法,但是头插法在并发扩容时可能会造成环形链表或数据丢失,而高低位平移发会发生数据覆盖的情况)

6.想要线程安全的HashMap怎么办?

(1)使用ConcurrentHashMap

(2)使用HashTable

(3)Collections.synchronizedHashMap()方法

7.ConcurrentHashMap原如何保证的线程安全?

JDK1.7:使用分段锁,将一个Map分为了16个段,每个段都是一个小的hashmap,每次操作只对其中一个段加锁

JDK1.8:采用CAS+Synchronized保证线程安全,每次插入数据时判断在当前数组下标是否是第一次插入,是就通过CAS方式插入,然后判断f.hash是否=-1,是的话就说明其他线程正在进行扩容,当前线程也会参与扩容;删除方法用了synchronized修饰,保证并发下移除元素安全

8.HashTable与HashMap的区别

(1)HashTable的每个方法都用synchronized修饰,因此是线程安全的,但同时读写效率很低

(2)HashTable的Key不允许为null

(3)HashTable只对key进行一次hash,HashMap进行了两次Hash

HashTable底层使用的数组加链表

9.ArrayList和LinkedList的区别

 ArratList的底层使用动态数组,默认容量为10,当元素数量到达容量时,生成一个新的数组,大小为前一次的1.5倍,然后将原来的数组copy过来;因为数组在内存中是连续的地址,所以ArrayList查找数据更快,由于扩容机制添加数据效率更低

LinkedList的底层使用链表,在内存中是离散的,没有扩容机制;LinkedList在查找数据时需要从头遍历,所以查找慢,但是添加数据效率更高

10.如何保证ArrayList的线程安全?

(1)使用collentions.synchronizedList()方法为ArrayList加锁

(2)使用Vector,Vector底层与Arraylist相同,但是每个方法都由synchronized修饰,速度很慢

(3)使用juc下的CopyOnWriterArrayList,该类实现了读操作不加锁,写操作时为list创建一个副本,期间其它线程读取的都是原本list,写操作都在副本中进行,写入完成后,再将指针指向副本。

11.hashCode和equals

 hashCode()和equals()都是Obkect类的方法,hashCode()默认是通过地址来计算hash码,但是可能被重写过用内容来计算hash码,equals()默认通过地址判断两个对象是否相等,但是可能被重写用内容来比较两个对象

所以两个对象相等,他们的hashCode和equals一定相等,但是hashCode相等的两个对象未必相等

如果重写equals()必须重写hashCode(),比如在HashMap中,key如果是String类型,String如果只重写了equals()而没有重写hashcode()的话,则两个equals()比较为true的key,因为hashcode不同导致两个key没有出现在一个索引上,就会出现map中存在两个相同的key

12.什么是反射?

反射是通过获取类的class对象,然后动态的获取到这个类的内部结构,动态的去操作类的属性和方法。

应用场景有:要操作权限不够的类属性和方法时、实现自定义注解时、动态加载第三方jar包时、按需加载类,节省编译和初始化时间;

获取class对象的方法有:class.forName(类路径),类.class(),对象的getClass()

13.Java创建对象得五种方式?

(1)new关键字   (2)Class.newInstance  (3)Constructor.newInstance

(4)Clone方法   (5)反序列化

二、线程

1.线程池有七个参数?

corePoolSize: 线程池核心线程数最大值

maximumPoolSize: 线程池最大线程数大小

keepAliveTime: 线程池中非核心线程空闲的存活时间大小

unit: 线程空闲存活时间单位

workQueue: 存放任务的阻塞队列

threadFactory: 用于设置创建线程的工厂,可以给创建的线程设置有意义的名字,可方便排查问题。

handler: 线程池的饱和策略事件,主要有四种类型。

2.四种拒绝策略

    AbortPolicy(抛出一个异常,默认的)

    DiscardPolicy(直接丢弃任务)

    DiscardOldestPolicy(丢弃队列里最老的任务,将当前这个任务继续提交给线程池)

    CallerRunsPolicy(交给线程池调用所在的线程进行处理)

3.五种阻塞队列 (5)

    ArrayBlockingQueue(有界队列)是一个用数组实现的有界阻塞队列,按FIFO排序量。

    LinkedBlockingQueue(可设置容量队列)基于链表结构的阻塞队列,按FIFO排序任务,容量可以选择进行设置,不设置的话,将是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE,吞吐量通常要高于ArrayBlockingQuene;newFixedThreadPool线程池使用了这个队列

    DelayQueue(延迟队列)是一个任务定时周期的延迟执行的队列。根据指定的执行时间从小到大排序,否则根据插入到队列的先后排序。newScheduledThreadPool线程池使用了这个队列。

    PriorityBlockingQueue(优先级队列)是具有优先级的无界阻塞队列;

    SynchronousQueue(同步队列)一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene,newCachedThreadPool线程池使用了这个队列。

4.五种创建线程的方式池的方式:

    newFixedThreadPool (固定数目线程的线程池)

    newCachedThreadPool(可缓存线程的线程池)

    newSingleThreadExecutor(单线程的线程池)

    newScheduledThreadPool(定时及周期执行的线程池)

    new ThreadPoolExecutor() 自定义的方式创建

5.sleep和wait区别

    sleep 属于 Thread类,wait属于Object类

    wait会释放掉锁,sleep不会释放锁

    wait必须在同步代码方法和同步代码块中,sleep没有这一个限制

wait()要调用notify()或notifyall()唤醒,sleep()自动唤醒

 yield()和join()区别

yield()调用后线程进入就绪状态

A线程中调用B线程的join() ,则B执行完前A进入阻塞状态

6.保证并发安全的三大特性?

原子性:一次或多次操作在执行期间不被其他线程影响

可见性:当一个线程在工作内存修改了变量,其他线程能立刻知道**(利用内存原子操作解决或者内存屏障或者lock前缀)**

有序性:JVM对指令的优化会让指令执行顺序改变,有序性是禁止指令重排**(内存屏障)**

volatile

保证变量的可见性和有序性,不保证原子性。使用了 volatile 修饰变量后,在变量修改后会立即同步到主存中,每次用这个变量前会从主存刷新。

单例模式双重校验锁变量为什么使用 volatile 修饰? 禁止 JVM 指令重排序,new Object()分为三个步骤:为实例对象分配内存,用构造器初始化成员变量,将实例对象引用指向分配的内存;实例对象在分配内存后实才不为null。如果分配内存后还未初始化就先将实例对象指向了内存,那么此时最外层的if会判断实例对象已经不等于null就直接将实例对象返回。而此时初始化还没有完成。

7.什么是CAS锁

CAS锁可以保证原子性,思想是更新内存时会判断内存值是否被别人修改过,如果没有就直接更新。如果被修改,就重新获取值,直到更新完成为止。这样的缺点是

(1)只能支持一个变量的原子操作,不能保证整个代码块的原子操作

(2)CAS频繁失败导致CPU开销大

(3)ABS问题:线程1和线程2同时去修改一个变量,将值从A改为B,但线程1突然阻塞,此时线程将A改为B,然后线程3又将B改成A,此时线程1将A又改为B,这个过程线程2是不知道的,这就是ABA问题,可以通过版本号或时间戳解决

8.Synchronized锁原理和优化

在JDK1.6以后Synchronized引入了偏向锁、轻量级锁、重量级锁、锁的粗化、锁消除的优化。并发性能基本和Lock持平的。

    偏向锁:是不存竞争情况下,从而在后续的代码块中没有加锁解锁的开销

    轻量级锁:轻量级锁所适应的场景是线程交替执行同步块的场合

    重量级锁:重量级锁首先会经过一定次数的CAS自旋操作获取锁,如果获取失败,存在同一时间多个线程访问同一把锁的场合,就会导致轻量级锁膨胀为重量级锁。是在竞争激烈的情况下创建一个monitor对象,并且将线程挂起,而挂起就要切换到内核状态执行。从而开销非常大。

    轻量级锁:当锁是偏向锁时,有另外一个线程来访问,会撤销掉偏向锁,然后升级为轻量级锁,这个线程会通过自旋方式不断获取锁,不会阻塞,提高性能

重量级锁:轻量级锁尝试去获取到锁,如果获取失败线程就会进入阻塞状态,该锁会升级为重量级锁,重量级锁时,来竞争锁的所有线程都会阻塞,性能降低

注意,锁只能升级不能降级

9.死锁产生的4个必要条件

互斥条件:进程要求对所匹配的资源进行排他性控制,即是一段时间内某资源仅为一进程所占有

请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放

不剥夺条件:进程已获得的资源在未使用完之前不,不能剥夺,只能在使用完时有自己释放

环路等待条件:在发生死锁时,必须存在一个进程–资源得环星链

10.预防死锁

资源一次性得分配:一次性分配所有得资源,这样就不会有请求了(破坏请求条件); 只要一个资源得不到分配,也不给这个进程分配其他得资源(破坏请求保持条件)

可剥夺条件:即当某个进程获得部分资源,得不到其他得资源,则释放已有得资源(破坏补课剥夺得条件)

资源有序分配法:系统分配资源编号,每一个进程按编号递增的顺序请求资源,释放则反之(环路破坏)

11.解除死锁

剥夺资源:从其它进程剥夺足够数量的资源给死锁进程,以解除死锁状态;

撤消进程:可以直接撤消死锁进程或撤消代价最小的进程,直至有足够的资源可用,死锁状态.消除为止;所谓代价是指优先级、运行代价、进程的重要性和价值等。

12.CPU密集型和IO密集型 的线程数设置

CPU 密集型:对于这样的任务最佳的线程数为CPU核心数的1~2倍,如果设置过多的线程,就会造成不必要的CPU上下文切换,性能相对于比较低

IO密集任务:由于IO读写是比较消耗时间的,并不会特别的消耗CPU的资源。对于这种任务最大的线程数一般大于CPU核心数的很多倍。

线程数 = CPU 核心数 *(1+平均等待时间/平均工作时间)

13.进程和线程的区别,进程间如何通信

进程:系统运行的基本单位,进程在运行过程中都是相互独立,但是线程之间运行可以相互影响。

线程:独立运行的最小单位,一个进程包含多个线程且它们共享同一进程内的系统资源

进程间通过管道、 共享内存、信号量机制、消

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值