JAVA面试题整理1

面试题整理

大部分参考了尚硅谷–周阳的讲解视频,这里是整理

volatile

1、线程可见性
两个线程修改同一个对象,另一个线程能感知到
2、防止指令重排
场景:new Object()、懒汉式单例、DCL
单线程能确保最终结果和代码执行逻辑是一致的
3、不保证原子性
不会被中断的操作
自增++、自减-- 不是原子操作
使用技巧:用程序的强逻辑控制多个变量的读写,比如while、if等等
更多:如果在方法中创建一个子线程,访问方法中的创建的对象,是否会有可见性问题,如果是jdk自定义的对象,可以尝试将对象的创建过程放到当前类当中

JMM内存模型

Java Memory Model
1、加锁前必须把共享变量写回主内存
2、加锁前必须把主内存最新值读取到工作内存
3、加锁解锁是同一把锁
共享变量存在于主内存,但是线程操作的是工作内存,操作完成之后写会主内存。线程操作变量之前会先比较,
要求实现:1、可见性 2、原子性 3、有序性(指的jvm指令的有序性,不是代码的顺序执行)

原子类

原理:CAS操作系统原语支持,并非代码实现(可以用代码实现),JDK8后的线程安全的容器也是这个原理,JDK7的ConcurrentHashMap用的是分段锁(Segment)
ABA问题:不是所有场景都需要解决这个问题,原子类提供了版本号的参数getStamp
AtomicReference<V>
AtomicInteger常用方法:
getAndSet、getAndIncrement

使用场景:对于长耗时任务可以使用synchronized(比如申请资源,大对象、大文件操作、容量大的容器类操作),小而快的任务可以使用原子类

synchronized

1、可重入(递归锁):可以一定程度上防止死锁
2、修饰this锁当前对象
3、修饰.class一般是静态类的锁
4、更有可能自己创建一个Object对象锁住

synchronized和Lock的区别

1、一个是关键字,一个是java接口
2、sychronzied只能是非公平的机制,Lock默认非公平但可以自己设置
3、两者都是可重入锁
4、Lock可以设置多个Condition,还可以精确唤醒,细粒度更高
5、synchronized是自动释放的锁,Lock需要手动释放
6、synchronized不能修饰变量,只能修饰方法和代码块
7、synchronized底层使用的monitor
8、Lock有超时获取和中断获取锁的方法

锁升级

偏向锁:第一个线程访问共享变量时,就会打上这个标记,不会直接去拿重量级锁
轻量级锁(CAS):自旋10次以内,或执行时间短
重量级锁:

手写自旋锁

Lock

公平锁和非公平锁

synchronized和ReentrantLock的默认情况都是非公平锁,就是指线程获取锁的时候允许插队(从其他状态恢复到RUNNABLE这一阶段),
一定是按照线程的创建顺序(这句话不对)
它在队列中的顺序去获取锁的(这个可以)

ReentrantLock
Condition
ReentrantReadWriteLock

读锁共享,只要是读操作不会互相影响
写锁互斥,不管是前面有读的操作还是写的操作都会阻塞当前写的操作

死锁怎么写,场景和原因

在一个对象锁中尝试获取另一个对象的锁
排查命令:jps -l 找到进程号和对应类的全限定类名
jstack 进程号 打印堆栈信息,找到wait的字样,确定死锁

原因有三

1、系统资源不足
2、资源分配不当
3、进程推进顺序不当

CountDownLatch

线程计数器,假设在父线程中启动了多个子线程,当这些子线程全部跑完再继续执行父线程的后续代码。

CyclicBarrier

栅栏,线程数达到指定数量才会全部放出去运行
await、countDown

Semaphore

信号量,多个共享资源互斥使用:
等到占用资源的线程释放,被阻塞的线程还可以再次获取
acquire、release

虚假唤醒

生产者和消费者

如果我们将wait放在if当中

sleep和wait的区别

1、都需要抛出InterruptionException
2、都会让当前线程blocking
3、sleep不会释放锁,wait则会释放

如何让A、B、C三个线程顺序执行

1、用join就可以实现,但是join一定会等待子线程死掉以后才会开启另一个线程,如果对细粒度要求比较高,用它不划算,而且join一定是父子线程,线程多了嵌套会比较深。

创建线程有哪些方式

1、继承线程类Thread
2、实现Runnable接口
3、实现Callable接口
4、使用线程池

线程池

底层就是阻塞队列

优势和为什么用

1、降低重复创建和销毁的性能消耗,也提高了响应速度
2、管理和调度起来方便
注意在finally中shutdown,否则停不下来

三个常用线程池

FixedThreadPool(size):固定线程数的线程池
CachedThreadPool():可扩容的
SingleThreadExecutor():单线程的
无论哪个,内部都会调用ThreadPoolExecutor构建
上述都是Executors创建出来的,正常情况生产上一个都不用。。。,原因是阻塞队列的长度是Integer.MAX_VALUE容造成OOM,我们使用ThreadPoolExcecutor去写线程池 ,代码:

BlockingQueue<Runnable> blockingQueue = new LinkedBlockingQueue<>(10);
ExecutorService threadPool = new ThreadPoolExecutor(3, 
        	6, 
        	1L, 
        	TimeUnit.SECONDS, 
        	blockingQueue, 
        	Executors.defaultThreadFactory(), 
        	new ThreadPoolExecutor.AbortPolicy());
try {
     for(int i = 0; i < 17; i ++) {
         threadPool.execute(() -> {
         	System.out.println(Thread.currentThread().getName() + " 办理业务");
         });
      }
   } finally {
            threadPool.shutdown();
   }

线程池参数考虑

CPU的核数:Runtime.getRuntime().availableProcessors();
CPU密集型:CPU核数 + 1(减少线程切换CPU)
IO密集型:CPU核数 * 2 (IO并不一定在用CPU)或者 CPU核数 / (1-阻塞系数)
阻塞系数一般为 0.8~0.9

使用无界阻塞队列会出现什么问题?
Callable和FutureTask

FutureTask只会被一个线程执行

execute和submit方法区别

无返回值和有返回值

如何让线程在一定时间内获取结果

FutureTask的get方法有超时获取

ThreadPool的7个核心参数:

前五个:
corePoolSize:核心或常驻线程数
maximumPoolSize:最大线程数,当核心线程和阻塞队列都满了,才扩容,也就是说到达最大线程数才会触发拒绝策略
keepAliveTime:多余线程存活时间
TimeUnit:时间单位
BlockingQueue:阻塞队列,阻塞的是没能进入线程池的线程
后面两个:
threadFactory:创建线程的工厂(一般默认)
handler:拒绝策略,到达最大线程数且阻塞队列已满,触发

拒绝策略

RejectedExceprionHandler
1、AbortPolicy(默认):直接抛异常
2、DiscardPolicy:直接丢弃任务
3、CallerRunsPolicy:回退给调用者线程
4、DiscardOldestPolicy:抛弃队列中等待最久的任务

阻塞队列

BlockingQueue<T>

ThreadLocal<T>

将变量与某一线程进行绑定

==和equals和hashCode

1、== 可以直接比较基本数据类型的值,如果不是基本类型,比较的是地址。
equals是Object类提供,可以被重写,如果没有重写调用的就是 ==
2、hashCode是内存地址转换的int值,没有重写过的则任何对象hashCode不相等。
一般重写eqauls也要重写hashCode
所以equals为false则hashCode可能相等,hashCode相等equals也不一定为true

Object中有哪些方法

地址与运算:equals、hashCode、
线程相关:wait、notify、notifyAll
常用:clone、toString
垃圾回收:finalize

Collection和Collections区别

Collection是列表的父接口
Collections提供了对列表和Map的操作方法

HashMap

线程不安全的具体场景
说下实现原理
描述一下put方法的实现流程

HashSet

线程不安全、不能存null、会去重、无法保证输出顺序。
它的底层数据结构就是HashMap,HashSet的Value是不可变的PRESENT对象(Object),就是利用HashMap的key实现的

ConcurrentHashMap

ArrayList

线程不安全,安全化的几种方式:

// Vector是线程安全的,读写都同步
List<T> list = new Vector<>();
// 只有写是同步的
List<T> list = Collections.synchronizedList(new ArrayList<>());
List<T> list = new CopyOnWriteArrayList<>();

ArrayList为什么自己实现序列化方法

内部的data数组是transient修饰的,因为它本身可以扩容,直接序列化内部数组,会有空的元素,增加了网络IO,自己序列化可以按照size准确输出想要的内容。

ArrayList和LinkedList区别

Collection和Collections

CopyOnWriteArrayList

原理:读写分离的思想

CopyOnWriteArraySet

异常

常见异常 :
NullPointerException、
InterruptionException、
ConcurrentModificationException、
在普通循环中增删非线程安全集合的元素会有这个异常
IOException、

反射

注解
注解的顺序问题

JDK8和JDK7有那些区别,实际工作有没有用到,怎么用的

1、JDK8取消了永久代,使用元空间(本机物理内存)


设计模式

基本设计原则
工厂
单例

spring框架注册bean的默认方式(singleton)

代理
装饰者模式
适配器模式

算法

快排
二分查找
统计string中重复字符串和次数

JVM

结构图说明

JVM内存分布
堆内存分布
堆内存分布

类加载器
双亲委派机制
GC垃圾回收

1、引用计数,难以解决循环依赖
2、复制算法(年轻代)s0和s1
3、标记清除
节约空间,容易造成碎片
4、标记整理(老年代)
移动对象需要成本

如何确定垃圾?GCRoots是什么?

哪些可以作为GCRoots:
1、虚拟机栈(栈帧中的局部变量)中引用的对象
2、类静态属性引用对象
3、方法区中常量引用的对象(static final
4、本地方法栈中的JNI(Native方法)引用的对象
有了这个就进行可达性分析

查看默认JVM参数配置和调优配置

参数类型:(多个命令之间空格间隔)
1、标配参数,每个版本的java都会有:-version、-help、
2、X参数:-Xint解释执行、-Xcomp编译执行、-Xmixed混合执行
3、XX参数:
a、布尔类型:-XX:+PrintGCDetails
b、KV设值类型:-XX:属性key=属性值value
-XX:MetaspaceSize=512m(设置元空间大小)
c、jinfo举例:
jinfo -flag PrintGCDetails 进程号
jinfo -flag MetaspaceSize 进程号(21807104)
jinfo -flag MaxTenuringThreshold 进程号 (查看最大年龄)
-Xms等价于-XX:InitialHeapSize (Runtime.getRuntime().totalMemory())
-Xmx等价于-XX:MaxHeapSize (Runtime.getRuntime().maxMemory())
java -XX:+PrintFlagsInitial -version = 是默认的没改过的,:=是修改过的
java -XX:+PrintCommandLineFlags -version
常用参数列举:
-Xms:初始堆内存大小
-Xmx:最大堆内存大小
-Xss:栈内存大小(在windows下,用jinfo -flag ThreadStackSize查看是0,)
-Xmn:设置年轻代大小
-XX:MetaspaceSize 设置元空间大小
-XX:+PrintGCDetails 打印垃圾回收具体情况
-XX:SurvivorRatio 伊甸园区和幸存者区的比例(默认是8:1:1)
-XX:NewRatio 老生代和新年代占比 (默认2:1)
-XX:MaxTenuringThreshold 设置垃圾的最大年龄(默认15,只能修改为15及以下)

JVM老年代和新生代的比例

2:1

强软弱虚四种引用

整体架构:在这里插入图片描述
强引用:不会被回收,即使OOM。(Object o = new Object())
软引用(SoftReference):内存足够就不会回收,不足就会回收。通常用于缓存,加载图片
弱引用(WeakReference):内存充足也会被回收
虚引用(PhantomReference):任何时候都可能被回收,必须和ReferenceQueue一起使用,get永远是null
WeakHashMap<>

谈谈OOM

java.lang.StackOverflowError
递归次数过多
java.lang.OutOfMemoryError:Java heap space
对象过多、或者大对象(比如很大的字节数组)
java.lang.OutOfMemoryError:GC overhead limit exceeded
对象生产过多,多数时间用于GC,且回收了不到2%(比如容器中对象很多)
java.lang.OutOfMemoryError:Direct buffer memory
可能使用了堆外内存(ByteBuffer.allocateDirect(capability))速度快(nio)
java.lang.OutOfMemoryError:unable to create new native thread
线程创建过多,解决办法:
1、减少线程创建数量
2、修改linux配置(默认1024)
vim /etc/security/limits.d/90-nproc.conf
java.lang.OutOfMemoryError:Metaspace
静态类过多或者使用反射不断加载静态类

YGC和FGC发生的具体场景
jstack,jmap,jutil分别的意义?如何线上排查JVM的相关问题?
垃圾回收器和垃圾回收算法

在这里插入图片描述

4种主要垃圾回收器:Serial(串行)、Parallel(并行)、CMS(并发标记回收)、G1、(ZGC)
Serial单线程回收,会暂停用户线程,不适合服务器
Parallel多线程回收,暂停时间缩短
CMS用户和垃圾回收可以交替执行不一定并行,不会暂停用户线程或者暂停时间很短
回收算法:
引用计数:
复制拷贝:新生代
标记清除:有内存碎片
标记整理:老年代

查看默认垃圾回收器

java -XX:+PrintCommandLineFlags -version
指定垃圾回收器:(-XX:+)
1、UseSerialGC,---------SerialOldGC(不再推荐)
相关名词:DefNew----Default New Generation、Tenured----Old这些词汇用+PrintGCDetails可以看到,分别指代的就是年轻代和老年代的GC回收器
2、(串行的多线程版)UseParNewGC,--------SerialOldGC(不再推荐)
相关名词:Parallel New Generation、Tenured
3、UseParallelGC,----------UseParallelOldGC,关注吞吐量(JDK8默认的方式)
相关名词:PSYoungGen----Parallel Scavenge、ParOldGen----Parallel Old Generation
4、UseConcMarkSweepGC,并发标记清除(针对老年代)
5、UseG1GC
四个回收步骤:
a、初始标记(CMS initial mark)会暂停用户线程
b、并发标记(CMS concurrent mark)和用户线程一起
c、重新标记(CMS remark)会暂停用户线程
d、并发清除(CMS concurrent sweep)和用户线程一起
解决内存碎片:-XX:CMSFullGCsBeforeCompaction 0(默认值是0)多少次GC会进行一次整理
6、UseG1GC
这个应该需要深入一点,暂不写粗制滥造的。

如何选择
单CPU或小内存,单机程序:+XX:UseSerialGC
多CPU,大吞吐量,后台计算型应用:-XX:+UseParallelGC或-XX:UseParrallelOldGC
多CPU,追求低停顿时间,快速响应如互联网应用:-XX:+UseConcMarkSweepGC或-XX:+ParNewGC

参数新生代垃圾回收器新生代算法老年代垃圾回收器老年代算法
-XX:+UseSerialGCSerialGC复制SerialOldGC标整
-XX:+UseParNewGCParNew复制SerialOldGC标整
-XX:+UseParallelGC/-XX:+UseParrallelOldGCParallel[Scavenge]复制ParallelOld标整
-XX:+UseConcMarkSweepGCParNew复制CMS + SerialOld的收集器组合(SerialOld作为CMS出错的后备收集器)标清
-XX:+UseG1GCG1整体上采用标记-整理算法局部是通过复制算法,不会产生内存碎片

启动命令: (nohup) java -server -Xms 10m -Xmx 10m -XX:+UseG1GC -jar … &

JDK和JRE的区别

框架

SpringBoot四大属性注入注解

@ConfigurationProperties
既可以设置属性注入的前缀prefix,可以设置自定义的yml配置文件
@Bean
@Configuration
@EnableConfigurationProperties

@Bean和@Compnent区别
手动获取Bean的方法
@Component
public class BeanUtils implements BeanFactoryAware {
	private BeanFactory beanFactory;
	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		this.beanFactory = beanFactory;
	}
	public void getBean(String name) {
		return beanFactory.getBean(name);
	}
}
Bean的生命周期

IoC控制反转,是从容器角度的说法,将bean的创建和获取交给容器管理
DI依赖注入,从bean或者使用角度的说法,给某个属性注入对象

Spring提供的一些拓展点

1、BeanFactoryAware----setBeanFactory(BeanFactory beanFactory)
2、InitializingBean----afterPropertiesSet()可以用于属性检查
3、InstantiationAwareBeanProcessor----postProcessBeforeInstantiation(Class<?> beanClass, String beanName)实例化Bean之前执行
----postProcessAfterInstantiation(Object bean, String beanName)实例化Bean之后执行
4、BeanPostProcessor----postProcessBeforeInitialization(Object bean, String beanName)
----postProcessAfterInitialization(Object bean, String beanName)

SpringBoot运行机制
Spring如何解决循环依赖
SpringIoC容器描述和理解

实际上就是一个Map的单例池,通过Type或者name找到这个对象。

Spring事务
传播机制

REQUIRED(默认):加入当前事务
SUPPOTRS:有事务就支持,没有则不会开启
MANDATORY:
REQUIRES_NEW:每次都新开启一个事务,挂起当前事务
NOT_SUPPORTED:
NEVER:
NESTED:

常见使用方式

@Transactional默认遇到异常会回滚

细化和手动控制
Spring AOP

使用它的主要目的是给一系列对象增强一些相同的功能,比如日志、事务

术语

切面(Aspect):一个关注点的模块化
连接点(Joinpoint):一个方法的执行
切入点(Pointcut):匹配连接点的断言,这个是关键
引入(Introduction):
目标对象(Target Object)
AOP代理(AOP Proxy)
织入(Weaving):
通知(Advice):即你想增强的功能
我自己想象的抽象视图:

MyBatis
批量插入
 <insert id="insertBatch"**>
 INSERT INTO user (col1, col2, col3) 
 VALUES
 <foreach collection="list" item="user" seperator=",">
 (#{user.name}, #{user.password}, #{user.sex})
 </foreach>
 </insert>

Redis

为什么会使用它

可以从redis本身的特性回答:
1、key-value数据库中速度最快、综合排名最高,和前端的json对象结构一致
2、内存级的数据库访问速度快,尤其是读取速度
3、作为独立的中间件可以集群化,后期有分布式场景易扩展

Redis基本数据类型
Redis超时的方案
双写一致性
缓存穿透和缓存雪崩
分布式锁
设计方案

MySQL

表设计三范式

第一范式:
列都是不可再分数据。
第二范式:
每个表只描述一件事
第三范式:
不存在对非主键列的传递依赖

MySQL常用函数

count()、max()、min()、abs(x)、pi()、sqrt()、mod(x,y)、round、floor、ceil
concat、trim

介绍一下存储引擎和区别

show engines;
查看表emp的存储引擎:show create table emp;
MyISAM不支持事务和外键,select和insert速度快,不支持行级锁,默认使用表级锁
InnoDB支持事务,MySQL默认,有提交和回滚的能力,采用行级锁
MEMORY内存级别,速度快
MERGE一组MyISAM表的组合

SQL语句分类

数据定义语言DDL(Data Definition Language)
DDL
CREATE,DROP,ALTER

create table dept(
	deptno int primary key,
	dname varchar(20)) engine=myisam;

数据查询语言DQL(Data Query Language)
SELECT
数据操纵语言DML(Data Manipulation Language)
INSERT,UPDATE,DELETE
数据控制功能DCL(Data Control Language)
GRANT,REVOKE,COMMIT,ROLLBACK

数据文件

db.opt:记录库的默认使用的字符集和校验规则
frm:表结构文件
ibd:数据文件

基本使用
建表语句
use databaseName;
create table tableName(
	id int primary key,
	name varchar(20),
	age int) engine=innodb charset=utf8;
)
mysql批量插入
insert into tbl_name(col1,col2,col3,col_varname) 
values(val1,val2,val3,@varname),
(val21,val22,val23,@varname),
(val31,val32,val33,@varname)
MySQL锁的分类

表级锁:
行级锁:
页面锁:

隔离级别描述

读未提交:(脏读)事务还未提交就可以访问已执行语句的结果
读已提交:(不可重复读)只能能读取已提交事务的结果,同一个事务两次selelct结果不一致
可重复读(MySQL默认的隔离级别):(幻读)同一个事务两次select结果的记录数不一致
串行化:(只能顺序执行的事务)

事务的特征

ACID:原子性(Atomicty)、一致性(Consistency)、隔离性(Lsolation)和持续性(Durability)

如果自己写一个存储引擎如何实现
日志

查看日志位置
show variables where variable_name=“log_error” or variable_name=“log_warnings”;

  • 错误日志(error log)

  • 通用查询日志(General query log)
    show variables like “%general%”

  • 二进制日志(binary log)
    记录了对MySQL数据库执行的更改操作,并且记录了语句的发生时间、执行市场;但是它不记录select、show等不修改数据库的操作。主要用于数据库恢复和主从复制。
    show variables like “%log_bin%”; // 查看是否开启
    show variables like “%binlog%”; // 参数查看
    show binary logs; // 查看日志信息

  • 慢查询日志(Slow query log)
    show variables like ‘%slow_query%’; // 是否开启
    show variables like ‘%long_query_time%’; // 时长

索引
  • 从索引结构来说:B Tree索引、Hash索引、FULLTEXT全文索引、R Tree索引
  • 从应用来说:普通索引、唯一索引、主键索引、复合索引
  • 从索引存储关系来说:聚簇(聚集)索引、非聚簇(聚集)索引
普通索引
  • CREATE INDEX <索引的名字> ON tableName (colName);
  • ALTER TABLE tableName ADD INDEX [索引的名字] (字段名);
  • CREATE TABLE tableName ([…], INDEX [索引的名字] (字段的名字));
唯一索引

CREATE UNIQUE INDEX 其余同上

主键索引
聚簇索引和非聚簇索引区别
索引原理和最左匹配原则

只会按照左侧第一个建立索引的列进行扫描,只会在order by和group by这些语句中生效,和and的次序无关。
like 开头不

执行计划
sql优化的经历
什么样的情况会造成慢SQL

分布式

SpringCloud
常用组件

一代:
eureka:注册中心、拉模式、AP
hystrix:熔断器
ribbon:负载均衡
feign:hystrix + ribbon
gateway:网关
springcloud config:注册中心
二代:
nacos:注册中心、推模式、AP/CP


搜索引擎


大数据


linux

常用命令

top:看CPU和内存占用
uptime:
vmstat:查看CPU
free:
df:
iostat:
ifstat:
pidstst:


自我介绍

不用重复简历里有的基本信息,直接说常用技术和最近的项目就可以。

问面试官的问题

一般问公司业务,会使用哪些技术框架,是否有完整且明确的晋升线路和技术培养方案,可以问一个项目会分配多少开发人员和项目紧急情况,从侧面观察公司规模、人事管理和是否加班等。

查漏补缺

MyBatis现在应该不怎么问了,还有SpringMVC执行流程啥的,比较基础,但是仍然会考察java基本功,会深度化。
人工智能暂不了解。

最后

该文档已经上传到gitee,前后整理耗时较长,后面会首先跟新gitee,再来补充博客。欢迎大家指正和提交:https://gitee.com/BenJerry/interview.git
,每天有时间就会跟新。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值