Java开发工程师面试总结

1. Java基础

1.1 接口与抽象类的区别

  1. 接口里必须是抽象方法,抽象类可以没有抽象方法;
  2. 接口可以继承多个父接口,抽象类只能被单继承;
  3. 接口里的变量必须被static,final修饰并初始化,抽象类里可以普通的成员变量;

1.2 重写与重载的区别

  1. 重载是表示一个类中可以有多个方法名相同,参数不同(参数个数,参数类型,参数顺序不同);
  2. 重写是子类对父类方法的一种重写, 访问权限不能是private的;

1.3 集合

Map和collection是所有集合的父接口;

  • Collection-set/List
  1. List-Vector,ArrayList,LinkedList 有序的,可以重复
  2. set-HashSet,TreeSet,LinkedHashSet 无序的,不可以重复
  • Map
  1. HashMap线程不同步,线程不安全,允许null作为key;
  2. HashTable使用了syschonized,线程安全,每次需要锁住整个结构,不允许null作为key;
  3. ConcurrentHashMap锁的粒度很细,分为16个桶,只锁当前用到的桶;

HashMap的底层原理:
Java8之前是数组+链表,Java8之后是数组+链表+红黑树;
数组中都是key-value的实例,java8之前叫entry,Java8之后叫node;
put的时候是通过key的hash值去计算index位置;
数组的长度是有限的,当hash值一样时,就有了链表;
扩容机制:负载因子是0.75f,创建新数组,长度为原来的2倍,重新计算hash值然后插入,长度扩大后,hash规则随之变化;
插入链表的方式Java8之前是头插法,Java8后是尾插法;头插会改变链表的顺序,尾插则不会,就不会出现链表成环的问题,死循环;
HashMap不能用在多线程中,底层代码get/put并没有加同步锁,线程不安全;
初始化长度为16,源代码中1<<4 为16;
Q:为啥我们重写equals方法的时候需要重写hashCode方法呢?用HashMap说明一下?
为重写equals方法时,我们用的object类的equals方法,比较的是两个对象的内存地址,计算key的hashCode值来定位index,当值相同时,利用equals方法判断是否相同,重写hashCode方法,保证相同的对象返回相同的hash值;
hash冲突,利用链表来解决,当碰撞发生时,对象会被存储在链表的下一节点;
原理是 首先当调用put方法时,用hashCode方法计算index(bucket桶)的位置来存储对象,获取对象时用equals方法找到正确的对象;

ConcurrentHashMap的实现原理:hashEntry用来封装表的键值对和segment可重入锁,每个segment保护一个HashEntry数组的元素;java7实行分段锁;java8采用table数组作为锁,对每一行进行加锁,数组,链表加红黑树(超过长度后就到红黑树)结构,采用Synchronize进行同步锁粒度降低和CAS

1.4 多线程

创建线程的方式

  • 继承Thread类
  • 实现Runnable接口,无返回结果
  • 实现Callable接口,有返回值

调用Thread.start()启动线程,run()执行线程的运行代码;

线程和进程的区别
进程是一个系统进行资源分配的独立单位
线程是进程的一个实体。一个进程可以有多个线程;

线程是怎样造成死锁的?

  • 一个资源每次只能被一个线程使用;
  • 线程已经获得的资源。在未使用完前,不能进行剥夺;
  • 线程在请求资源阻塞时,对已有的资源保持不放;
  • 若干线程循环等待资源关系;

如何避免死锁?
指定获取锁的顺序;只有获取A锁的线程才能获取B锁;

sleep()和wait()的区别?
sleep()是Thread类的方法,睡眠多少毫秒,线程阻塞,到时间会接触阻塞,阻塞时不会释放锁;
wait()是Object类的方法,必须与synchronized一起使用,线程阻塞时会释放互斥锁,notify()唤醒线程;

线程池
四种线程池

  • newFixedThreadPool 固定线程数目的
  • newCachedThreadPool 可缓存的
  • newSingleThreadPool 一个单线程的
  • newScheduledThreadPool 支持定时及周期性的任务执行的

创建线程池的方式
用Excutors类的四个方法,ExecutorService;
自己定义newThreadPoolExecutor;构造方法参数说明

  • corePoolSize 核心线程数
  • maximumPoolSize 线程池最大容纳线程数
  • keepAliveTime 非核心线程的闲置超时时间
  • unit 指定keepAliveTime 单位
  • workQueue 线程队列 linkedBlockingQueue Array…

ThreadFactoryBuilder;

保证多线程安全
使用安全类 java.util.concurrent下的原子类AtomicInteger
concurrentHashMap

1.6 反射

运行时可以获取类的信息(属性,构造器,方法,注解);运行时动态创建对象;

Class clazz = Class.forName(className)
Constuctor constructor = clazz.getConstuctor();
constructor.newInstance();
Class<> xxx = XX.class; 已经声明过类型;
Class<> xx = xx.getClass(); 获取该实例的对象
Class.forName() 通过全限定名来获取对象

场景
spring读取配置文件到容器
jdbc连接数据库驱动类时

2. Spring框架

2.1 IOC

2.2 AOP

2.3 事务

3. Spring Cloud微服务

4.MySQL数据库

4.1 SQL调优

创建索引,避免全表扫描,经常检索的字段创建索引;
避免在索引上使用计算;
使用表的别名
考虑创建中间表

4.2 数据库性能优化方案

  1. 代码层面的优化 ;
  2. 定位慢sql ,慢查询日志定位到出问题的sql,使用explain工具进行比对和调优;
  3. 合理使用索引,可以使用的操作符 between, in, >,like不以%开头,不能用的操作符 not in, like以%开头;
  4. 容易导致索引失效 ,避免使用or来连接,不做列运算
  5. 数据超百万可能需要分库分表;
  6. 缓存查询,先到缓存查询,再到数据库查询;

4.3 NoSQL的特性和使用场景

对exception做的监控系统,如果在应用系统发生严重故障的时候,可能会短时间产生大量exception数据,这个时候如果选用MySQL,会造成MySQL的瞬间写压力飙升,容易导致MySQL服务器的性能急剧恶化以及主从同步延迟之类的问题,这种场景就比较适合用Hbase类似的NoSQL来存储。

5.分布式

5.1 分布式缓存

静态RAM加速,通过内存或其他高速存储来加速;
缓存更新模式

  • Cache aside 缓存读取失败,查询db,写入缓存;更新:直接更新到DB;
  • read/write through 读取写入都是用了缓存存储;
  • write behind caching 这种模式下所有的操作都走缓存,缓存里的数据再通过异步的方式同步到数据库里面。所以系统的写性能能够大大提升了。

缓存失效策略

  • 主动失效 系统自带主动检查是否失效的机制
  • 被动失效 通过访问缓存对象才去检查是否失效

缓存淘汰策略

  • FIFO 先进先出
  • LRU 最近最久没有使用
  • LFU 最近最少使用

分布式缓存常见问题

  • 缓存穿透 db中不存在数据,穿过缓存查db,网络攻击;
    解决:包装对象;
  • 缓存击穿 在缓存失效的时候,大量的请求,造成db压力瞬间过大;
    解决:在查询db前,使用分布式锁锁住服务;
  • 缓存雪崩 大部分缓存同时失效,造成服务器性能急剧下降;
    解决:失效时间为基本时间+随机时间;

5.2 消息

5.3 分布式锁

6.大数据生态体系

6.1 Flink

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值