记录草稿:比较仓促 随便一写
-------------
自我介绍
-------------
面试java开发岗位
项目经验 银行信用卡业务 互联网渠道 微信小程序 支付宝 adp银行信用卡业务
k8s docker
springclould rabbitmq kafuka
网络 nginx 节点
前后分离
到达网关 网关走k8s 节点
硬件负载
软件:容器概念 扩充实例节点
-------------
问题
-------------
高并发问题:节点--> 压测预估 限流、扩容
熔断 拦截后 请求怎么返回 --> 重试机制
springcould 组件:gateway eureka 熔断器 配置中心(轻舟,阿波罗)
Nacos(阿里) 区别:集成了配置中心
分布式事务:单独处理 接口密传
redis锁 :分布式事务怎么设计的:秒杀--》单位时间内锁轮询 共享变量 队列、限流、扩容
分布式事务 cap
多线程场景:线程池 springboot 注解 配置参数 线程池的操作细节和流程
容我想一下这个流程 全局锁?
synchronized升级 串行化 指令级 升级后 锁什么?标志位 对象 悲观锁
乐观锁 有哪些 怎么用的 cas 弊端?多线程情况,aba 解决 java 原子类执行
数据库:oracle mysql 引擎innerdb
索引 类型 聚集索引、、非聚集索引
怎么判断有没有索引 explain like不会用到索引 最左原则
设计模式:工厂 单例 策略 装饰器
0代理模式:反射 解决了什么问题 事务,日志 动态代理jdk,cglib
java对象克隆 深拷贝浅拷贝
java 多态 构造方法
常用的集合 队列特点
java jdk 11 更新了什么
你还有什么问题吗
技术栈 业务方面 技术 收索引擎 平台是主要做什么
---------------
评价
---------------
技术掌握比较全面
数据库相关了解较少
对Java基础了解较少
解析问题:
第一个问题由高并发入手:
Question 1 :如何理解java高并发,如何解决,什么方式解决
面试者回答:前期压测 后期限流
网上高阶答案:大佬解决方式
解读高阶思想
- 加缓存 导致超发问题
- 加悲观锁 影响效率
- 消息队列 FIFO队列思路 队列瞬间被撑爆
- 加乐观锁 增大CPU的计算开销 相对较好
- 缓存服务器
互联网正在高速发展,使用互联网服务的用户越多,高并发的场景也变得越来越多。电商秒杀和抢购,是两个比较典型的互联网高并发场景。虽然我们解决问题的具体技术方案可能千差万别,但是遇到的挑战却是相似的,因此解决问题的思路也异曲同工。
个人整理并发解决方案。
a.应用层面:读写分离、缓存、队列、集群、令牌、系统拆分、隔离、系统升级(可水平扩容方向)。
b.时间换空间:降低单次请求时间,这样在单位时间内系统并发就会提升。
c.空间换时间:拉长整体处理业务时间,换取后台系统容量空间。
Question 2 : springcould 组件
1 eureka 和 nacos的区别
区别
2 Hystrix(熔断器)
Question 3 : 分布式事务
CAP:一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)
cp ap
Question 4 : 多线程
线程池
handler的拒绝策略:
有四种:
第一种AbortPolicy:不执行新任务,直接抛出异常,提示线程池已满
第二种DisCardPolicy:不执行新任务,也不抛出异常
第三种DisCardOldSetPolicy:将消息队列中的第一个任务替换为当前新进来的任务执行
第四种CallerRunsPolicy:直接调用execute来执行当前任务
五,四种常见的线程池:
CachedThreadPool:可缓存的线程池,该线程池中没有核心线程,非核心线程的数量为Integer.max_value,就是无限大,当有需要时创建线程来执行任务,没有需要时回收线程,适用于耗时少,任务量大的情况。
SecudleThreadPool:周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大。适用于执行周期性的任务。
SingleThreadPool:只有一条线程来执行任务,适用于有顺序的任务的应用场景。
FixedThreadPool:定长的线程池,有核心线程,核心线程的即为最大的线程数量,没有非核心线程
Question 6 : jdk新特性
引自
- jdk8
Lambda表达式
//使用java匿名内部类
Comparator<Integer> cpt = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
TreeSet<Integer> set = new TreeSet<>(cpt);
System.out.println("=========================");
//使用JDK8 lambda表达式
Comparator<Integer> cpt2 = (x,y) -> Integer.compare(x,y);
TreeSet<Integer> set2 = new TreeSet<>(cpt2);
// java7中 筛选产品为nike的
public List<Product> filterProductByColor(List<Product> list){
List<Product> prods = new ArrayList<>();
for (Product product : list){
if ("nike".equals(product.getName())){
prods.add(product);
}
}
return prods;
}
// 使用 lambda
public List<Product> filterProductByPrice(List<Product> list){
return list.stream().filter(p->"nike".equals(p.getName())).collect(Collectors.toList());
}
- 函数式接口
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
// Predicate<Integer> predicate = n -> true
// n 是一个参数传递到 Predicate 接口的 test 方法
// n 如果存在则 test 方法返回 true
System.out.println("输出所有数据:");
// 传递参数 n
eval(list, n->true);
// Predicate<Integer> predicate1 = n -> n%2 == 0
// n 是一个参数传递到 Predicate 接口的 test 方法
// 如果 n%2 为 0 test 方法返回 true
System.out.println("输出所有偶数:");
eval(list, n-> n%2 == 0 );
// Predicate<Integer> predicate2 = n -> n > 3
// n 是一个参数传递到 Predicate 接口的 test 方法
// 如果 n 大于 3 test 方法返回 true
System.out.println("输出大于 3 的所有数字:");
eval(list, n-> n > 3 );
}
public static void eval(List<Integer> list, Predicate<Integer> predicate) {
for(Integer n: list) {
if(predicate.test(n)) {
System.out.println(n + " ");
}
}
}
Predicate
接收一个值返回boolean
Predicate p = t->true;
Supplier
无接受参数返回一个值
Supplier<T> s = () -> new T();
Consumer
接受一个参数无返回值
Consumer<String> c = c -> System.out.println(s);
Function<T,R>
接受参数T 返回参数R
Function<Long,String> f = c -> String.valueof(c);
- 方法引用
静态引用:
格式:Class::static_method
List<String> list = Arrays.asList("a","b","c");
list.forEach(str -> System.out.print(str));
list.forEach(System.out::print);
构造器调用
构造器方法引用格式:Class::new,调用默认构造器
List<String> list = Arrays.asList("a","b","c");
List<Test> list.stream().map(Test::new).collect(Collectors.toList());
public class Test{
private final String desc;
public Test(String desc){
this.desc=desc;
}
}
方法调用
格式:instance::method
List<String> list = Arrays.asList("a","b","c");
Test test = new Test();
List<String> list.stream().map(test::toAdd).collect(Collectors.toList());
public class Test{
private final String desc;
public Test(String desc){
this.desc=desc;
}
public String toAdd(String desc){
return desc+"add";
}
}
- Stream API
// 使用jdk1.8中的Stream API进行集合的操作
@Test
public void test(){
// 循环过滤元素
proList.stream()
.fliter((p) -> "红色".equals(p.getColor()))
.forEach(System.out::println);
// map处理元素然后再循环遍历
proList.stream()
.map(Product::getName)
.forEach(System.out::println);
// map处理元素转换成一个List
proList.stream()
.map(Product::getName)
.collect(Collectors.toList());
}
- 接口中的默认方法和静态方法
public interface ProtocolAdaptor {
ProtocolAdaptor INSTANCE = DynamicLoader.findFirst(ProtocolAdaptor.class).orElse(null);
default ProtocolAdaptor proxy() {
return (ProtocolAdaptor) Proxy.newProxyInstance(ProtocolAdaptor.class.getClassLoader(),
new Class[]{ProtocolAdaptor.class},
(proxy, method, args) -> intercept(method, args));
}
}
- Optional
用于处理对象空指针异常
public String getDesc(Test test){
return Optional.ofNullable(test)
.map(Test::getDesc).else("");
}
- JDK 11
从Java 10开始,您可以声明没有其类型的局部变量。您只需要定义var关键字而不是类型。从Java 11开始,您还可以将其与lambda表达式一起使用,如下所示
public String sumOfString() {
BiFunction<String, String, String> func = (var x, var y) -> x + y;
return func.apply("abc", "efg");
}