├── .gitignore ├── 1.Java Based.md ├── 10.Spring.md ├── 11.Spring Boot.md ├── 12.Dubbo.md ├── 13.Spring Cloud.md ├── 14.Message Queue.md ├── 15.Mybatis.md ├── 16.Zookeeper.md ├── 17.Maven.md ├── 18.Open Question.md ├── 19.Distribute_MicroService.md ├── 2.Java Concurrent.md ├── 20.Java Performance.md ├── 21. Nginx.md ├── 22. ShardingJDBC.md ├── 23.ES.md ├── 3.Java Lock.md ├── 4.JVM.md ├── 5.Java Reflect_IO.md ├── 6.Design Pattern.md ├── 7.Data Structure.md ├── 8.DataBase.md ├── 9.Redis.md ├── Bug分享 └── 1.Lock Transactional.md ├── Other Interview.md ├── README.md ├── media ├── 006y8mN6ly1g8xdtvdrcyj31jy06adjs.jpg ├── 006y8mN6ly1g8xdwn9fq8j31ki0r8nfb.jpg ├── 006y8mN6ly1g8xe5miksnj30w201w74f.jpg ├── 006y8mN6ly1g8xetz5v5jj31so04sgmx.jpg ├── 006y8mN6ly1g8xf7p2kg1j30h004omxn.jpg ├── 006y8mN6ly1g8xfievgsdj31kk03awf9.jpg ├── 006y8mN6ly1g8xfrevz58j30v602yaah.jpg ├── 01.png ├── 252461fbb6d64d3dbc1914b7eadbfb86.jpeg ├── 36465fd7d91b3a4aeb3b28c3777649e6.jpeg ├── 4935fcc0a209fd1d4b70cade94986f59.jpeg ├── 6650aa32de0def76db0e4c5228619aef.jpeg ├── IMG_082BD9A3B24F-1.jpeg ├── distributed-system-request-sequence.png ├── dubbo-keep-connection.png ├── dubbo-not-keep-connection.png ├── dubbo-service-invoke-road.png ├── image-20191114193034340-3731511.png ├── image-20191114193034340.png ├── image-20191114194022209.png ├── image-20191114194055084.png ├── image-20191114194125306.png ├── image-20191114194139915.png ├── image-20191114194157527.png ├── image-20191114194224919.png ├── image-20191114194236837.png ├── image-20191114194247158.png ├── image-20191114194335314.png ├── image-20191114194356825.png ├── image-20191114194415039.png ├── image-20191114194430674.png ├── image-20191114194439833.png ├── image-20191114194449725.png ├── image-20191114194503521.png ├── image-20191114194740033.png ├── image-20191114194815842.png ├── image-20191114194918523.png ├── image-20191114194952076.png ├── image-20191114195007116.png ├── image-20191114195010955.png ├── image-20191114195023197.png ├── image-20191114195045400.png ├── image-20191114195113356.png ├── image-20191114195209444.png ├── image-20191114195228161.png ├── image-20191114195305300.png ├── image-20191114195334883.png ├── image-20191114195346681.png ├── image-20191114195421280.png ├── image-20191114195509483.png ├── image-20191114200036013.png ├── image-20191114203012441.png ├── image-20191114203913199.png ├── image-20191114204200585.png └── serialize-deserialize.png ├── 大厂面经 ├── Interview Exp1.md ├── Interview Exp2.md ├── Interview Exp3.md ├── Interview Exp4.md ├── Interview Exp5.md ├── Interview Exp6.md ├── Interview Exp7.md ├── Interview Exp8.md ├── Interview Exp9.md └── media │ ├── 006tNbRwgy1g9ux8rjqfwj30g70fhdm4.jpg │ ├── 006tNbRwgy1g9ux8w8661j30hc08u403.jpg │ ├── 006tNbRwgy1g9ux90cmw4j30h803iab4.jpg │ ├── 006tNbRwgy1g9ux96vbg7j30i407sgmz.jpg │ ├── 006tNbRwgy1g9ux9a6cfxj308b049gm0.jpg │ ├── 006tNbRwgy1g9ux9dyrn5j30ax0a43zm.jpg │ ├── 640-20191213213310547 │ ├── 640-20191213213310630 │ ├── 640-20191213213310681 │ ├── 640-20191213213310684 │ ├── 640-20191213213310692 │ ├── 640-20191213213310736 │ ├── 640-20191213213310747 │ ├── 640-20191213213310749 │ ├── 640-20191213213310764 │ ├── 640-20191213213310784 │ ├── 640-20191213213310802 │ ├── 640-20191213213310803 │ ├── 640-20191213213310828 │ ├── 640-20191213213310899 │ ├── 640-20191213213322270 │ ├── 640-20191213213322273 │ ├── 640-20191213213322276 │ ├── 640-20191213213322278 │ ├── 640-20191213213322285 │ ├── 640-20191213213322329 │ ├── 640-20191213213322353 │ ├── 640-20191213213327997 │ ├── 640-20191213213328002 │ ├── 640-20191213213328002-6244008 │ ├── 640-20191213213328002-6244008. │ ├── 640-20191213213328004 │ ├── 640-20191213213328010 │ ├── 640-20191213213328034 │ ├── 640-20191213213328040 │ ├── 640-20191213213349268 │ ├── 640-20191213213349274 │ ├── 640-20191213213349278 │ ├── 640-20191213213349286 │ ├── 640-20191213213349309 │ ├── 640-20191213213349324 │ ├── 640-20191213213349350 │ ├── 640-20191213213358869 │ ├── 640-20191213213358870 │ ├── 640-20191213213358873 │ ├── 640-20191213213358875 │ ├── 640-20191213213358889 │ ├── 640-20191213213358898 │ ├── 640-20191213213358910 │ ├── 640-20191213213554931 │ ├── 640-20191213213602270 │ ├── image-20191213092233778.png │ ├── image-20191213092446557.png │ ├── image-20191213093127572.png │ ├── image-20191213093225461.png │ ├── image-20191213093243414.png │ ├── image-20191213093257647.png │ ├── image-20191213213621574.png │ ├── image-20191213213740733.png │ ├── image-20191213213805148.png │ ├── image-20191213213928996.png │ ├── image-20191213214128396.png │ └── image-20191213214535975.png ├── 学习资料 ├── Learning.md └── media │ ├── 006tNbRwly1ga6z6ig0vej30ck0ju75u.jpg │ ├── image-20191223212524703.png │ ├── image-20191223212734977.png │ ├── image-20191223212741417.png │ ├── image-20191223212859627.png │ ├── image-20191223212918623.png │ ├── image-20191223212936257.png │ ├── image-20191223212952306.png │ ├── image-20191223213011426.png │ ├── image-20191223213029704.png │ └── image-20191223213731596.png └── 源码分析 ├── CompletableFuture.md ├── ConcurrentLinkedQueue.md ├── Flow_SubmissionPublisher.md ├── Helpers.md ├── LinkedBlockingQueue.md ├── LinkedHashMap.md ├── LongAdder.md ├── Spring Boot └── Spring Boot Reference 2.6.11 .pdf ├── SynchronousQueue.md ├── ThreadLocal.md ├── Unsafe.md └── media ├── 5cd1ba2adf7c0-20191214003715601.jpg ├── 5cd1ba2adf7c0.jpg ├── 5cd1ba2d418b6-20191214003733877.jpg └── 5cd1ba2d418b6.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | /notes/ 2 | boostnote.json 3 | .DS_Store 4 | yuque.yml 5 | ._* 6 | ._1 7 | -------------------------------------------------------------------------------- /10.Spring.md: -------------------------------------------------------------------------------- 1 | # 10.Spring 2 | 3 | [TOC] 4 | 5 | > 《精通Spring 4.x 企业应用开发实战》、《Spring技术内幕:深入Spring架构与设计原理》、《Spring源码深度解析》 6 | 7 | ### BeanFactory 与ApplicationContext 是干什么的,两者的区别 8 | 9 | BeanFactory、ApplicationContext都代表容器,BeanFactory是一个基础接口,实现了容器基础的功能,ApplicationContext是容器的高级形态,增加了许多了特性,顶级父类是BeanFactory。 10 | 11 | 跟FactoryBean的区别是: 12 | 13 | FactoryBean 是一个Bean,用于创建或修饰其他的Bean实例,典型应用是AOP代理类,使用'&'获取FactoryBean本身,通过getObject来获取原来的Bean实例 14 | 15 | BeanFactory 是一个工厂,是容器的顶层接口 16 | 17 | ### BeanPostProcessor 的实现 18 | 19 | Bean的后置处理器,是一个监听器,可以监听容器触发的事件。将它向IOC容器注册后,容器中管理的Bean具备了接收IOC容器事件回调的能力。BeanPostProcessor是一个接口类,有两个接口方法,postProcessBeforeInitialization提供Bean初始化前的回调入口;postProcessAfterInitialization 提供Bean初始化后的回调入口`AbstractAutowireCapableBeanFactory#initializeBean`,这个类可以对项目中的Bean进行修饰,所有Bean都会调用该实现。 20 | 21 | ### BeanDefinition 的实现 22 | 23 | BeanDefinition抽象了对Bean的定义,其是容器实现依赖反转功能的核心数据结构 24 | 25 | ### Spring IOC容器的实现 26 | 27 | Spring提供了各种各样的容器,有DefaultListableBeanFactory、FileSystemXmlApplicationContext等,这些容器都是基于BeanFactory,BeanFactory实现了容器的基础功能,包括containsBean能够判断容器是否含有指定名称的Bean,getBean获取指定名称参数的Bean等。 28 | 29 | Spring通过`refresh()`方法对容器进行初始化和资源的载入 30 | 31 | 首先通过ResourceLoader的Resource接口定位到存储Bean信息的路径 32 | 33 | 第二个过程是BeanDefinition载入,把定义好的Bean表示成IOC容器的内部数据结构BeanDefinition,通过定义BeanDefinition来管理应用的各种对象及依赖关系,其是容器实现依赖反转功能的核心数据结构 34 | 35 | 第三个过程是BeanDefinition注册,容器解析得到BeanDefinition后,需要在容器中注册,这由IOC实现BeanDefinitionRegistry接口来实现,注册过程是IOC容器内部维护了一个ConcurrentHasmap来保存得到的BeanDefinition。如果某些Bean设置了lazyinit属性,Bean的依赖注入会在这个过程预先完成,而不需要等到第一次使用Bean的时候才触发。 36 | 37 | ### Spring DI(依赖注入)的实现 38 | 39 | Spring 的依赖注入发生在以下两种情况: 40 | 41 | 1. 用户第一次调用`getBean()`方法 42 | 2. bean配置了lazy-init=false,容器会在解析注册Bean定义的时候进行预实例化,触发依赖注入 43 | 44 | getBean()方法定义在BeanFactory接口中,具体实现在子类AbstractBeanFactory中,过程如下: 45 | 46 | 1. getBean()方法最终是委托给doGetBean方法来实例化Bean,doGetBean方法会先从缓存中找是否有创建过,没有再从父工厂中去查找 47 | 2. 如果父工厂中没有找到,会根据Bean定义的模式来创建Bean,单例模式的Bean会先从缓存中查找,确保只创建一次,原型模式的Bean每次都会创建,其他模式根据配置的不同生命周期来选择合适的方法创建。创建的具体方法通过匿名类中getObject,并委托给createBean来完成bean的实例化。 48 | 49 | 3. 在createBean中,先对Bean进行一些准备工作,然后会应用配置的前后处理器,如果创建成功就直接返回该代理Bean 50 | 4. 没有创建代理Bean的话,会创建指定的Bean实例,委托给doCreateBean完成,该过程会通过提前实例化依赖Bean,并写入缓存来解决Bean的循环依赖 51 | 5. 通过populateBean注入Bean属性,并调用init-method初始化方法 52 | 6. 注册实例化的Bean 53 | 54 | ### Spring如何解决循环依赖问题(三级缓存) 55 | 56 | 比如A依赖B, B依赖A. 57 | 58 | 创建A的时候,会把A对应的ObjectFactory放入缓存中,当注入的时候发现需要B, 就会去调用B对象,B对象会先从singletonObjects 查找,没有再从earlySingletonObjects找,还没有就会调用singletonFactory创建对象B,B对象也是先从singletonObjects,earlySingletonObjects,singletonFactories三个缓存中搜索,只要找到就返回,相关方法`AbstractBeanFactory.doGetBean()` 59 | 60 | ### Spring Bean 生命周期 61 | 62 | 1. Bean实例的创建 63 | 2. 为Bean实例设置属性 64 | 3. 调用Bean的初始化方法 65 | 4. 应用可以通过IOC容器使用Bean 66 | 5. 当容器关闭时,调用Bean的销毁方法 67 | 68 | ### Spring Bean的作用域,默认是哪个? 69 | 70 | Singleton: 单例模式,IOC容器中只会存在一个共享的Bean实例,是Spring的默认模式; 71 | 72 | prototype: 原型模式,每次从IOC容器获取Bean的时候,都会创建一个新的Bean实例; 73 | 74 | request: 每次请求都生成一个实例; 75 | 76 | session: 在一次请求会话中,容器返回该Bean的同一实例,不同的Session请求不同的实例,实例仅在该Session内有效,请求结束,则实例销毁; 77 | 78 | globalsession: 全局的session中,容器返回该Bean的同一个实例,仅在portlet context 有效 79 | 80 | ### AOP两种代理方式 81 | 82 | AOP面向切面编程,可以通过预编译和运行时动态代理,实现在不修改源代码的情况下给程序动态添加功能。 83 | 84 | 程序入口是:`AbstractAutowireCapableBeanFactory -> doCreateBean -> initializeBean -> applyBeanPostProcessorsAfterInitialization` 85 | 86 | 默认策略是如果目标类是接口,则使用JDK动态代理技术,否则使用Cglib来生成代理 87 | 88 | 1. JDK 动态代理 89 | 90 | 主要涉及java.lang.reflect中的两个类,Proxy 和 InvocationHandler 91 | 92 | InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编辑在一起。只能为实现接口的类创建代理。 93 | 94 | 2. Cglib 代理 95 | 96 | 是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展Java类与实现Java接口,Cglib封装了asm,可以在运行期动态生成新的class。可以是普通类,也可以是实现接口的类 97 | 98 | ### Spring AOP实现原理 99 | 100 | 通过JDK代理,和CGLIB代理两种方式生成动态代理,构造不同的回调方法来对拦截器链的调用,比如JdkDynamicAopProxy的invoke方法,Cglib2AopProxy中的DynamicAdvisedInterceptor的intercept方法,首先获取配置的拦截器链,通过ReflectiveMethodInvocation的proceed方法实现对拦截器链的调用, 首先需要根据配置来对拦截器进行匹配,匹配成功后,拦截器发挥作用,在对拦截器调用完成后,再对目标对象的方法调用,这样一个普通的Java对象的功能就得到了增强 101 | 102 | ### 哪些方法不能被AOP增强 103 | 104 | 1. 基于JDK代理,除public外的其他所有方法,包括public static也不能被增强 105 | 2. 基于CGLIB代理,由于其通过生成目标类子类的方式来增强,因此不能被子类继承的方法都不能被增强,private、static、final 方法 106 | 107 | ### AOP 切点函数 108 | 109 | | 类别 | 函数 | 入参 | 说明 | 110 | | ------------------ | ------------- | -------------- | ------------------------------------------------------------ | 111 | | 方法切入点函数 | execution() | 方法匹配模式串 | 满足某一匹配模式的所有目标类方法连接点。
如execution(* greetTo(..)) 表示所有目标类中的greetTo()方法 | 112 | | | @annotation() | 方法注解类名 | 标注了特定注解的目标类方法连接点。
如@annotation(com.smart.anno.NeedTest)表示任何标注了@NeedTest注解的目标类方法 | 113 | | 方法入参切入点函数 | args() | 类名 | 通过判断目标类方法运行时入参对象的类型定义指定连接点。
如args(com.smart.Waiter)表示所有有且仅有一个按类型匹配于Waiter入参的方法 | 114 | | | @args() | 类型注解类名 | 通过判断目标类方法运行时入参对象的类是否标注特定注解来指定连接点。
如@args(com.smart.Monitorable)表示任何这样的一个目标方法:它有一个入参且`入参对象的类`标注@Monitorable注解 | 115 | | 目标类切点函数 | within() | 类名匹配串 | 表示特定域下的所有连接点。
如within(com.smart.service.\*) 表示com.smart.service 包中的所有连接点,即包中所有类的所有方法;
而within(com.smart.service.\*Service)表示在com.smart.service包中所有以Service结尾的类的所有连接点 | 116 | | | target() | 类名 | 假如目标类按类型匹配于指定类,则目标类的所有连接点匹配这个切点
如通过target(com.smart.Waiter),Waiter及Waiter实现类NaiveWaiter中的所有连接点都匹配该切点 | 117 | | | @within() | 类型注解类名 | 假如目标类型按类型匹配于某个类A, 且类A标注了特定注解,则目标类的所有连接点匹配该切点
如@within(com.smart.Monitorable) 假如Waiter类标注了@Monitorable注解,则Waiter的所有连接点都匹配该切点,`说是这个注解也会匹配Waiter的子类,但试了后并没有用,Spring 5.1` | 118 | | | @target | 类型注解类名 | 假如目标类标注了特定注解,则目标类的所有连接点都匹配该切点。
如@target(com.smart.Monitorable),假如NaiveWaiter标注了@Monitorable,则NaiveWaiter的所有连接点都匹配这个切点 | 119 | | 代理类切点函数 | this() | 类名 | 代理类按类型匹配于指定类,则被代理的目标类的所有连接点都匹配该切点。
如this(com.smart.Seller) 匹配任何运行期对象为Seller类型的类 | 120 | 121 | 122 | 123 | ### 六种增强类型 124 | 125 | 1. @Before 前置增强,相当于BeforeAdvice 126 | 2. @AfterReturning 后置增强,相当于AfterReturningAdvice 127 | 3. @Around 环绕增强,相当于MethodInterceptor 128 | 4. @AfterThrowing 抛出增强,相当于ThrowsAdvice 129 | 5. @AfterFinal增强,不管抛出异常还是正常退出,都会执行,没有对应的增强接口,一般用于释放资源 130 | 6. @DeclareParents 引介增强,相当于IntroductionInterceptor 131 | 132 | ### Spring MVC运行流程 133 | 134 | image-20190910155238902 135 | 136 | 1. 客户端请求到DispatcherServlet 137 | 2. DispatcherServlet根据请求地址查询映射处理器HandleMapping,获取Handler 138 | 3. 请求HandlerAdatper执行Handler 139 | 4. 执行相应的Controller方法,执行完毕返回ModelAndView 140 | 5. 通过ViewResolver解析视图,返回View 141 | 6. 渲染视图,将Model数据转换为Response响应 142 | 7. 将结果返回给客户端 143 | 144 | `2,3 两步都在DispatcherServlet -> doDispatch中进行处理` 145 | 146 | ### Spring MVC 启动流程 147 | 148 | 1. 在Tomcat启动的时候,ServletContext 会根据web.xml加载ContextLoaderListener,继而通过ContextLoaderListener 载入IOC容器,具体过程有ContextLoader完成,这个IOC容器是在Web环境下使用的WebApplicationContext, 这个容器在后面的DispatcherServlet中作为双亲根上下文来使用 149 | 2. IOC容器加载完成后,开始加载DIspatcherServlet,这是Spring MVC的核心,由`HttpServletBean -> initServeltBean`启动(HttpServletBean是DispatcherServlet的父类,HttpServletBean继承了HttpServlet),最终调用`DispatcherServlet -> initStrategies` 方法对HandlerMapping、ViewResolver等进行初始化,至此,DispatcherServelt就初始化完成了,它持有一个第一步完成的上下文作为根上下文,以自己的Servlet名称命名的IOC容器,这个容器是一个WebApplicationContext对象。 150 | 151 | ### Spring 事务实现方式、事务的传播机制、默认的事务类别· 152 | 153 | 1. 事务实现方式 154 | 155 | - 声明式,在xml文件中通过tx:advice来配置事务 156 | - 注解式,在xml文件中定一个事务管理对象(DataSourceTransactionManager),然后加入\, 这样就可以使用@Transactional注解配置事务 157 | 158 | 2. 事务的传播机制 159 | 160 | 一共7种事务传播行为,相关code: `AbstractPlatformTransactionManager -> getTransaction` 161 | 162 | - PROPAGATION_REQUIRED 163 | 164 | 如果当前没有事务,则新建一个事务;如果已经存在一个事务,则加入到这个事务中,这也是默认事务类别 165 | 166 | - PROPAGATION_SUPPORTS 167 | 168 | 支持当前事务。如果当前没有事务,则以非事务方式执行 169 | 170 | - PROPAGATION_MANDATORY 171 | 172 | 使用当前事务。如果当前没有事务,则抛出异常 173 | 174 | - PROPAGATION_REQUIRES_NEW 175 | 176 | 新建事务。如果当前存在事务,则把当前事务挂起 177 | 178 | - PROPAGATION_NOT_SUPPORTED 179 | 180 | 以非事务方式执行操作。如果当前存在事务,则把当前事务挂起 181 | 182 | - PROPAGATION_NEVER 183 | 184 | 以非事务方式执行。如果当前存在事务,则抛出异常 185 | 186 | - PROPAGATION_NESTED 187 | 188 | 如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作 189 | 190 | ### Spring 事务模版 191 | 192 | TransactionTemplate 事务模版是对原始事务管理方式的封装,原始事务管理是基于`TransactionDefinition`、`PlatformTransactionManager`、`TransactionStatus` 的编程式事务 193 | 194 | 事务模版主要通过execute(TransactionCallback action)来执行事务,TransactionCallback 有两种方式一种是有返回值TransactionCallback,一种是没有返回值TransactionCallbackWithoutResult。 195 | 196 | ### Spring 事务底层原理 197 | 198 | 1. 事务的准备 199 | 200 | 在声明式事务处理中,需要Ioc容器配置TransactionProxyFactoryBean,其父类AbstractSingletonProxyFactoryBean实现了InitializingBeean接口,因此在初始化过程中会调用afterPropertiesSet方法,这个方法实例化了ProxyFactory, 并为其设置了通知,目标对象后,最终返回Proxy代理对象,对象建立起来后,在调用其代理方法的时候,会调用相应的TransactionInterceptor拦截器,在这个调用中,会根据TransactionAttribute配置的事务属性进行配置,为事务处理做好准备 201 | 202 | 2. 事务拦截器实现 203 | 204 | 经过TransactionProxyFactoryBean的AOP包装后,此时如果对目标对象进行方法调用,实际上起作用的是一个Proxy代理对象,拦截器会拦截其中的事务处理,在调用Proxy对象的代理方法时会触发invoke回调,其中会根据事务属性配置决定具体用哪一个PlatformTransactionManager来完成事务操作 205 | 206 | ### Spring事务失效(事务嵌套), JDK动态代理给Spring事务埋下的坑 207 | 208 | https://blog.csdn.net/bntx2jsqfehy7/article/details/79040349 209 | 210 | ### Spring 单例实现原理 211 | 212 | 在创建Bean的时候`AbstractAutowireCapableBeanFactory -> doCreateBea0` 通过BeanDefinition 设置的是否单例属性,来判断该bean是否是单例,如果是单例就 根据Bean的名称删除bean缓存中同名称的bean,再在后面重新创建bean. 213 | 214 | ### Spring 中有哪些不同类型的事件 215 | 216 | 对于ApplicationEvent 类和在ApplicationContext接口中处理的事件,如果一个Bean实现了ApplicationListener接口,但一个ApplicationEvent发布后,Bean会自动被通知 217 | 218 | ```java 219 | public class AllApplicationEventListener implements ApplicationListener { 220 | @Override 221 | public void onApplicationEvent(ApplicationEvent applicationEvent) { 222 | 223 | } 224 | } 225 | ``` 226 | 227 | Spring 提供了5种标准的事件: 228 | 229 | 1. 上下文更新事件(ContextRefreshedEvent):该事件会在ApplicationContext被初始化或者更新时发布。也可以在ConfigurableApplicationContext 接口中的refresh()方法时触发 230 | 2. 上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始或重新开始容器时触发该事件 231 | 3. 上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件 232 | 4. 上下文关闭事件(ContextCloseEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁 233 | 5. 请求处理事件(RequestHandledEvent):在Web应用中,当一个Http请求(Request)结束时触发该事件 234 | 6. 自定义事件继承ApplicationEvent, 在通过ApplicationContext 接口的publishEvent()方法发布事件 235 | 236 | ### Spring 扩展点总结 237 | 238 | 可以看看这篇文章:https://www.diguage.com/post/spring-extensions-overview/ 239 | 240 | ### 缓存的一些策略有哪几种类型 241 | 242 | 常见的有FIFO、LRU、LFU、TTL、TTI 243 | 244 | FIFO:先进先出策略,先放入缓存的数据先被移除 245 | 246 | LRU:最久未使用策略,即使用时间距离现在最久的那个数据被移除 247 | 248 | LFU:最近最少使用策略,即一定时间段内使用次数(频率)最少的那个数据被移除 249 | 250 | TTL:存活期,即从缓存中创建时间点开始直至到期的一个时间段(不管这个时间段内有没有访问都将过期) 251 | 252 | TTI:空闲期,即一个数据多久没被访问就从缓存中移除的时间 253 | 254 | 255 | 256 | ### Spring Cache 注解 257 | 258 | | 注解 | 用法 | 259 | | ------------ | -------------------------------------------------- | 260 | | @Cacheable | 先查询缓存,如果没有执行方法并缓存结果,用于取数据 | 261 | | @CachePut | 先执行方法,然后将返回值放入缓存,用于更新数据 | 262 | | @CacheEvict | 删除缓存,用于删除数据 | 263 | | @Caching | 基于前3者的注解数组,多用于一个类有多种实现的情况 | 264 | | @CacheConfig | 全局缓存注解,用于类上 | 265 | 266 | 缓存管理器 267 | 268 | 1. SimpleCacheManager 可以配置缓存列表名称,基本的缓存管理器 269 | 2. NoOpCacheManager 不缓存任何数据,用于测试 270 | 3. ConcurrentMapCacheManager 不用配置缓存列表,自动生成缓存ConcurrentMapCache 271 | 4. CompositeCacheManager 可以将不同的缓存管理器组合在一起,不同的缓存使用不同的缓存管理器,并且可以通过fallbackToNoOpCache属性回到NoOpCacheManager 272 | 273 | 274 | 275 | ### Spring BeanUtils bean拷贝工具用过吗?它是浅拷贝还是深拷贝?怎么实现的?有没有什么坑?其他还有什么bean 拷贝的方法,是浅拷贝还是深拷贝?如何实现深拷贝? 276 | 277 | BeanUtils是通过java反射机制来实现从源Bean将属性的值赋值到目标Bean中,两个Bean是不同的对象,但如果Bean中的属性是引用对象,那么copy的只是引用地址。其他的CGLIB的BeanCopier,Apache的BeanUtils都不是真正的深拷贝。 278 | 279 | 要实现真正的深度copy,需要将bean转化成json,再将json转化成目标bean。或者使用流的方法,将源bean转化成流,再从流读取bean。 280 | 281 | ```java 282 | public class User implements Serializable { 283 | private int id; 284 | private String userName; 285 | 286 | public User myCopy() { 287 | User copy = null; 288 | try { 289 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 290 | ObjectOutputStream oos = new ObjectOutputStream(baos); 291 | oos.writeObject(this); 292 | //将流序列化成对象 293 | ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 294 | ObjectInputStream ois = new ObjectInputStream(bais); 295 | copy = (User)ois.readObject(); 296 | } catch(Exception ex) { 297 | ex.printStackTrace(); 298 | } 299 | } 300 | } 301 | ``` 302 | 303 | -------------------------------------------------------------------------------- /11.Spring Boot.md: -------------------------------------------------------------------------------- 1 | # 11.Spring Boot 2 | 3 | > 这里我找了一些个人感觉容易问到的面试题 4 | 5 | ### 什么是 Spring Boot? 6 | 7 | Spring Boot是 Spring 的子项目,正如其名字,提供 Spring 的引导( **Boot** )的功能。 8 | 9 | 通过 Spring Boot ,我们开发者可以快速配置 Spring 项目,引入各种 Spring MVC、Spring Transaction、Spring AOP、MyBatis 等等框架,而无需不断重复编写繁重的 Spring 配置,降低了 Spring 的使用成本。 10 | 11 | 12 | 13 | ### Spring Boot启动流程 14 | 15 | 1. 启动类里面调用SpringApplication.run方法 16 | 2. 在run方法中,首先构造SpringApplication对象,然后再调用run方法 17 | 3. 在构造SpringApplication对象中,做了如下工作 18 | - 将sources放入primarySources变量中 19 | - 判断webApplication是什么类型的 20 | - 设置ApplicationContextInitializer,ApplicationListener,通过加载META-INF/spring.factories中配置的类 21 | - 找到main方法找到启动主类 22 | 23 | 4. run方法中,做的工作 24 | 25 | - StopWatch主要是监控启动过程,统计启动时间,检测应用是否已经启动或者停止。 26 | 27 | - 加载SpringApplicationRunListener(也是通过META-INF/spring.factories),默认加载的是EventPublishingRunListener 28 | 29 | - 调用RunListener.starting()方法。 30 | 31 | - 根据args创建应用参数解析器ApplicationArguments; 32 | 33 | - 准备环境变量:获取环境变量environment,将应用参数放入到环境变量持有对象中,监听器监听环境变量对象的变化(listener.environmentPrepared) 34 | 35 | - 打印Banner信息(SpringBootBanner) 36 | 37 | - 创建SpringBoot的应用上下文(AnnotationConfigEmbeddedWebApplicationContext) 38 | 39 | - prepareContext上下文之前的准备 40 | 41 | - refreshContext刷新上下文 42 | 43 | - afterRefresh(ApplicationRunner,CommandLineRunner接口实现类的启动) 44 | 45 | - 返回上下文对象 46 | 47 | 48 | 49 | ### Spring Boot启动的时候会加载哪些包? 50 | 51 | 在web项目中,会在Maven中配置 spring-boot-starter-web 包,该包中包含了spring-core、spring-content、servlet、tomcat、jackson、HikariCP、junit、jdbc、slf4j 等 52 | 53 | 54 | 55 | ### 如何重新加载 Spring Boot 上的更改,而无需重新启动服务器? 56 | 57 | - 【推荐】`spring-boot-devtools` 插件。注意,这个工具需要配置 IDEA 的自动编译。 58 | 59 | - Spring Loaded 插件。 60 | 61 | `Spring Boot 2.X 后,官方宣布不再支持 Spring Loaded 插件 的更新,所以基本可以无视它了。` 62 | 63 | - [JRebel](https://www.jianshu.com/p/bab43eaa4e14) 插件,需要付费。 64 | 65 | - 使用插件化开发,插件化代码使用手动注册Bean的方式 66 | 67 | 关于如何使用 `spring-boot-devtools` 和 Spring Loaded 插件,可以看看 [《Spring Boot 学习笔记:Spring Boot Developer Tools 与热部署》](https://segmentfault.com/a/1190000014488100) 。 68 | 69 | 70 | 71 | ### 什么是 Spring Boot 自动配置? 72 | 73 | 1. Spring Boot 在启动时扫描项目所依赖的 jar 包,寻找包含`spring.factories` 文件的 jar 包。 74 | 2. 根据 `spring.factories` 配置加载 AutoConfigure 类。 75 | 3. 根据 `@Conditional` 等条件注解的条件,进行自动配置并将 Bean 注入 Spring IoC 中。 76 | 77 | https://my.oschina.net/itsaysay/blog/3011826 78 | 79 | -------------------------------------------------------------------------------- /12.Dubbo.md: -------------------------------------------------------------------------------- 1 | # 12.Dubbo 2 | 3 | > 最好的文档:http://dubbo.apache.org/zh-cn/docs/user/quick-start.html 4 | 5 | ### Dubbo SPI的理解 6 | 7 | Dubbo SPI 跟Java SPI很相似,Java SPI是Java内置的一种服务提供发现功能,一种动态替换发现机制。 8 | 9 | Java SPI使用方法: 10 | 11 | 1. 在META-INF/services 目录下放置配置文件,文件名是接口全路径名,文件内部是要实现接口的实现类全路径名,编码用UTF-8 12 | 2. 使用ServiceLoad.load(xx.class)调用 13 | 14 | Dubbo比Java 增加了: 15 | 16 | 1. 可以方便地获取某一个想要的扩展实现 17 | 2. 对于扩展实现IOC依赖注入功能 18 | 3. @SPI声明一个扩展接口,@Adaptive用在方法上,表示自动生成和编译一个动态的Adaptive类,如果用在类上表示一个装饰模式的类 19 | 20 | Dubbo 通过ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension()方法进行加载,每个SPI接口(@SPI注解的接口)都会产生一个ExtensionLoader扩展加载器实例,保存在名为EXTENSION_LOADERS的ConcureentMap中,通过扩展加载器调用getAdaptiveExtension()方法来获得自适应对象,并注入对象依赖属性 21 | 22 | Dubbo扩展接口文件放在META-INF/dubbo 目录下,文件名是接口全路径名,文件内部是接口实现类的全路径名 23 | 24 | ### Dubbo 基本原理、执行流程 25 | 26 | - 基本原理 27 | 28 | 1. service 层,接口层,给服务提供者和消费者来实现的 29 | 30 | 2. config 层,配置层,主要是对 dubbo 进行各种配置的 31 | 32 | 3. proxy 层,服务代理层,无论是 consumer 还是 provider,dubbo 都会给你生成代理,代理之间进行网络通信 33 | 34 | 4. registry 层,服务注册层,负责服务的注册与发现 35 | 5. cluster 层,集群层,封装多个服务提供者的路由以及负载均衡,将多个实例组合成一个服务 36 | 6. monitor 层,监控层,对 rpc 接口的调用次数和调用时间进行监控 37 | 7. protocal 层,远程调用层,封装 rpc 调用 38 | 8. exchange 层,信息交换层,封装请求响应模式,同步转异步 39 | 9. transport 层,网络传输层,抽象 mina 和 netty 为统一接口 40 | 10. serialize 层,数据序列化层 41 | 42 | - 执行流程 43 | 1. 服务容器Container负责启动加载运行服务提供者Provider,根据Provider配置文件根据协议发布服务,完成服务初始化 44 | 2. 在Provider(服务提供者)启动时,根据配置中的Registry地址连接注册中心,将Provider的服务信息发布到注册中心 45 | 3. Consumer(消费者)启动时,根据消费者配置文件中的服务引用信息,连接到注册中心,向注册中心订阅自己所需的服务 46 | 4. 注册中心根据服务订阅关系,返回Provider地址列表给Consumer,如果有变更,注册中心会推送最新的服务地址信息给Consumer 47 | 5. Consumer调用远程服务时,根据路由策略,先从缓存的Provider地址列表中选择一台进行,跨进程调用服务,假如调用失败,再重新选择其他调用 48 | 6. 服务Provider和Consumer,会在内存中记录调用次数和调用时间,每分钟发送一次统计数据到Monitor 49 | 50 | ### Dubbo 负载均衡策略、集群策略 51 | 52 | 负载均衡策略: 53 | 54 | 1. RoundRobinLoadBalance 权重轮询算法,按照公约后的权重设置轮询比例,把来自用户的请求轮流分配给内部的服务器 55 | 2. LeastActiveLoadBalance 最少活跃调用数均衡算法,活跃数是指调用前后计数差,使慢的机器收到的更少 56 | 3. ConsistenHashLoadBalance 一致性Hash算法,相同参数的请求总是发到同一个提供者 57 | 4. RandomLoadBlance 随机均衡算法,按权重设置随机概率,如果每个提供者的权重都相同,那么随机选一个,如果权重不同,则先累加权重值,从0~累加权重值选一个随机数,判断该随机数落在哪个提供者上 58 | 59 | 集群容错策略: 60 | 61 | 1. FailoverCluster: 失败转移,当出现失败时,重试其他服务器,通常用于读操作,但重试会带来更长延迟,默认集群策略 62 | 2. FailfastCluster: 快速失败,只发起一次调用,失败立即报错,通常用于非幂等性操作 63 | 3. FailbackCluster: 失败自动恢复, 对于Invoker调用失败,后台记录失败请求,任务定时重发,通常用于通知 64 | 4. BroadcastCluster: 广播调用,遍历所有Invokers,如果调用其中某个invoker报错,则catch住异常,这样就不影响其他invoker调用 65 | 5. AvailableCluster: 获取可用调用,遍历所有Invokers并判断Invoker.isAvalible,只要有一个为true就直接调用返回,不管成不成功 66 | 6. FailsafeCluster: 失败安全,出现异常时,直接忽略,通常用于写入审计日志等操作 67 | 7. ForkingCluster: 并且调用,只要一个成功即返回,通常用于实时性要求较高的操作,但需要更多的服务资源 68 | 8. MergeableCluster: 分组聚合,按组合并返回结果,比如某个服务接口有多种实现,可以用group区分,调用者调用多种实现并将得到的结果合并 69 | 70 | ### 注册中心挂了还可以通信吗? 71 | 72 | 可以。对于正在运行的 Consumer 调用 Provider 是不需要经过注册中心,所以不受影响。并且,Consumer 进程中,内存已经缓存了 Provider 列表。 73 | 74 | 那么,此时 Provider 如果下线呢?如果 Provider 是**正常关闭**,它会主动且直接对和其处于连接中的 Consumer 们,发送一条“我要关闭”了的消息。那么,Consumer 们就不会调用该 Provider ,而调用其它的 Provider 。 75 | 76 | 另外,因为 Consumer 也会持久化 Provider 列表到本地文件。所以,此处如果 Consumer 重启,依然能够通过本地缓存的文件,获得到 Provider 列表。 77 | 78 | 再另外,一般情况下,注册中心是一个集群,如果一个节点挂了,Dubbo Consumer 和 Provider 将自动切换到集群的另外一个节点上。 79 | 80 | 81 | 82 | ### dubbo 支持哪些通信协议?支持哪些序列化协议?说一下 Hessian 的数据结构? 83 | 84 | **序列化**,就是把数据结构或者是一些对象,转换为二进制串的过程,而**反序列化**是将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程。 85 | 86 | ![serialize-deserialize](https://tva1.sinaimg.cn/large/006tNbRwly1gaf4l46as0j30a805wt8k.jpg) 87 | 88 | dubbo 支持不同的通信协议 89 | 90 | - dubbo 协议 91 | 92 | **默认**就是走 dubbo 协议,单一长连接,进行的是 NIO 异步通信,基于 hessian 作为序列化协议。使用的场景是:传输数据量小(每次请求在 100kb 以内),但是并发量很高。 93 | 94 | 为了要支持高并发场景,一般是服务提供者就几台机器,但是服务消费者有上百台,可能每天调用量达到上亿次!此时用长连接是最合适的,就是跟每个服务消费者维持一个长连接就可以,可能总共就 100 个连接。然后后面直接基于长连接 NIO 异步通信,可以支撑高并发请求。 95 | 96 | 长连接,通俗点说,就是建立连接过后可以持续发送请求,无须再建立连接。 97 | 98 | ![dubbo-keep-connection](https://tva1.sinaimg.cn/large/006tNbRwly1gaf4l1da8nj30cn0a1glk.jpg) 99 | 100 | 而短连接,每次要发送请求之前,需要先重新建立一次连接。 101 | 102 | ![dubbo-not-keep-connection](https://tva1.sinaimg.cn/large/006tNbRwly1gaf4kykcovj30c909xq2s.jpg) 103 | 104 | - rmi 协议 105 | 106 | 走 Java 二进制序列化,多个短连接,适合消费者和提供者数量差不多的情况,适用于文件的传输,一般较少用。 107 | 108 | - hessian 协议 109 | 110 | 走 hessian 序列化协议,多个短连接,适用于提供者数量比消费者数量还多的情况,适用于文件的传输,一般较少用。 111 | 112 | - http 协议 113 | 114 | 走 json 序列化。 115 | 116 | - webservice 117 | 118 | 走 SOAP 文本序列化。 119 | 120 | 121 | 122 | dubbo 支持的序列化协议 123 | 124 | dubbo 支持 hession、Java 二进制序列化、json、SOAP 文本序列化多种序列化协议。但是 hessian 是其默认的序列化协议。 125 | 126 | 127 | 128 | 说一下 Hessian 的数据结构 129 | 130 | Hessian 的对象序列化机制有 8 种原始类型: 131 | 132 | - 原始二进制数据 133 | - boolean 134 | - 64-bit date(64 位毫秒值的日期) 135 | - 64-bit double 136 | - 32-bit int 137 | - 64-bit long 138 | - null 139 | - UTF-8 编码的 string 140 | 141 | 另外还包括 3 种递归类型: 142 | 143 | - list for lists and arrays 144 | - map for maps and dictionaries 145 | - object for objects 146 | 147 | 还有一种特殊的类型: 148 | 149 | - ref:用来表示对共享对象的引用。 150 | 151 | 152 | 153 | ### 如何基于 dubbo 进行服务治理、服务降级、失败重试以及超时重试? 154 | 155 | ### 服务治理 156 | 157 | 1. 调用链路自动生成 158 | 159 | 一个大型的分布式系统,或者说是用现在流行的微服务架构来说吧,**分布式系统由大量的服务组成**。那么这些服务之间互相是如何调用的?调用链路是啥?说实话,几乎到后面没人搞的清楚了,因为服务实在太多了,可能几百个甚至几千个服务。 160 | 161 | 那就需要基于 dubbo 做的分布式系统中,对各个服务之间的调用自动记录下来,然后自动将**各个服务之间的依赖关系和调用链路生成出来**,做成一张图,显示出来,大家才可以看到对吧。 162 | 163 | ![dubbo-service-invoke-road](https://tva1.sinaimg.cn/large/006tNbRwly1gaf4koexwoj30d40cfq2u.jpg) 164 | 165 | 2. 服务访问压力以及时长统计 166 | 167 | 需要自动统计**各个接口和服务之间的调用次数以及访问延时**,而且要分成两个级别。 168 | 169 | - 一个级别是接口粒度,就是每个服务的每个接口每天被调用多少次,TP50/TP90/TP99,三个档次的请求延时分别是多少; 170 | - 第二个级别是从源头入口开始,一个完整的请求链路经过几十个服务之后,完成一次请求,每天全链路走多少次,全链路请求延时的 TP50/TP90/TP99,分别是多少。 171 | 172 | 这些东西都搞定了之后,后面才可以来看当前系统的压力主要在哪里,如何来扩容和优化啊。 173 | 174 | 3. 其它 175 | 176 | - 服务分层(避免循环依赖) 177 | - 调用链路失败监控和报警 178 | - 服务鉴权 179 | - 每个服务的可用性的监控(接口调用成功率?几个 9?99.99%,99.9%,99%) 180 | 181 | ### 服务降级 182 | 183 | 比如说服务 A 调用服务 B,结果服务 B 挂掉了,服务 A 重试几次调用服务 B,还是不行,那么直接降级,走一个备用的逻辑,给用户返回响应。 184 | 185 | 举个栗子,我们有接口 `HelloService`。`HelloServiceImpl` 有该接口的具体实现。 186 | 187 | ```xml 188 | public interface HelloService { 189 | void sayHello(); 190 | } 191 | 192 | public class HelloServiceImpl implements HelloService { 193 | public void sayHello() { 194 | System.out.println("hello world......"); 195 | } 196 | } 197 | 198 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | ``` 225 | 226 | 我们调用接口失败的时候,可以通过 `mock` 统一返回 null。 227 | 228 | mock 的值也可以修改为 true,然后再跟接口同一个路径下实现一个 Mock 类,命名规则是 “接口名称+`Mock`” 后缀。然后在 Mock 类里实现自己的降级逻辑。 229 | 230 | ``` 231 | public class HelloServiceMock implements HelloService { 232 | public void sayHello() { 233 | // 降级逻辑 234 | } 235 | } 236 | ``` 237 | 238 | ### 失败重试和超时重试 239 | 240 | 所谓失败重试,就是 consumer 调用 provider 要是失败了,比如抛异常了,此时应该是可以重试的,或者调用超时了也可以重试。配置如下: 241 | 242 | ``` 243 | 244 | ``` 245 | 246 | 举个栗子。 247 | 248 | 某个服务的接口,要耗费 5s,你这边不能干等着,你这边配置了 timeout 之后,我等待 2s,还没返回,我直接就撤了,不能干等你。 249 | 250 | 可以结合你们公司具体的场景来说说你是怎么设置这些参数的: 251 | 252 | - `timeout`:一般设置为 `200ms`,我们认为不能超过 `200ms` 还没返回。 253 | - `retries`:设置 retries,一般是在读请求的时候,比如你要查询个数据,你可以设置个 retries,如果第一次没读到,报错,重试指定的次数,尝试再次读取。 -------------------------------------------------------------------------------- /13.Spring Cloud.md: -------------------------------------------------------------------------------- 1 | # 13.Spring Cloud 2 | 3 | ### Spring Cloud 核心功能是什么? 4 | 5 | Spring Cloud 主要提供了如下核心的功能: 6 | 7 | - Distributed/versioned configuration 分布式/版本化的配置管理 8 | - Service registration and discovery 服务注册与服务发现 9 | - Routing 路由 10 | - Service-to-service calls 端到端的调用 11 | - Load balancing 负载均衡 12 | - Circuit Breakers 断路器 13 | - Global locks 全局锁 14 | - Leadership election and cluster state 选举与集群状态管理 15 | - Distributed messaging 分布式消息 16 | 17 | ### Spring Cloud 有哪些组件? 18 | 19 | 脑图如下: 20 | 21 | ![Spring Cloud的 组件](https://itsaysay-1313174343.cos.ap-shanghai.myqcloud.com/blog/68747470733a2f2f747661312e73696e61696d672e636e2f6c617267652f303036744e6252776c7931676166346c6171676c766a33306873306573337a342e6a7067.jpeg) 22 | 23 | 由于 [Spring Cloud Netflix](https://github.com/spring-cloud/spring-cloud-netflix) 要进入维护模式,下面是一些可以替代组件 24 | 25 | | | Netflix | 阿里 | 其它 | 26 | | -------- | ------- | -------- | ------------------------------------------------------------ | 27 | | 注册中心 | Eureka | Nacos | Zookeeper、Consul、Etcd | 28 | | 熔断器 | Hystrix | Sentinel | Resilience4j | 29 | | 网关 | Zuul | 暂无 | Spring Cloud Gateway | 30 | | 负载均衡 | Ribbon | Dubbo | [`spring-cloud-loadbalancer`](https://github.com/spring-cloud/spring-cloud-commons/tree/master/spring-cloud-loadbalancer) | 31 | 32 | ### Spring Cloud 和 Spring Boot 的区别和关系? 33 | 34 | 1. Spring Boot 专注于快速方便的开发单个个体微服务。 35 | 2. Spring Cloud 是关注全局的微服务协调整理治理框架以及一整套的落地解决方案,它将 Spring Boot 开发的一个个单体微服务整合并管理起来,为各个微服务之间提供:配置管理,服务发现,断路器,路由,微代理,事件总线等的集成服务。 36 | 3. Spring Boot 可以离开 Spring Cloud 独立使用,但是 Spring Cloud 离不开 Spring Boot ,属于依赖的关系。 37 | 38 | 总结: 39 | 40 | - Spring Boot ,专注于快速,方便的开发单个微服务个体。 41 | - Spring Cloud ,关注全局的服务治理框架。 42 | 43 | ### 有哪些可以作为Spring Cloud的注册中心 44 | 45 | 在 Spring Cloud 中,能够使用的注册中心,还是比较多的,如下: 46 | 47 | - [`spring-cloud-netflix-eureka-server`](https://github.com/spring-cloud/spring-cloud-netflix/tree/master/spring-cloud-netflix-eureka-server) 和 [`spring-cloud-netflix-eureka-client`](https://github.com/spring-cloud/spring-cloud-netflix/tree/master/spring-cloud-netflix-eureka-server) ,基于 Eureka 实现。 48 | - [`spring-cloud-alibaba-nacos-discovery`](https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-nacos-discovery) ,基于 Nacos 实现。 49 | - [`spring-cloud-zookeeper-discovery`](https://github.com/spring-cloud/spring-cloud-zookeeper/tree/master/spring-cloud-zookeeper-discovery) ,基于 Zookeeper 实现。 50 | - … 等等 51 | 52 | 以上的实现,都是基于 [`spring-cloud-commons`](https://github.com/spring-cloud/spring-cloud-commons) 的 [`discovery`](https://github.com/spring-cloud/spring-cloud-commons/blob/master/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/) 的 [DiscoveryClient](https://github.com/spring-cloud/spring-cloud-commons/blob/master/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/DiscoveryClient.java) 接口,实现统一的客户端的注册发现。 53 | 54 | ### SpringCloud的注册和发现流程,以Eureka为注册中心 55 | 56 | img 57 | 58 | 1. 服务启动时会生成服务的基本信息对象InstanceInfo,然后再启动时注册到服务治理中心 59 | 2. 服务注册完成后,会从服务治理中心拉取所有的服务信息,缓存在本地 60 | 3. 之后服务会根据配置的指定间隔时间发送一个心跳信息,续约服务 61 | 4. 如果服务治理中心在90s内没有收到一个服务的续约,就会认为服务已经挂了,会把服务注册信息删除 62 | 5. 服务停止前,会主动发送一个停止请求,服务治理中心会删除这个服务的信息 63 | 6. 如果Eureka收到的心跳包不足正常值的85%(可配置)就会进入自我保护模式,这种模式,Eureka不会删除任何服务信息 64 | 65 | ### Eureka 如何实现集群? 66 | 67 | 详细文章:[《配置 Eureka Server 集群》](https://www.jianshu.com/p/5d5b2cf7d476) 68 | 69 | 此处,也很容易引申出一个问题,为什么 Eureka 被设计成 AP 的系统,答案可以看看 [《为什么不应该使用 ZooKeeper 做服务发现》](http://dockone.io/article/78) 。 70 | 71 | ### 聊聊 Eureka 缓存机制? 72 | 73 | [《Eureka 缓存细节以及生产环境的最佳配置》](http://bhsc881114.github.io/2018/04/01/eureka缓存细节以及生产环境的最佳配置/) 74 | 75 | ### 什么是 Eureka 自我保护机制? 76 | 77 | [《[Spring Cloud\] Eureka 的自我保护模式及相关问题》](https://blog.csdn.net/t894690230/article/details/78207495) 78 | 79 | ### 说说Spring Cloud 的负载均衡 80 | 81 | 在 Spring Cloud 中,能够使用的负载均衡,如下: 82 | 83 | - [`spring-cloud-netflix-ribbon`](https://github.com/spring-cloud/spring-cloud-netflix/tree/master/spring-cloud-netflix-ribbon) ,基于 Ribbon 实现。 84 | - [`spring-cloud-loadbalancer`](https://github.com/spring-cloud/spring-cloud-commons/tree/master/spring-cloud-loadbalancer) ,提供简单的负载均衡功能。 85 | 86 | 以上的实现,都是基于 [`spring-cloud-commons`](https://github.com/spring-cloud/spring-cloud-commons) 的 [`loadbalancer`](https://github.com/spring-cloud/spring-cloud-commons/tree/master/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer) 的 [ServiceInstanceChooser](https://github.com/spring-cloud/spring-cloud-commons/blob/ecabe2bb8d9cb14aa6edcff41fdb79dc304ed004/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/ServiceInstanceChooser.java) 接口,实现统一的服务的选择。并且,负载均衡组件在选择需要调用的服务之后,还提供调用该服务的功能,具体方法见 [LoadBalancerClient](https://github.com/spring-cloud/spring-cloud-commons/blob/master/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerClient.java) 接口的 `#execute(...)` 方法。 87 | 88 | ### 为什么要负载均衡? 89 | 90 | 简单来说,随着业务的发展,单台服务无法支撑访问的需要,于是搭建多个服务形成集群。那么随之要解决的是,每次请求,调用哪个服务,也就是需要进行负载均衡。 91 | 92 | 目前负载均衡有两种模式: 93 | 94 | 1. 客户端模式 95 | 2. 服务端模式 96 | 97 | 在 Spring Cloud 中,我们使用前者,即客户端模式。 98 | 99 | 详细的内容,可以看看 [《客户端负载均衡与服务端负载均衡》](https://blog.csdn.net/u014401141/article/details/78676296) 。 100 | 101 | 在计算中,负载平衡可以改善跨计算机,计算机集群,网络链接,中央处理单元或磁盘驱动器等多种计算资源的工作负载分布。负载平衡旨在优化资源使用,最大化吞吐量,最小化响应时间并避免任何单一资源的过载。使用多个组件进行负载平衡而不是单个组件可能会通过冗余来提高可靠性和可用性。负载平衡通常涉及专用软件或硬件,例如多层交换机或域名系统服务器进程。 102 | 103 | ### Feign 实现原理 104 | 105 | **Feign的一个关键机制就是使用了动态代理**。咱们一起来看看下面的图,结合图来分析: 106 | 107 | - 首先,如果你对某个接口定义了 `@FeignClient` 注解,Feign 就会针对这个接口创建一个动态代理。 108 | - 接着你要是调用那个接口,本质就是会调用 Feign 创建的动态代理,这是核心中的核心。 109 | - Feign的动态代理会根据你在接口上的 `@RequestMapping` 等注解,来动态构造出你要请求的服务的地址。 110 | - 最后针对这个地址,发起请求、解析响应。 111 | 112 | ![Feign 原理](https://itsaysay-1313174343.cos.ap-shanghai.myqcloud.com/blog/68747470733a2f2f747661312e73696e61696d672e636e2f6c617267652f303036744e6252776c7931676166346c6a6d3768686a333075623039646161682e6a7067.jpeg) 113 | 114 | ### Feign 和 Ribbon 的区别? 115 | 116 | Ribbon 和 Feign 都是使用于调用用其余服务的,不过方式不同。 117 | 118 | - 启动类用的注解不同。 119 | - Ribbon 使用的是 `@RibbonClient` 。 120 | - Feign 使用的是 `@EnableFeignClients` 。 121 | - 服务的指定位置不同。 122 | - Ribbon 是在 `@RibbonClient` 注解上设置。 123 | - Feign 则是在定义声明方法的接口中用 `@FeignClient` 注解上设置。 124 | - 调使用方式不同。 125 | - Ribbon 需要自己构建 Http 请求,模拟 Http 请求而后用 RestTemplate 发送给其余服务,步骤相当繁琐。 126 | - Feign 采使用接口的方式,将需要调使用的其余服务的方法定义成声明方法就可,不需要自己构建 Http 请求。不过要注意的是声明方法的注解、方法签名要和提供服务的方法完全一致。 127 | 128 | ### 为什么要网关服务? 129 | 130 | 使用网关服务,我们实现统一的功能: 131 | 132 | - 动态路由 133 | - 灰度发布 134 | - 健康检查 135 | - 限流 136 | - 熔断 137 | - 认证: 如数支持 HMAC, JWT, Basic, OAuth 2.0 等常用协议 138 | - 鉴权: 权限控制,IP 黑白名单,同样是 OpenResty 的特性 139 | - 可用性 140 | - 高性能 141 | 142 | ### 熔断和降级区别 143 | 144 | 熔断是下层服务一旦产生故障就断掉;降级需要对服务进行分级,把产生故障的服务丢掉,换一个轻量级的方案。 145 | 146 | 147 | 148 | ### Spring Cloud Gateway 149 | 150 | #### 过滤器 151 | 152 | 分类: 153 | 154 | 1、 GatewayFilter,网关过滤器,只应用在单个路由或者一个分组的路由上 155 | 156 | - AddRequestHeader:用于在请求头中添加自定义键值对 157 | - AddRequestParameter:用于在请求中添加请求参数的键值对 158 | - AddResponseHeader:用于在响应头中添加键值对 159 | - Hystrix网关过滤工厂:用于将断路器引入网关路由中 160 | - PrefixPath:用于使用简单的Prefix参数 161 | - PreserveHostHeader:用于设置路由过滤器的请求属性,检查是否发送原始主机头或由HTTP客户端确定主机头 162 | - RequestRateLimiter:用于确定当前请求是否允许继续,如果不允许,返回提示“HTTP 429 - Too Many Requests” 163 | - RedirectTo:用于接收请求的状态和URL参数,该状态是一个重定向的300系列的HTTP代码,如301,URL是Location的头部值 164 | - RemoveNonProxyHeaders:用于从转发的请求中删除请求头 165 | - RemoveRequestHeader:用于删除请求头,需要请求头名 166 | - RemoveResponseHeader:用于响应头,需要响应头名 167 | - RewritePath:用于使用Java正则表达式重写请求路径 168 | - SaveSession:用于在转发下游调用之前强制执行保存Session操作 169 | - SecureHeaders:用于为响应添加安全头 170 | - SetPath:允许通过路径的模版段来操作请求的路径,使用了Spring框架的URI模版,支持多种匹配 171 | - SetResponseHeader:用于设置响应头,需要有一个Key-Value对 172 | - SetStatus:用于设置请求响应状态,需要一个Status参数,该参数的值必须是有效的SpringHttpStatus, 173 | - StripPrefix:用于剥离前缀,需要parts参数,表明在请求被发送到下游之前从请求路径中剥离的元素数量 174 | - Retry:用于重试 175 | - RequestSize:用于限制请求的大小,当请求超过限制时启用,限制请求到达下游服务,该过滤器将RequestSize作为参数 176 | 177 | 2、 GlobalFilter,全局过滤器,应用在所有的路由上 178 | 179 | - Forward Routing Filter 180 | - LoadBalancerClientFilter 181 | - Netty Routing Filter 182 | - Netty Write Response Filter 183 | - RouteToRequestUrl Filter 184 | - Websocket Routing Filter 185 | - GateWay Metrics Filter 网关指标过滤器 186 | - Combined Global Filter and GateWayFilter 组合式全局过滤器和网关过滤器排序 187 | - Marking An Exchange As Routed 路由交换 188 | 189 | > 详细见:[Spring Cloud Gateway 参考指南_cloud: gateway: metrics: enabled: true-CSDN博客](https://blog.csdn.net/weixin_40972073/article/details/125840118?ops_request_misc=%7B%22request%5Fid%22%3A%22171941508116800184151243%22%2C%22scm%22%3A%2220140713.130102334.pc%5Fblog.%22%7D&request_id=171941508116800184151243&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-125840118-null-null.nonecase&utm_term=gateway&spm=1018.2226.3001.4450) 190 | 191 | -------------------------------------------------------------------------------- /14.Message Queue.md: -------------------------------------------------------------------------------- 1 | # 14.消息队列 2 | 3 | > 《深入理解Kafka 核心设计与实践原理》 4 | 5 | ### Kafka 6 | 7 | #### 说一下Kafka 8 | 9 | Kafka是一款高性能的消息中间件,包括Producer,Consumer,Broker,以及Zookeeper,Zookeeper用来负责集群元数据管理,控制器的选举等操作,Producer将消息发送到Broker,由Broker负责将收到的消息存储到磁盘中,Consumer负责从Broker订阅并消费消息。Kafka中的消息是以主题为单位,主题可以分布在不同的分区,分区可以分布于不同的Broker,分区有Leader 与副本follower,follower负责从leader同步数据,leader负责读写请求 10 | 11 | 12 | 13 | #### 消息的幂等性处理思路 14 | 15 | 主要是防止消息重复消费,通过业务方去保证消息的幂等性,每条消息设置一个唯一Id,数据库的话通过唯一索引。 16 | 17 | 18 | 19 | #### 消息队列如何保证高可用 20 | kafka可以有多个Borker,一个topic会将数据存储在不同的partiton上, 并且有多个副本来同步数据,但只会有一个leader,数据以Log的形式存储在硬盘中,并且记录了消费的offset。如果leader挂掉,会从ISR集合中的副本选出一个做为leader。 21 | 22 | 23 | 24 | #### Kafka 新建的分区会在哪个目录下创建 25 | 26 | 在启动Kafka集群之前,我们需要配置好log.dirs参数,其值是kafka数据的存放目录,这个参数可以配置多个目录,目录之间使用逗号分隔,通常这些目录是分布在不同的磁盘上用于提高读写性能。 27 | 28 | 也可以配置log.dir参数,含义一样,只需要设置其中一个即可。如果log.dirs参数只配置了一个目录,那么分配到各个Broker上的分区肯定只能在这个目录下创建文件夹用于存储数据。 29 | 30 | 但是如果log.dirs参数配置了多个目录,Kafka会在含有分区目录最少的文件夹中创建新的分区目录,分区目录名为Topic名 + 分区ID。`注意,是分区文件夹总数最少的目录,而不是磁盘使用量最少的目录` 31 | 32 | 33 | 34 | #### Kafka的 ack 机制 35 | 36 | ack 有三个值 0 1 -1 37 | 38 | 0 : 生产者不会等待borker返回,延迟最低但是存储的保证最弱当server挂掉的时候就会丢数据 39 | 40 | 1 : 等待leader确认消息返回,但如果Leader挂掉后不保证是否复制完成 41 | 42 | -1: 等待所有的副本确认消息返回 43 | 44 | 45 | 46 | #### 如何保证消息可靠性 47 | 48 | kafka保证消息可靠性,可以通过如下几个配置: 49 | 1. 生产者配置 acks = all (-1) ISR中的所有副本都写入成功,才代表该消息发送成功 50 | 2. min.insync.replicas默认为1,指定了ISR集合中最小的副本数,不满足条件就会抛出NotEnoughReplicasException 或 NotEnoughReplicasAfterAppendException,也就是必须保证有一个副本同步数据跟得上leader 51 | 3. unclean.leader.election.enable 默认为false, 当leader下线的时候可以从非ISR集合中选举新的leader,这样能提高可用性,但会丢数据 52 | 4. 配置log.flush.interval.messages 和 log.flush.interval.ms 同步刷盘策略 53 | 5. 消费端手动提交位移,enable.auto.commit 设置为false,自动提交会带来重复消费和消息丢失的问题,客户端如果消息消费失败应该放入死信队列,以便后期排除故障 54 | 6. 回溯消费功能,消息貌似已经成功消费,但实际消息失败了,不知道是什么错误造成的,就可以通过回溯消费补偿,或者复现 “丢失”,seek()方法 55 | 56 | 57 | 58 | #### 消息积压问题 59 | 60 | 如果消息积压了太多,一直消费不了,需要检查是不是consumer有问题,或者服务端磁盘是否快满了。 61 | 1. consumer有问题就修复问题。但由于积压的数据太多,用原程序消费还是太慢。就需要扩容,新建临时topic,将分区改为原来的10倍,写程序将原来积压的消息发送到新建的topic中,启动10倍的机器来消费这些数据 62 | 2. 服务端磁盘满,就只能扩容服务端磁盘,再采用第一种办法来修复问题 63 | 64 | 65 | 66 | #### 怎么保证消息顺序消费 67 | 68 | 消息要顺序消费的场景,比如发送了一个用户新增的消息,随后用户修改了发送了一个修改的消息,最后又删除了发送了一个删除的消息,由于Kafka的多分区,多消费者,消费端势必会变成无序消费,但消费端业务需要顺序处理,如果先消费了删除消息,根本没数据,随后又消费了新增消息,最后消息没有删除,变成了脏数据。 69 | 70 | 解决方法是:生产者发送消息的时候,根据用户id指定分区key,指定后kafka会将消息发送到指定的分区中,这样保证了分区中消息的顺序。消费端,可以使用单线程从指定分区中消费,如果要保证性能,消费端定义多个内存队列,将相同用户id的消息发送到同一个内存队列中,然后开启多线程从来消费多个内存队列,一个线程处理一个内存队列 71 | 72 | 73 | 74 | #### kafka的分区策略 75 | 76 | 消费者客户端参数partition.assignment.strategy 来配置消费分区策略 77 | 1. RangeAssignor 默认分配策略 通过 分区数/消费者总数 来获得一个跨度进行分配 78 | 2. RoundRobinAssignor 轮询分配策略 79 | 3. StickyAssignor 能够使分区的分配尽可能与上一次保持一致,避免过度重分配 80 | 4. 自定义分配,实现PartitionAssignor接口 81 | 82 | 83 | 84 | #### kafka 集群如何搭建 85 | 86 | - 安装zk集群,修改各个节点的kafka配置文件server.properties(broker.id、listeners、zookeeper.connect) 87 | - 启动zk、启动kafka 88 | 89 | k8s 上创建:[K8s - 安装部署Kafka、Zookeeper集群教程(支持从K8s外部访问) - 蜂蜜log - 博客园 (cnblogs.com)](https://www.cnblogs.com/fengyuanfei/p/17789107.html) 90 | 91 | 92 | 93 | #### 什么是ISR 94 | 95 | - AR(Assigned Repllicas)一个partition的所有副本(即使replica,不区分leader或follower) 96 | - ISR(In-Sync Replicas)能够和leader保持同步的follower+leader本身组成的集合 97 | - OSR(Out-Sync Relipcas)不能和leader 保持同步的follower集合 98 | 99 | -------------------------------------------------------------------------------- /15.Mybatis.md: -------------------------------------------------------------------------------- 1 | # 15.Mybatis 2 | 3 | ### MyBatis 编程步骤 4 | 5 | 1. 创建 SqlSessionFactory 对象。 6 | 7 | 2. 通过 SqlSessionFactory 获取 SqlSession 对象。 8 | 9 | 3. 通过 SqlSession 获得 Mapper 代理对象。 10 | 11 | 4. 通过 Mapper 代理对象,执行数据库操作。 12 | 13 | 5. 执行成功,则使用 SqlSession 提交事务。 14 | 15 | 6. 执行失败,则使用 SqlSession 回滚事务。 16 | 17 | 7. 最终,关闭会话。 18 | 19 | 20 | 21 | ### MyBatis 如何执行批量插入? 22 | 23 | 1. 使用Sql 拼接,有语句大小限制 24 | 25 | ```sql 26 | INSERT INTO [表名]([列名],[列名]) 27 | VALUES 28 | ([列值],[列值])), 29 | ([列值],[列值])), 30 | ([列值],[列值])); 31 | ``` 32 | 33 | 2. 使用Mybatis 的批量插入方式 34 | 35 | ```java 36 | private static SqlSessionFactory sqlSessionFactory; 37 | 38 | @Test 39 | public void testBatch() { 40 | // 创建要插入的用户的名字的数组 41 | List names = new ArrayList<>(); 42 | names.add("张三"); 43 | names.add("李四"); 44 | names.add("李二"); 45 | names.add("王五"); 46 | 47 | // 获得执行器类型为 Batch 的 SqlSession 对象,并且 autoCommit = false ,禁止事务自动提交 48 | try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false)) { 49 | // 获得 Mapper 对象 50 | UserMapper mapper = session.getMapper(UserMapper.class); 51 | // 循环插入 52 | for (String name : names) { 53 | mapper.insertUser(name); 54 | } 55 | // 提交批量操作 56 | session.commit(); 57 | } 58 | } 59 | ``` 60 | 61 | 3. 使用循环一条条插入 62 | 63 | 64 | 65 | ### Mybatis 的 XML Mapper文件中,不同的 XML 映射文件,id 是否可以重复? 66 | 67 | 不同的 XML Mapper 文件,如果配置了 `"namespace"` ,那么 id 可以重复;如果没有配置 `"namespace"` ,那么 id 不能重复。毕竟`"namespace"` 不是必须的,只是最佳实践而已。 68 | 69 | 原因就是,`namespace + id` 是作为 `Map` 的 key 使用的。如果没有 `"namespace"`,就剩下 id ,那么 id 重复会导致数据互相覆盖。如果有了 `"namespace"`,自然 id 就可以重复,`"namespace"`不同,`namespace + id` 自然也就不同。 70 | 71 | 72 | 73 | ### 简述 Mybatis 的 XML 映射文件和 Mybatis 内部数据结构之间的映射关系? 74 | 75 | Mybatis 将所有 XML 配置信息都封装到 All-In-One 重量级对象Configuration内部。 76 | 77 | 在 XML Mapper 文件中: 78 | 79 | - `` 标签,会被解析为 ParameterMap 对象,其每个子元素会被解析为 ParameterMapping 对象。 80 | 81 | - `` 标签,会被解析为 ResultMap 对象,其每个子元素会被解析为 ResultMapping 对象。 82 | 83 | - 每一个 ``、``、``、`` 标签,都会被解析为一个 MappedStatement 对象。 98 | 99 | 另外,Mapper 接口的实现类,通过 MyBatis 使用 **JDK Proxy** 自动生成其代理对象 Proxy ,而代理对象 Proxy 会拦截接口方法,从而“调用”对应的 MappedStatement 方法,最终执行 SQL ,返回执行结果。整体流程如下图:流程 100 | 101 | - 其中,SqlSession 在调用 Executor 之前,会获得对应的 MappedStatement 方法。例如:`DefaultSqlSession#select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler)` 方法,代码如下: 102 | 103 | ```java 104 | // DefaultSqlSession.java 105 | 106 | @Override 107 | public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) { 108 | try { 109 | // 获得 MappedStatement 对象 110 | MappedStatement ms = configuration.getMappedStatement(statement); 111 | // 执行查询 112 | executor.query(ms, wrapCollection(parameter), rowBounds, handler); 113 | } catch (Exception e) { 114 | throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e); 115 | } finally { 116 | ErrorContext.instance().reset(); 117 | } 118 | } 119 | ``` 120 | 121 | 122 | Mapper 接口里的方法,是不能重载的,因为是**全限名 + 方法名**的保存和寻找策略 -------------------------------------------------------------------------------- /16.Zookeeper.md: -------------------------------------------------------------------------------- 1 | # 16.Zookeeper 2 | 3 | ### Zookeeper 是什么? 4 | 5 | zk是一个开源的分布式协调服务,它是集群的管理者,监视着集群中各个节点的状态根据节点提交反馈进行下一步操作,最终将简单易用的接口和性能高效1、文档的系统提供给用户 6 | 7 | 分布式应用程序可以基于zk实现数据发布/订阅,负载均衡、Master选举、分布式锁、分布式队列等功能 8 | 9 | **特性** 10 | 11 | - 顺序一致性(有序性) 12 | 13 | 从同一个客户端发起的事务请求,最终将会严格地按照其发起顺序被应用到 Zookeeper 中去。 14 | 15 | 有序性是 Zookeeper 中非常重要的一个特性。 16 | 17 | 所有的更新都是全局有序的,每个更新都有一个唯一的时间戳,这个时间戳称为zxid(Zookeeper Transaction Id)。 18 | 19 | 而读请求只会相对于更新有序,也就是读请求的返回结果中会带有这个 Zookeeper 最新的 zxid 。 20 | 21 | - 原子性 22 | 23 | 所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的,即整个集群要么都成功应用了某个事务,要么都没有应用。 24 | 25 | - 单一视图 26 | 27 | 无论客户端连接的是哪个 Zookeeper 服务器,其看到的服务端数据模型都是一致的。 28 | 29 | - 可靠性 30 | 31 | 一旦服务端成功地应用了一个事务,并完成对客户端的响应,那么该事务所引起的服务端状态变更将会一直被保留,除非有另一个事务对其进行了变更。 32 | 33 | - 实时性 34 | 35 | Zookeeper 保证在一定的时间段内,客户端最终一定能够从服务端上读取到最新的数据状态。 36 | 37 | ​ 38 | 39 | ### Zookeeper 有哪几种节点类型? 40 | 41 | - PERSISTENT 持久节点 42 | 43 | 创建之后一直存在,除非有删除操作,创建节点的客户端会话失效也不影响此节点。 44 | 45 | - PERSISTENT_SEQUENTIAL 持久顺序节点 46 | 47 | 跟持久一样,就是父节点在创建下一级子节点的时候,记录每个子节点创建的先后顺序,会给每个子节点名加上一个数字后缀。 48 | 49 | - EPHEMERAL 临时节点 50 | 51 | 创建客户端会话失效(注意是会话失效,不是连接断了),节点也就没了。不能建子节点。 52 | 53 | - EPHEMERAL_SEQUENTIAL 临时顺序节点 54 | 55 | 基本特性同临时节点,增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。 56 | 57 | 58 | 59 | ### Zookeeper 的通知机制是什么? 60 | 61 | Zookeeper 允许客户端向服务端的某个 znode 注册一个 Watcher 监听,当服务端的一些指定事件触发了这个 Watcher ,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客户端根据 Watcher 通知状态和事件类型做出业务上的改变。 62 | 63 | 整个流程如下: 64 | 65 | - 第一步,客户端注册 Watcher 。 66 | - 第二步,服务端处理 Watcher 。 67 | - 第三步,客户端回调 Watcher 。 68 | 69 | 70 | 71 | ### Zookeeper 采用什么权限控制机制? 72 | 73 | 目前,在 Linux/Unix 文件系统中,使用 UGO(User/Group/Others) 权限模型,也是使用最广泛的权限控制方式。是一种粗粒度的文件系统权限控制模式。 74 | 75 | 一般我们管理后台,采用的 RBAC 居多,和 UGO 比较类似,差别在于一般将权限分配给 Role ,而不是直接给 User 。 76 | 77 | 对于 Zookeeper ,它采用 ACL(Access Control List)访问控制列表。包括三个方面: 78 | 79 | - 权限模式(Scheme) 80 | 81 | - IP :从 IP 地址粒度进行权限控制 82 | - 【常用】Digest :最常用,用类似于 `username:password` 的权限标识来进行权限配置,便于区分不同应用来进行权限控制。 83 | - World :最开放的权限控制方式,是一种特殊的 digest 模式,只有一个权限标识 `“world:anyone”` 。 84 | - Super :超级用户。 85 | 86 | - 授权对象 87 | 88 | 授权对象指的是权限赋予的用户或一个指定实体,例如 IP 地址或是机器等。 89 | 90 | - 权限 Permission 91 | 92 | - CREATE :数据节点创建权限,允许授权对象在该 znode 下创建子节点。 93 | - DELETE :子节点删除权限,允许授权对象删除该数据节点的子节点。 94 | - READ :数据节点的读取权限,允许授权对象访问该数据节点并读取其数据内容或子节点列表等。 95 | - WRITE :数据节点更新权限,允许授权对象对该数据节点进行更新操作。 96 | - ADMIN :数据节点管理权限,允许授权对象对该数据节点进行 ACL 相关设置操作。 97 | 98 | 99 | 100 | ### 集群中的机器角色有哪些? 101 | 102 | - 1、Leader 103 | 104 | - 事务请求的唯一调度和处理者,保证集群事务处理的顺序性。 105 | - 集群内部各服务的调度者。 106 | 107 | - 2、Follower 108 | 109 | - 处理客户端的非事务请求,转发事务请求给 Leader 服务器。 110 | - 参与事务请求 Proposal 的投票。 111 | 参与 Leader 选举投票。 112 | 113 | - 3、Observer 114 | 115 | 3.3.0 版本以后引入的一个服务器角色,在不影响集群事务处理能力的基础上提升集群的非事务处理能力。 116 | 117 | - 处理客户端的非事务请求,转发事务请求给 Leader 服务器 118 | - 不参与任何形式的投票。 119 | 120 | 如果 ZooKeeper 集群的读取负载很高,或者客户端多到跨机房,可以设置一些 Observer 服务器,以提高读取的吞吐量。Observer 和 Follower 比较相似,只有一些小区别: 121 | 122 | - 首先 Observer 不属于法定人数,即不参加选举也不响应提议,也不参与写操作的“过半写成功”策略; 123 | - 其次是 Observer 不需要将事务持久化到磁盘,一旦 Observer 被重启,需要从 Leader 重新同步整个名字空间。 124 | 125 | 126 | 127 | ### 集群如果有 3 台机器,挂掉 1 台集群还能工作吗?挂掉 2 台呢? 128 | 129 | 记住一个原则:过半存活即可用。所以挂掉 1 台可以继续工作,挂掉 2 台不可以工作。 130 | 131 | 132 | 133 | ### 集群支持动态添加机器吗 134 | 135 | 在 3.5 版本开始,支持动态扩容。 136 | 137 | 而在 3.5 版本之前,Zookeeper 在这方面不太好。所以需要如下两种方式: 138 | 139 | - 全部重启:关闭所有 Zookeeper 服务,修改配置之后启动。不影响之前客户端的会话。 140 | - 逐个重启:顾名思义。这是比较常用的方式。 141 | 142 | 143 | 144 | ### ZooKeeper 的工作原理? 145 | 146 | > 结合ZK介绍来讲 147 | 148 | ZooKeeper 的核心是原子广播,这个机制保证了各个 Server 之间的同步。实现这个机制的协议叫做 **Zab** 协议。Zab 协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步): 149 | 150 | - 选主:当服务启动或者 Leader 崩溃后,Zab 就进入了恢复模式,当新的 Leader 被选举出来,且大多数 Server 完成了和 Leader 的状态同步以后,恢复模式就结束了。 151 | 152 | 当整个 Zookeeper 集群刚刚启动,或者 Leader 服务器宕机、重启或者网络故障导致不存在过半的服务器与 Leader服务器保持正常通信时,所有进程(服务器)进入崩溃恢复模式。 153 | 154 | - 首先,选举产生新的Leader服务器。 155 | - 然后,集群中 Follower 服务器开始与新的 Leader 服务器进行数据同步。 156 | 157 | - 当集群中超过半数机器与该Leader服务器完成数据同步之后,退出恢复模式进入消息广播模式, 158 | 159 | - 同步:状态同步保证了 Leader 和 Server 具有相同的系统状态。 160 | Leader 服务器开始接收客户端的事务请求,生成事务提案来进行事务请求处理。 161 | 162 | 163 | 164 | ### Zookeeper 的同步流程? 165 | 166 | 选完 Leader 以后,Zookeeper 就进入状态同步过程。 167 | 168 | - 1、Leader 等待 Server 连接。 169 | - 2、Follower 连接 Leader ,将最大的 zxid 发送给 Leader 。 170 | - 3、Leader 根据 Follower 的 zxid 确定同步点。 171 | - 4、完成同步后通知 Follower 已经成为 update 状态。 172 | - 5、Follower 收到 update 消息后,又可以重新接受 Client 的请求进行服务了。 173 | 174 | 当然,同步流程并不是像上述描述的这么简单,具体的,还是得看看 [《Zookeeper Leader 和 Learner 的数据同步》](https://blog.csdn.net/weixin_36145588/article/details/75043611) 。 175 | 176 | 177 | 178 | ### Zookeeper 的选举过程? 179 | 180 | 当 Leader 崩溃,或者 Leader 失去大多数的 Follower,这时 Zookeeper 进入恢复模式,恢复模式需要重新选举出一个新的 Leader,让所有的 Server 都恢复到一个正确的状态。 181 | 182 | Zookeeper 的选举算法有两种:一种是基于 basic paxos 实现的,另外一种是基于 fast paxos 算法实现的。系统默认的选举算法为 fast paxos 。 183 | 184 | > 相对详细的,可以看看 [《【分布式】Zookeeper的Leader选举》](http://www.cnblogs.com/leesf456/p/6107600.html) 和 [《Zookeeper 源码分析 —— Zookeeper Leader 选举算法》](https://juejin.im/post/5b949d595188255c6a041c22) 。 185 | > 186 | > - 不同阶段的选举流程 187 | > - 服务器启动时期的 Leader 选举。 188 | > - 服务器运行时期的 Leader 选举。 189 | > - 三种选举算法 190 | > - LeaderElection :使用 basic paxos 算法。 191 | > - FastLeaderElection :使用 fast paxos 算法。 192 | > - AuthFastLeaderElection :在 FastLeaderElection 的基础上,增加认证。 193 | > - 最终在 Zookeeper 3.4.0 版本之后,只保留 FastLeaderElection 版本。 194 | 195 | - **fast paxos** 196 | 197 | 由于 LeaderElection 收敛速度较慢,所以 Zookeeper 引入了 FastLeaderElection 选举算法,FastLeaderElection 也成了Zookeeper默认的Leader选举算法。 198 | 199 | FastLeaderElection 是标准的 Fast Paxos 的实现。它首先向所有 Server 提议自己要成为 Leader ,当其它 Server 收到提议以后,解决 epoch 和 zxid 的冲突,并接受对方的提议,然后向对方发送接受提议完成的消息。重复这个流程,最后一定能选举出Leader。 200 | 201 | FastLeaderElection 算法通过异步的通信方式来收集其它节点的选票,同时在分析选票时又根据投票者的当前状态来作不同的处理,以加快 Leader 的选举进程。 202 | 203 | 流程 -------------------------------------------------------------------------------- /17.Maven.md: -------------------------------------------------------------------------------- 1 | # 17.Maven 2 | 3 | ### dependency 4 | 5 | - groupId 6 | 7 | 定义隶属的实际项目 8 | 9 | - artifactId 10 | 11 | 定义项目中的一个模块 12 | 13 | - version 14 | 15 | 定义依赖或项目的版本 16 | 17 | ### maven依赖 生命周期scope 18 | 19 | - compile 20 | 21 | 默认值,表示当前依赖参与项目的编译、测试、运行阶段,属于强依赖,打包时,会打到包里去 22 | 23 | - test 24 | 25 | 仅仅参与测试,包括测试用例的编译和执行,比如Junit 26 | 27 | - runtime 28 | 29 | 依赖仅参与运行周期中的使用,一般这种类库都是接口与实现相分离的类库,比如JDBC,在编译时依赖相关的接口,在具体运行时,需要mysql等驱动程序 30 | 31 | - provided 32 | 33 | 该依赖在打包过程中,不需要打进去,这个由运行环境提供,比如tomcat或者基础类库等 34 | 35 | - system 36 | 37 | 使用上与provided相同,不同之处在于该依赖不从maven仓库中提取,而是从本地文件系统中提取,其会参与systemPath的属性进行提取依赖 38 | 39 | - import 40 | 41 | 只能在dependencyManagement中使用,能解决Maven单继承问题,import依赖关系实际上并不参与限制依赖关系的传递性 42 | 43 | ### 本地jar报安装到Maven仓库 44 | 45 | mvn install:install-file -Dfile=本地jar包路径 -DgroupId=jar包的groupId -DartifactId=jar包artifactId -Dversion=jar包版本 -Dpackaging=jar 46 | 47 | -------------------------------------------------------------------------------- /18.Open Question.md: -------------------------------------------------------------------------------- 1 | # 18.开放题 2 | 3 | ##### 假设一个场景,要求stop the world时间非常短,你会怎么设计垃圾回收机制? 4 | 5 | STW时间短即要求应用响应时间快,应用的绝大多数对象都存在年轻代中,并且能够活到GC的对象很少,所以采用复制算法,只需要复制少量的对象就可以完成收集,同时将年轻代大小调大,通过-Xmn设置。由于年轻代分为Eden区和两个Survivor区,大部分新生对象都存在Eden区,因此还可以通过-XX:SurvivorRatio 调大Eden区的比例,比如-XX:SurvivorRatio=4,表示两个Survivor区与一个Eden区的比值为2:4 6 | 7 | 8 | 9 | ##### 现在有一个A类,其中有A、B、C方法,C方法中调用了A、B,定义了一个A、B方法的日志切面,请问能打印出日志吗? 10 | 11 | 12 | 13 | ##### 分级代理问题 14 | 15 | 某公司销售一款智能硬件柜机,内含多种可消费的服务。 16 | 17 | 销售模式为代理方式,设备由公司免费发给代理商,代理商负责安置柜机、促进柜机产生用户消费。 18 | 公司将某批设备划拨给一级代理后,一级代理继续划拨给二级代理,以此类推可以逐级展开。 19 | 上一级代理可以管理下级代理的分成比例,分成的比例包括默认比例和根据某个特定消费服务单独设置的比例。 20 | 21 | 当用户使用设备并在设备上完成消费时,需要追溯该笔消费所属的多级代理并逐级结算代理分成。 22 | 例:公司发货10000台设备给一级代理A1,包含服务S1,S2,S1设置30%分成、S2设置40%分成。 23 | 一级代理自己销售5000台设备,并将另外5000台设备代理给二级代理商A12、A13,分别为S1、S2设置20%、30%提成。那么当用户在A12代理的设备消费S1服务时,支付100元,其中20元提成结算给代理商A12,10元提成结算给A1,剩余70元收入入总公司账户。 24 | 25 | 请理解这个业务需求,进行概要设计。 26 | 1. 列出关键的类名、方法名、参数名(均为英文)。 27 | 2. 假设订单成功消息将触发onTransactionSuccess( ... )方法,请给出(...)部分的必要参数列表 28 | 3. 写出onTransactionSuccess方法的伪代码,调用#1列出的方法完成分成逻辑 29 | 30 | 31 | 32 | ##### 设计短链接问题 33 | 34 | https://blog.csdn.net/xlgen157387/article/details/80026452 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /19.Distribute_MicroService.md: -------------------------------------------------------------------------------- 1 | # 19.分布式、微服务知识点 2 | 3 | > 参考《高可用可伸缩微服务架构》 4 | 5 | ### 领域驱动有了解吗?什么是领域驱动模型? 6 | 7 | ### JWT有了解吗,什么是JWT 8 | 9 | ### 说说如何设计一个良好的 API 10 | 11 | ### 说说 CAP 定理、BASE 理论 12 | 13 | CAP: 14 | 15 | C(一致性 Consistency),所有节点上的数据时刻保持一致 16 | 17 | A(可用性 Avaliability),每个请求都能够收到一个响应,无论响应成功或者失败 18 | 19 | P(分区容错 Partition-tolerance),系统出现脑裂以后,可能导致某些server 与集群中的机器失去联系 20 | 21 | BASE: 22 | 23 | XA事务虽然可以保证数据库在分布式系统下的ACID特性,但会带来性能方面的影响 24 | 25 | eBay提出了BASE理论 26 | 27 | Basically available:数据库采用分片模式,把100w的用户数据分布在5个实例上,如果破坏了其中一个实例,仍然可以保证80%的用户可用 28 | 29 | Soft-state:在基于client-server模式的系统中,server端是否有状态,决定了系统是否具备良好的水平扩展、负载均衡、故障恢复等特性。Server端承诺会维护client端状态数据,这个状态仅维持一小段时间,这段时间以后,server端会丢弃这个状态,恢复正常状态 30 | 31 | Eventually consistent:数据最终一致性 32 | 33 | 34 | 35 | ### 微服务与 SOA 的区别 36 | 37 | SOA即面向服务架构,关注点是服务,现有的分布式服务化技术有Dubbo等 38 | 39 | 1. 微服务是一种经过改良架构设计的SOA解决方案,是面向服务的交互方案 40 | 2. 微服务更趋向于以自治的方式产生价值 41 | 3. 微服务与敏捷开发的思想高度结合在一起,服务的定义更加清晰,同时减少了企业ESB开发的复杂性 42 | 4. 微服务是SOA思想的一种提炼 43 | 5. SOA是重ESB,微服务是轻网关 44 | 45 | ### 如何拆分服务、水平分割、垂直分割 46 | 47 | ### 如何应对微服务的链式调用异常 48 | 49 | ### 如何快速追踪与定位问题 50 | 51 | ### 如何保证微服务的安全、认证 52 | 53 | 54 | 55 | ### 如何保证接口的幂等性 56 | 57 | 1. 乐观锁,使用版本号 58 | 59 | 2. 唯一索引,可以把作为唯一索引的键单独称为一个表,作为去重表 60 | 61 | 3. 分布式锁,使用setnx,如果setnx返回0就代表重复请求,同时在业务逻辑处理完成后,删除缓存 62 | 63 | 64 | 65 | ### 分布式服务接口请求的顺序性如何保证? 66 | 67 | 首先,一般来说,个人建议是,你们从业务逻辑上设计的这个系统最好是不需要这种顺序性的保证,因为一旦引入顺序性保障,比如使用**分布式锁**,会**导致系统复杂度上升**,而且会带来**效率低下**,热点数据压力过大等问题。 68 | 69 | 下面我给个我们用过的方案吧,简单来说,首先你得用 dubbo 的一致性 hash 负载均衡策略,将比如某一个订单 id 对应的请求都给分发到某个机器上去,接着就是在那个机器上,因为可能还是多线程并发执行的,你可能得立即将某个订单 id 对应的请求扔一个**内存队列**里去,强制排队,这样来确保他们的顺序性。 70 | 71 | [distributed-system-request-sequence 72 | 73 | 但是这样引发的后续问题就很多,比如说要是某个订单对应的请求特别多,造成某台机器成**热点**怎么办?解决这些问题又要开启后续一连串的复杂技术方案......曾经这类问题弄的我们头疼不已,所以,还是建议什么呢? 74 | 75 | 最好是比如说刚才那种,一个订单的插入和删除操作,能不能合并成一个操作,就是一个删除,或者是其它什么,避免这种问题的产生。 76 | 77 | 78 | 79 | ### 说说分布式一致性的实现方案 80 | 81 | 1. 2PC两阶段提交 82 | 83 | 分**准备阶段、提交阶段**,由事务管理协调器发起 84 | 85 | 准备阶段:事务管理器向参与者发起指令,参与者评估自己的状态,如果参与者评估指令可以完成,则会写redo或者undo日志,然后锁定资源,执行操作,但并不提交。如果其中一个参与者返回准备准备失败,则协调者向参与者发起中止指令,参与者取消已经变更的事务,执行undo日志,释放锁定的资源 86 | 87 | 提交阶段:如果每个参与者明确返回准备成功,也就是预留资源和执行操作成功,则协调者向参与者发起提交指令,参与者提交资源变更的事务,释放锁定的资源; 88 | 89 | 缺点: 90 | 91 | 阻塞,对于任何一次指令都必须收到明确的响应,才会继续下一步,否则处于阻塞状态,占用的资源被一直锁定,不会释放 92 | 93 | 单点故障,协调者宕机,参与者没有协调者指挥,会一直阻塞,需要自己实现协调者选举 94 | 95 | 脑裂,协调者发送指令,有的参与者可能会没有接收到指令,导致多个参与者事务状态不一致 96 | 97 | 2. 3PC三阶段提交 98 | 99 | 是二阶段提交的改进版本,通过超时机制解决了阻塞问题 100 | 101 | 询问阶段:协调者询问参与者是否可以完成指令,协调者回复是或者不是,不做真正的操作,如果超时会导致中止 102 | 103 | 准备阶段、提交阶段:与二阶段相同 104 | 105 | 3. TCC补偿事务 106 | 107 | 将一个任务拆分成Try、Confirm、Cancle三个步骤,主业务先发起请求执行Try,如果没有问题,则提交任务到TCC事务管理器,由事务管理器执行Confirm,如果出现问题,再执行逆操作Cancel 108 | 109 | 优点:解决了阻塞问题,通过TCC自动化Cancel降低了不一致的情况 110 | 111 | 缺点:实现还是臃肿,在极端情况下会出现不一致和脑裂问题 112 | 113 | 4. RocketMQ事务 114 | 115 | 系统A发送一个事务消息到MQ,MQ会反馈消息接收成功,系统A会收到消息接收成功回调,此时系统A执行本地事务,执行成功后向MQ发送确认消息,否则向MQ取消消息,MQ收到确认消息后,消费系统B就能够接收到该事务消息,执行操作 116 | 117 | 5. Saga模式 118 | 119 | ​ 将长事务拆分为多个可以交错运行的子事务集合,其中每个子事务都保证事务的一致性。整个运行过程由Saga事务协调器来协调,如果每一个子事务都正常结束,则整个事务正常完成;如果某个子事务失败,则整个事务失败,会根据相反顺序执行补偿操作。 120 | 121 | ​ 每个Saga由一系列子事务T组成,每个T都对应一个补偿动作C,补偿动作C用于撤销T造成的结果 122 | 123 | Saga的执行顺序有两种(0< j < n) 124 | 125 | 1. 成功的执行顺序:T1,T2,T3,...,Tn 126 | 2. 最终失败的执行顺序:T1,T2,T3,...,Tj, Cj,...C3,C2,C1。 Tj 代表执行失败,执行失败后,会执行补偿动作来撤销执行 127 | 128 | Saga 定义了以下两种恢复策略 129 | 130 | 1. backward recovery: 向后恢复,补偿所有已完成的事务。如果任一子事务失败,则撤销之前所有成功的sub-transation,整个Saga的执行结果被撤销 131 | 2. forward recovery: 向前恢复,重试失败的事务,假设每个子事务最终都会成功。适用于必须成功的场景,该情况不需要Cj 132 | 133 | 6. Paxos算法模式 134 | 135 | 该算法模式有3个角色: 136 | 137 | 1. Proposer,提议者,提出提案(Proposal),Proposal信息包括提案编号和提议的值 138 | 2. Acceptor,决策者,参与决策,回应Proposers的提案,如果收到的Proposers获得了多数Acceptor接受,则Acceptor称该Proposal被批准 139 | 3. Learner,学习者,不参与决策,从Proposers/Acceptors学习最新达成一致的提案(Value) 140 | 141 | Paxos 算法运行在运行宕机故障的异步系统中,它不要求可靠的消息传递,也容忍消息丢失,延迟,乱序和重复,它利用大多数机制保证了“2F+1”的容错能力,即“2F+1”个节点的系统最多允许F个节点同时出现故障 142 | 143 | ### 说说达到最终一致性的方案 144 | 145 | 1. 查询模式,通过查询了解调用服务的最终处理情况,决定下一步做什么 146 | 2. 补偿模式,有了查询模式,就可以知道服务所在状态,通过补偿模式修正操作 147 | 3. 定时校对模式 148 | 149 | ### 缓存、数据库一致性方案 150 | 151 | 1. 更新操作,先删除缓存,再修改数据库,如果数据库失败,数据库中的还是旧数据,缓存是空的,在查询的时候,发现缓存是空的,就会从数据库取数据,然后更新到缓存中 152 | 153 | 2. 方案一在高并发下,先删除了缓存,但数据库还没修改成功,此时读请求过来,发现没有缓存,就会去查询数据库,放入缓存,随后更新数据库操作完成了,此时缓存中的数据是旧数据,与数据库中的数据不一致。 154 | 155 | 方案如下: 156 | 157 | 在请求的时候,发现没有缓存,就发一个更新操作,到JVM队列,主线程循环判断缓存是否更新,并设置超时时间,如果超时,就直接取数据库数据,返回旧数据。JVM队列中,如果之前已经有更新操作,自动丢弃后面的更新操作,防止频繁更新。 158 | 159 | 如果实例服务是分布式部署,需要将同一请求路由到同一个实例,可以通过某个请求参数的hash路由,也可以通过Nginx的hash路由功能 160 | 161 | https://blog.csdn.net/dustin_cds/article/details/79595297 162 | 163 | ### 架构设计原则 164 | 165 | 要保持模块模块大小适中,尽可能减少调用深度,多扇入少扇出,保持高内聚低耦合,单入口、单出口,模块的作用域要在模块内,模块功能是可预测的,另外面向对象设计要遵守如下原则: 166 | 167 | 单一责任原则:一个类只做一种责任类型 168 | 169 | 开放-封闭原则:支持扩展,不支持修改 170 | 171 | 里氏替换原则:子类可以替换父类 172 | 173 | 依赖倒置原则:细节依赖抽象 174 | 175 | 接口分离原则:不强迫适用,依赖抽象,不依赖具体 176 | 177 | -------------------------------------------------------------------------------- /21. Nginx.md: -------------------------------------------------------------------------------- 1 | # 21.Nginx 2 | 3 | ### 解释一下什么是Nginx?有什么特性? 4 | 5 | Nginx 是一个Web服务器和反向代理服务器,用于Http、Https、SMTP、POP3 和 IMAP协议 6 | 7 | 特性包括:反向代理/L7负载均衡器、切入式Perl解释器、动态二进制升级、可用于重新编写URL,具有非常好的PCRE支持 8 | 9 | 10 | 11 | ### Nginx 和 Apache 的区别 12 | 13 | 1)轻量级,同样起web 服务,比apache 占用更少的内存及资源 14 | 15 | 2)抗并发,nginx 处理请求是异步非阻塞的,而apache 则是阻塞型的,在高并发下nginx 能保持低资源低消耗高性能 16 | 17 | 3)高度模块化的设计,编写模块相对简单 18 | 19 | 4)最核心的区别在于apache是同步多进程模型,一个连接对应一个进程;nginx是异步的,多个连接(万级别)可以对应一个进程 20 | 21 | 22 | 23 | ### Nginx 如何实现高并发 24 | 25 | 一个主进程,多个工作进程,每个工作进程可以处理多个请求,每进来一个request,会有一个worker进程去处理。但不是全程处理,处理到可能发生阻塞的地方,比如向上游(后端)服务器转发request,并等待请求返回。那么,这个处理的worker继续处理其他请求,而一旦上游服务器返回了,就会触发这个事件,worker才会来接手,这个request才会接着往下走。由于web server 的工作性质决定了每个request的大部分生命都在网络传输中,实际上花费在server机器上的时间片不多,这是几个进程就解决高并发的秘密所在,即webserver刚好属于网络io密集型应用,不算计算密集型 26 | 27 | 28 | 29 | ### 请解释Nginx如何处理HTTP请求 30 | 31 | Nginx使用反应器模式,主事件循环等待操作系统发出准备事件的信号,这样数据就可以从套接字读取,在该实例中读取到缓冲区并进行处理,单个线程可以提供数万个并发连接 32 | 33 | 34 | 35 | ### 使用“反向代理服务器”的优点是什么 36 | 37 | 反向代理服务器可以隐藏源服务器的存在和特征。它充当互联网云和web服务器之间的中间层。 38 | 39 | 40 | 41 | ### 在Nginx中,如何使用未定义的服务器名称来阻止处理请求 42 | 43 | ``` 44 | server { 45 | listen 80; 46 | server_name ""; 47 | return 4444; 48 | } 49 | ``` 50 | 51 | 这里服务器名被保留为一个空字符串,它将在没有“主机”头字段的情况下匹配请求,而一个特殊的Nginx的非标准代码444被返回,从而终止连接 52 | 53 | 54 | 55 | ### Nginx 一些主要配置,分别用来做什么的 56 | 57 | - 用来配置虚拟主机 58 | 59 | ```shell 60 | #基于域名的虚拟主机 61 | server { 62 | listen 80; #监听端口 63 | server_name a.com; #监听域名 64 | 65 | location / { 66 | root /var/www/a.com; #根目录定位 67 | index index.html; 68 | } 69 | } 70 | 71 | #基于端口的虚拟主机配置 访问 192.xxx.xx.xxx:8080 72 | server { 73 | listen 8080; #监听8080端口 74 | server_name 192.xxx.xx.xxx; #服务器IP地址 75 | 76 | location / { 77 | root /var/www/html8080; 78 | index index.html; 79 | } 80 | } 81 | ``` 82 | 83 | - 日志管理配置 84 | 85 | ```shell 86 | #不同的server可以使用不同的log 87 | #此处定义了日志格式,最好定位在顶层,方便其他server公用 88 | log_format main '$remote_addr - $remote_user [$time_local] "$request" ' 89 | # '$status $body_bytes_sent "$http_referer" ' 90 | # '"$http_user_agent" "$http_x_forwarded_for"'; 91 | 92 | $remote_addr 用户ip 93 | $remote_user [$time_local] 用户访问时间 94 | $request 请求类型 get,post... 95 | $status 请求状态 200 304... 96 | $body_bytes_sent 请求的内容有多少字节 97 | $http_referer 上一个页面来自哪里(从哪里跳转过来) 98 | $http_user_agent 用户代理(用了什么浏览器访问) 99 | 100 | 101 | 102 | #这说明 该server, 它的访问日志的文件,使用的格式main格式. 103 | access_log logs/host.access.log main; 104 | ``` 105 | 106 | 另外可以写一个sh脚本,每天半夜切分log日志,避免log每天累积造成文件过大 107 | 108 | ``` shell 109 | #!/bin/bash 110 | base_path='/usr/local/nginx/logs' 111 | log_path=$(date -d yesterday +"%Y%m") 112 | day=$(date -d yesterday +"%d") 113 | mkdir -p $base_path/$log_path 114 | mv $base_path/access.log $base_path/$log_path/access_$day.log 115 | #echo $base_path/$log_path/access_$day.log 116 | kill -USR1 `cat /usr/local/nginx/logs/nginx.pid` 117 | 118 | #Crontab 编辑定时任务 119 | 01 00 * * * /xxx/path/b.sh 每天0时1分(建议在02-04点之间,系统负载小) 120 | 121 | ``` 122 | 123 | - 配置定位 124 | 125 | ```shell 126 | #location 的语法 127 | location [=|~|~*|^~] patt { 128 | ... 129 | } 130 | #中括号可以不写任何参数,此时称为一般匹配 131 | #也可以写参数 132 | #因此,大类型可以分为3种 133 | #首先看有没有精准匹配,如果有,则停止匹配过程,若没有向下匹配到最符合的location 134 | location = patt {} #[精准匹配] 135 | location patt{} #[一般匹配] 136 | location ~ patt{} #[正则匹配] 137 | ``` 138 | 139 | - 配置反向代理和负载均衡 140 | 141 | ```shell 142 | http { 143 | ... 144 | #负载均衡服务器池 145 | upstream xxx { 146 | server 127.xx.xx.xx1; 147 | server 127.xx.xx.xx2; 148 | } 149 | server { 150 | liseten 80; 151 | server_name localhost; 152 | location / { 153 | #用户真实IP 154 | proxy_set_header X-Real-IP $remote_addr; 155 | proxy_pass http://xxx #upstream 对应自定义名称 156 | include proxy.conf; 157 | } 158 | } 159 | } 160 | ``` 161 | 162 | -------------------------------------------------------------------------------- /22. ShardingJDBC.md: -------------------------------------------------------------------------------- 1 | # 22.Sharding-JDBC 2 | 3 | [toc] 4 | 5 | > Sharding-JDBC官方文档地址:https://shardingsphere.apache.org/document/current/cn/features/ 6 | > 7 | > 其他文章: 8 | > 9 | > 分库分表基础:https://www.yuque.com/lexiangqizhong/java/pmbya5 10 | > 11 | > 数据库分库分表思路:https://www.cnblogs.com/butterfly100/p/9034281.html 12 | 13 | ### 分库分表的方式 14 | 15 | - 垂直分库 16 | 17 | 由于垂直分表,还是将表放在同一个库中,表多了必然会造成CPU,内存,IO的竞争。 18 | 19 | 定义:通过按照业务将表进行分类,分布到不同的数据库上,每个库可以在不同的服务器上 20 | 21 | 优点: 22 | 23 | 1. 解决业务的耦合,业务清晰 24 | 2. 能对不同业务的数据进行分级管理、维护、监控、扩展等 25 | 3. 高并发场景下,垂直分库一定程度的提升IO、数据库连接数、降低单机硬件资源的瓶颈 26 | 27 | 拆分原则:根据不同的业务进行拆分 28 | 29 | - 水平分库 30 | 31 | 定义:把同一个表的数据按一定规则(比如 IDHash%库数量)拆分到不同的数据库中,每个库可以放在不同的服务器上 32 | 33 | 优点: 34 | 35 | 1. 解决了单库大数据,高并发的性能瓶颈 36 | 2. 减少了IO竞争,锁竞争,提高了系统稳定性,某个库出现问题,仍然有部分数据可用提高了系统的可用性 37 | 38 | - 垂直分表 39 | 40 | 定义:将一个表按照字段分成多个表,每个表存储其中一部分字段 41 | 42 | 优点: 43 | 44 | 1. 避免IO争抢,为什么大字段效率低,第一由于数据量本身大,需要更长的读取时间;第二跨页,页是数据库存储单位,很多查找及定位操作都是以页为单位,单页内的数据行越多数据库整体性能越好,而大字段占用空间大,单页内存储行数少,因此IO效率低;第三,数据库以行为单位将数据库加载到内存中,这样表中字段长度较短且访问频率较高,内存能加载更多的数据,命中率更高,减少了磁盘IO,从而提升数据库性能 45 | 2. 减少锁表的几率,在通过update更新表字段的时候,会将该条记录锁定,而将字段拆分后,能减少锁表几率。如果通过冷热数据进行字段拆分,还将提供热数据的操作效率 46 | 47 | 常见拆分原则: 48 | 49 | 1. 把不常用的字段单独放在一张表中 50 | 2. 把text、blob等大字段拆分放入附表中 51 | 3. 经常组合查询的列放入同一张表 52 | 53 | - 水平分表 54 | 55 | 定义:在同一个库内,把同一个表的数据按一定规则拆分到多个表中 56 | 57 | 优点: 58 | 59 | 1. 优化单一表数据量过大而产生的性能问题 60 | 2. 避免IO争抢并减少锁表的几率 61 | 62 | ### 分库分表使用 like 查询,是否能查询出来?性能如何?会去查询所有的库和表吗? 63 | 64 | 分库分表使用 like 查询是有限制的。目前 Shariding-JDBC 不支持 like 语句中包含分片键,但不包含分片键的 like 语句可以正确执行。 65 | 至于 like 性能问题,是与数据库相关的,Shariding-JDBC 仅仅是解析 SQL 以及路由至正确的数据源而已。 66 | 是否会查询所有的库和表是根据分片键决定的,如果 SQL 中不包括分片键,就会查询所有库和表,这个和是否有 like 没有关系。 67 | 68 | ### Sharding-JDBC 与 Mycat 有一定的相似性,区别点在于对于 SQL 语句的自解析上,是否可以这么理解? 69 | 70 | 从设计理念上看确实有一定的相似性。 71 | 72 | 主要流程都是 `SQL 解析 -> SQL 改写 -> SQL 路由 -> SQL 执行 -> 结果归并`。但架构设计上是不同的。 73 | 74 | ShardingJDBC分片架构图 75 | 76 | Mycat 是基于 Proxy,它复写了 MySQL 协议,将 Mycat Server 伪装成一个 MySQL 数据库,而 Sharding-JDBC 是基于 JDBC 接口的扩展,是以 jar 包的形式提供轻量级服务的。 77 | 78 | SQL 解析这块,现在的 Shariding-JDBC 和 Mycat 也比较相似,都是使用 Druid 作为 SQL 解析的基础类库。但 Sharding-JDBC 正在重写 SQL 解析这块,是去掉 Duird 的完全自研版本。不可否认 Druid 是一个优秀的连接池,而且 SQL 解析这块做得也很强,但它毕竟不是一个专门为了 Sharding 而做的 SQL 解析器,它的大致解析流程是 **Lexer -> Parser -> AST -> Vistor**,使用者需要实现它的 Vistor 接口,将自己的业务逻辑在 Vistor 中实现,因此需要通过 Vistor 再生成 SharidingContext,而抽象语法树 AST,也需要对 SQL 完全理解。 79 | 80 | Sharding-JDBC 自研的 SQL 解析器,对于 Sharding 不相关的关键词采用跳过的方法,整体解析流程简化为 **Lexer -> Parser -> SharidingContext**,在性能以及实现复杂度上都有所突破。 81 | 82 | ### 分库分表需要考虑的点 83 | 84 | 1. 容量规划:现有的数据量有多大,每天或者每月增长量是多少。现在需要分多少个库表,分完能够支撑多长时间。 85 | 2. 分库分表策略确定:数据如何分布均匀,分多少库 分多少表。按范围分还是年月分还是HASH取模啥的。 86 | 3. 扩容等问题。一旦现有容量到达极限,如果进行扩容?扩容过程中数据迁移量有多少? 87 | 4. 如果进行历史数据迁移。 88 | 89 | ### 分库分表后带来的问题 90 | 91 | 1. 事务问题: 92 | 93 | ShardingJDBC提供本地事务、两阶段事务、柔性事务 94 | 95 | > https://shardingsphere.apache.org/document/current/cn/features/transaction/ 96 | 97 | 2. 跨节点join的问题: 98 | 99 | - 换条技术栈:使用ES后者其他NOSQL数据库。 100 | 101 | - 分两次查询实现。在第一次查询的结果集中找出关联数据的id,然后根据这些id发起第二次请求得到关联数据。 102 | 103 | 3. 跨表或跨库的count、order by、group by以及聚合函数问题。 104 | 这些是一类问题,因为它们都需要基于全部数据集合进行计算。 105 | 106 | 解决方案:与解决跨节点join问题的类似,分别在各个节点上得到结果后在应用程序端进行合并。和join不同的是每个结点的查询可以并行执行,因此很多时候它的速度要比单一大表快很多。但如果结果集很大,对应用程序内存的消耗是一个问题。 107 | 108 | 4. 非分表字段查询问题:再加一张中间表或者换条技术栈。 109 | 110 | 5. 跨分片的排序分页 111 | 一般来讲,分页时需要按照指定字段进行排序。当排序字段就是分片字段的时候,我们通过分片规则可以比较容易定位到指定的分片,而当排序字段非分片字段的时候,情况就会变得比较复杂了。为了最终结果的准确性,我们需要在不同的分片节点中将数据进行排序并返回,并将不同分片返回的结果集进行汇总和再次排序,最终再返回给用户。 112 | 113 | > Sharding JDBC实现的归并引擎:https://shardingsphere.apache.org/document/current/cn/features/sharding/principle/merge 114 | 115 | 6. 全局ID 116 | 117 | - UUID:是一种最简单的实现,但是缺点明显,由于uuid非常长,占用空间大,并且索引的创建和基于索引的查询都会有一定的性能问题。 118 | 119 | - 使用数据库的表,专门生成id:创建一张表,专门用来获取id ,但是这种方案性能瓶颈明显,所有的插入操作都下需要访问这张表,很容易就成为系统性能瓶颈,并且存在单点问题,即使使用主从模式,也只能解决单点问题。 120 | 121 | - 雪花算法:由毫秒级时间41位 机器ID 10位 毫秒内序列12位组成,实现简单。整体按照时间自增排序,不会产生id碰撞,效率极高。但是存在时钟回拨的id碰撞风险 122 | 123 | - Redis自增:这个就是依赖redis的单线程特性,使用自增integer来保证全局唯一,性能也很好。 124 | 125 | > Sharding JDBC 内置UUID和雪花算法 两种主键生成器 126 | > 127 | > https://shardingsphere.apache.org/document/current/cn/features/sharding/concept/key-generator/ 128 | 129 | ### 如何把系统不停机迁移到分库分表 130 | 131 | **面试题** 132 | 133 | 现在有一个未分库分表的系统,未来要分库分表,如何设计才可以让系统从未分库分表动态切换到分库分表上? 134 | 135 | **面试官心里分析** 136 | 137 | 你看看,你现在已经明白为啥要分库分表了,你也知道常用的分库分表中间件了,你也设计好你们如何分库分表的方案了(水平拆分、垂直拆分、分表),那问题来了,你接下来该怎么把你那个单库单表的系统给迁移到分库分表上去? 138 | 139 | 所以这都是一环扣一环的,就是看你有没有全流程经历过这个过程。 140 | 141 | **友情提示:** 142 | 143 | 假设,你现有有一个单库单表的系统,在线上在跑,假设单表有600万数据 144 | 145 | 3个库,每个库里分了4个表,每个表要放50万的数据量 146 | 147 | 假设你已经选择了一个分库分表的数据库中间件,sharding-jdbc,mycat,都可以 148 | 149 | 你怎么把线上系统平滑地迁移到分库分表上面去 150 | 151 | sharding-jdbc:自己上官网,找一个官网最基本的例子,自己写一下,试一下,跑跑看,是非常简单的 152 | 153 | mycat:自己上官网,找一个官网最基本的例子,自己写一下,试一下看看 154 | 155 | 1个小时以内就可以搞定了 156 | 157 | **面试题剖析** 158 | 159 | 这个其实从low到高大上有好几种方案,我们都玩儿过,我都给你说一下 160 | 161 | **1. 停机迁移方案** 162 | 163 | 我先给你说一个最low的方案,就是很简单,大家伙儿凌晨12点开始运维,网站或者app挂个公告,说0点到早上6点进行运维,无法访问。。。。。。 164 | 165 | 接着到0点,停机,系统挺掉,没有流量写入了,此时老的单库单表数据库静止了。然后你之前得写好一个导数的一次性工具,此时直接跑起来,然后将单库单表的数据哗哗哗读出来,写到分库分表里面去。 166 | 167 | 导数完了之后,就ok了,修改系统的数据库连接配置啥的,包括可能代码和SQL也许有修改,那你就用最新的代码,然后直接启动连到新的分库分表上去。 168 | 169 | 验证一下,ok了,完美,大家伸个懒腰,看看看凌晨4点钟的北京夜景,打个滴滴回家吧! 170 | 171 | 但是这个方案比较low,谁都能干,我们来看看高大上一点的方案。 172 | 173 | **2.双写迁移方案** 174 | 175 | 这个是我们常用的一种迁移方案,比较靠谱一些,不用停机,不用看北京凌晨4点的风景 176 | 177 | 简单来说,就是在线上系统里面,之前所有写库的地方,增删改操作,除了对老库增删改,加上对新库的增删改,这就是所谓双写,同时写俩库,老库和新库。 178 | 179 | 然后系统部署之后,新库数据差太远,用之前说的导数工具,跑起来读老库数据写新库,写的时候要根据gmt_modified这类字段判断这条数据最后修改的时间,除非是读出来的数据在新库里没有,或者是比新库的数据新才会写。 180 | 181 | 接着导一万轮之后,有可能数据还是存在不一致,那么就程序自动做一轮校验,比对新老库每个表的每条数据,接着如果有不一样的,就针对那些不一样的,从老库读数据再次写。反复循环,直到两个库每个表的数据都完全一致为止。 182 | 183 | 接着当数据完全一致了,就ok了,基于仅仅使用分库分表的最新代码,重新部署一次,不就仅仅基于分库分表在操作了么,还没有几个小时的停机时间,很稳。所以现在基本玩儿数据迁移之类的,都是这么干了。 184 | 185 | 186 | 187 | ### 如何设计可以动态扩容缩容的分库分表方案? 188 | 189 | **面试题** 190 | 191 | 如何设计可以动态扩容缩容的分库分表方案? 192 | 193 | **面试官心里分析** 194 | 195 | (1)选择一个数据库中间件,调研、学习、测试; 196 | (2)设计你的分库分表的一个方案,你要分成多少个库,每个库分成多少个表,3个库每个库4个表; 197 | (3)基于选择好的数据库中间件,以及在测试环境建立好的分库分表的环境,然后测试一下能否正常进行分库分表的读写; 198 | (4)完成单库单表到分库分表的迁移,双写方案; 199 | (5)线上系统开始基于分库分表对外提供服务; 200 | (6)扩容了,扩容成6个库,每个库需要12个表,你怎么来增加更多库和表呢? 201 | 202 | 这个是你必须面对的一个事儿,就是你已经弄好分库分表方案了,然后一堆库和表都建好了,基于分库分表中间件的代码开发啥的都好了,测试都ok了,数据能均匀分布到各个库和各个表里去,而且接着你还通过双写的方案咔嚓一下上了系统,已经直接基于分库分表方案在搞了。 203 | 204 | 那么现在问题来了,你现在这些库和表又支撑不住了,要继续扩容咋办?这个可能就是说你的每个库的容量又快满了,或者是你的表数据量又太大了,也可能是你每个库的写并发太高了,你得继续扩容。 205 | 206 | 这都是玩儿分库分表线上必须经历的事儿 207 | 208 | **面试题剖析** 209 | 210 | **1.停机扩容** 211 | 212 | 这个方案就跟停机迁移一样,步骤几乎一致,唯一的一点就是那个导数的工具,是把现有库表的数据抽出来慢慢倒入到新的库和表里去。但是最好别这么玩儿,有点不太靠谱,因为既然分库分表就说明数据量实在是太大了,可能多达几亿条,甚至几十亿,你这么玩儿,可能会出问题。 213 | 214 | 从单库单表迁移到分库分表的时候,数据量并不是很大,单表最大也就两三千万。 215 | 216 | 写个工具,多弄几台机器并行跑,1小时数据就导完了。 217 | 218 | 3个库+12个表,跑了一段时间了,数据量都1亿~2亿了。光是导2亿数据,都要导个几个小时,6点,刚刚导完数据,还要搞后续的修改配置,重启系统,测试验证,10点才可以搞完。 219 | 220 | **2.优化后的方案** 221 | 222 | 一开始上来就是32个库,每个库32个表,1024张表 223 | 224 | 我可以告诉各位同学说,这个分法,第一,基本上国内的互联网肯定都是够用了,第二,无论是并发支撑还是数据量支撑都没问题。 225 | 226 | 每个库正常承载的写入并发量是1000,那么32个库就可以承载32 * 1000 = 32000的写并发,如果每个库承载1500的写并发,32 * 1500 = 48000的写并发,接近5万/s的写入并发,前面再加一个MQ,削峰,每秒写入MQ 8万条数据,每秒消费5万条数据。 227 | 228 | 有些除非是国内排名非常靠前的这些公司,他们的最核心的系统的数据库,可能会出现几百台数据库的这么一个规模,128个库,256个库,512个库。 229 | 230 | 1024张表,假设每个表放500万数据,在MySQL里可以放50亿条数据。 231 | 232 | 每秒的5万写并发,总共50亿条数据,对于国内大部分的互联网公司来说,其实一般来说都够了。 233 | 234 | 谈分库分表的扩容,第一次分库分表,就一次性给他分个够,32个库,1024张表,可能对大部分的中小型互联网公司来说,已经可以支撑好几年了。 235 | 236 | 一个实践是利用32 * 32来分库分表,即分为32个库,每个库里一个表分为32张表。一共就是1024张表。根据某个id先根据32取模路由到库,再根据32取模路由到库里的表。 237 | 238 | 刚开始的时候,这个库可能就是逻辑库,建在一个数据库上的,就是一个mysql服务器可能建了n个库,比如16个库。后面如果要拆分,就是不断在库和mysql服务器之间做迁移就可以了。然后系统配合改一下配置即可。 239 | 240 | 比如说最多可以扩展到32个数据库服务器,每个数据库服务器是一个库。如果还是不够?最多可以扩展到1024个数据库服务器,每个数据库服务器上面一个库一个表。因为最多是1024个表么。 241 | 242 | 这么搞,是不用自己写代码做数据迁移的,都交给dba来搞好了,但是dba确实是需要做一些库表迁移的工作,但是总比你自己写代码,抽数据导数据来的效率高得多了。 243 | 244 | 哪怕是要减少库的数量,也很简单,其实说白了就是按倍数缩容就可以了,然后修改一下路由规则。 245 | 246 | 对2 ^ n取模 247 | 248 | orderId 模 32 = 库 249 | orderId / 32 模 32 = 表 250 | 251 | orderId 库 表 252 | 253 | 259 3 8 254 | 1189 5 5 255 | 352 0 11 256 | 4593 17 15 257 | 258 | 1、设定好几台数据库服务器,每台服务器上几个库,每个库多少个表,推荐是32库 * 32表,对于大部分公司来说,可能几年都够了; 259 | 260 | 2、路由的规则,orderId 模 32 = 库,orderId / 32 模 32 = 表; 261 | 262 | 3、扩容的时候,申请增加更多的数据库服务器,装好mysql,倍数扩容,4台服务器,扩到8台服务器,16台服务器; 263 | 264 | 4、由dba负责将原先数据库服务器的库,迁移到新的数据库服务器上去,很多工具,库迁移,比较便捷; 265 | 266 | 5、我们这边就是修改一下配置,调整迁移的库所在数据库服务器的地址; 267 | 268 | 6、重新发布系统,上线,原先的路由规则变都不用变,直接可以基于2倍的数据库服务器的资源,继续进行线上系统的提供服务。 269 | 270 | ![image-20240903130206635](https://itsaysay-1313174343.cos.ap-shanghai.myqcloud.com/blog/image-20240903130206635.png) -------------------------------------------------------------------------------- /23.ES.md: -------------------------------------------------------------------------------- 1 | # 23.ES 2 | 3 | ### ES的分布式架构原理 4 | 5 | 核心思想是在多台机器上启动多个ES进程实例,组成一个ES集群。ES中存储数据的基本单位是索引,用来存储具有共同特性的文档集合,一个索引差不多就相当于Mysql中的表。为了提高可伸缩性和容错性,ES会将索引划分为多个分片,每个分片都是一个独立的Lucene索引,可以部署在集群中的任何节点上,一个索引包含一个或多个主分片和零个或多个副本分片,主分片负责数据的写入,而副本分片则用于数据的容错和读请求的分流。 6 | 7 | ### ES写入数据的工作原理 8 | 9 | 10 | 11 | ### ES在数据量很大的情况下如何提高性能 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /3.Java Lock.md: -------------------------------------------------------------------------------- 1 | # 3.锁 2 | 3 | [TOC] 4 | 5 | > 《Java并发编程的艺术》、《Java并发编程之美》 6 | 7 | ### 乐观锁和悲观锁 8 | 9 | 两者原本是数据库中的概念,但Java锁中也有类似的思想。 10 | 11 | 乐观锁:认为数据在一般情况下不会造成冲突,在访问记录前不会加排他锁,而是在进行数据提交更新时,才会对数据冲突与否进行检测 12 | 13 | 悲观锁:认为数据很容易被其他线程修改,在处理数据前就加锁,并在整个数据处理过程中数据都处于锁定状态 14 | 15 | ### 公平锁、非公平锁 16 | 17 | 公平锁:根据线程请求锁的顺序来获取锁 18 | 非公平锁:抢占式获取锁 19 | 20 | ### 什么是死锁,什么情况下产生死锁 21 | 22 | 具备以下4个条件就会产生死锁: 23 | 24 | - 互斥条件:指线程对已经获取到的资源进行排它性使用,即该资源同时只由一个线程占用。如果此时还有其他线程请求获取该资源,则请求者只能等待,直至占有资源的线程释放该资源 25 | - 请求并持有条件:指一个线程已经持有了至少一个资源,但又提出了新的资源请求,而新的资源已被其他线程占有,所以当前线程会被阻塞,但阻塞的同时并不释放自己已经获取的资源 26 | - 不可剥夺条件:指线程获取到的资源在自己使用完之前不能被其他线程抢占,只有在自己使用完毕后才由自己释放该资源 27 | - 循环等待:发生死锁的时候,必然存在一个(线程-资源)的环形链,即线程一在等待线程二占用的资源,线程二在等待线程三等待的资源... 28 | 29 | 例如: 30 | 31 | ```java 32 | public class DeadLock { 33 | 34 | private static Object obj = new Object(); 35 | private static Object obj2 = new Object(); 36 | 37 | public static void main(String[] args) throws InterruptedException { 38 | Thread t = new Thread(() -> { 39 | System.out.println("线程1,开始获取obj1锁"); 40 | synchronized (obj) { 41 | System.out.println("线程1,获取obj1锁成功"); 42 | System.out.println("线程1,开始获取obj2锁"); 43 | //休眠让两个线程都获取到对应的锁 44 | sleep(1); 45 | synchronized (obj2) { 46 | System.out.println("线程1,获取obj2锁成功"); 47 | 48 | } 49 | } 50 | }); 51 | t.start(); 52 | 53 | Thread t2 = new Thread(() -> { 54 | System.out.println("线程2,开始获取obj2锁"); 55 | synchronized (obj2) { 56 | System.out.println("线程2,获取obj2锁成功"); 57 | System.out.println("线程2,开始获取obj1锁"); 58 | sleep(1); 59 | synchronized (obj) { 60 | System.out.println("线程2,获取obj1锁成功"); 61 | } 62 | } 63 | }); 64 | t2.start(); 65 | t2.join(); 66 | } 67 | 68 | public static void sleep(long second){ 69 | try { 70 | Thread.sleep(second * 1000); 71 | } catch (InterruptedException e) { 72 | e.printStackTrace(); 73 | } 74 | } 75 | } 76 | ``` 77 | 78 | 79 | 80 | ### 如何 避免死锁 81 | 82 | 1. 使线程按照指定的顺序获取锁,并释放锁 83 | 84 | ``` 85 | Thread 1: 86 | lock A 87 | lock B 88 | 89 | Thread 2: 90 | wait for A 91 | lock C (when A locked) 92 | 93 | Thread 3: 94 | wait for A 95 | wait for B 96 | wait for C 97 | ``` 98 | 99 | 2. 设置获取锁超时时间,超过时间,自动放弃获取锁,并释放已经持有的锁,使用lock.tryLock(timeount)代替synchronized 100 | 101 | 3. 避免一个线程同时获取多个锁 102 | 103 | ### 什么是活锁 104 | 105 | 活锁也是一种死锁,死锁的话,所有线程都处于阻塞状态,活锁是由于某些条件没有满足,导致一直重复尝试,但有可能自行解开,比如设置了重试次数限制,或者超时时间 106 | 107 | ### sleep 、wait、yield的区别 108 | 109 | sleep: 110 | 111 | - 让当前线程休眠指定时间 112 | - 不释放锁资源 113 | - 可通过调用interrupt()方法来唤醒休眠线程 114 | 115 | wait: 116 | 117 | - 让当前线程进入等待状态,当其他线程调用notify或者notifyAll方法时,当前线程进入就绪状态 118 | - 当前线程会释放已获取的锁资源,并进入等待队列 119 | - 只能在synchronized中使用 120 | 121 | yield: 122 | 123 | - 让出线程当前的CPU执行时间,当前线程进入就绪状态,不阻塞当前线程,只是让同优先级或者更高优先级的线程优先执行 124 | - 线程下次调度时依旧有可能执行到 125 | 126 | ### 什么是虚假唤醒?如何避免 127 | 128 | AB线程执行了wait()方法,C线程执行了notifyAll()方法唤醒了它们,AB线程就都开始执行,但其中只有一个线程能执行成功,另外一个线程会得到错误的结果。 129 | 130 | 避免方式是将wait()方法包裹在while(条件)中,进行循环判断 131 | 132 | ```java 133 | synchronized (someObject) { 134 | while (!condition) { 135 | someObject.wait(); 136 | } 137 | // 现在 condition 为 true,执行你的操作 138 | } 139 | ``` 140 | 141 | ### Synchronized原理 142 | 143 | Synchronized可以修饰普通方法、同步方法块、静态方法; 144 | 普通方法锁是当前实例对象 145 | 146 | 静态方法锁是当前类的Class对象 147 | 148 | 同步方法块锁是Synchonized配置的对象; 149 | 用的锁是存在对象头里的,根据mark word的锁状态来判断锁,如果锁只被同一个线程持有使用的是偏向锁,不同线程互相交替持有锁使用轻量级锁,多线程竞争使用重量级锁。锁会按偏向锁->轻量级锁->重量级锁 升级,称为锁膨胀 150 | 151 | > 扩展:https://github.com/farmerjohngit/myblog/issues/12 152 | 153 | ### synchronized和Lock的区别 154 | 155 | 1. synchronized 是Java内置关键字,Lock是Java类 156 | 2. synchronized 无法显式的判断是否获取锁的状态,Lock可以判断是否获取到锁 157 | 3. synchronized 会自动释放锁,Lock需要在finally中手工释放锁 158 | 4. synchronized 不同线程获取锁只有一个线程能获取成功,其他线程会一直阻塞直到获取锁,Lock有阻塞锁,也有非阻塞锁,阻塞锁还有尝试设置,功能更强 159 | 5. synchronized 可重入,不可中断,非公平,Lock锁可重入,可判断,有公平锁,非公平锁 160 | 6. Lock锁适合大量同步代码的同步问题,synchronized锁适合代码少量的同步问题 161 | 162 | ### synchronized 可重入是怎么实现的 163 | 164 | 可重入是指:当一个线程持有一个锁对象之后,再次去获取同一个锁时能够成功获取。 165 | 166 | 因为synchronized使用的是锁对象,当某个线程第一次持有锁后,会修改锁对象的mark word锁状态为偏向锁,偏向锁会在当前线程的栈帧中建立一个锁记录空间,mark word会将指针指向栈中的锁记录。当线程再次获取锁对象的时候,会检查mark word 中的指针是否指向当前线程的栈帧,如果是就直接获取锁,如果不是就需要竞争 167 | 168 | ### ReentrantLock可重入性怎么实现的? 169 | 170 | 由于ReentrantLock是通过AQS来实现的,其使用了AQS的state状态值来表示线程获取该锁的可重入次数,默认情况下state为0表示当前锁没有被任何线程持有,当一个线程获取该锁时会尝试使用**CAS设置state值为1**,如果CAS设置成功则当前线程获取了该锁,然后**记录该锁的持有者为当前线程**,在该线程没有释放锁的情况下第二次获取该锁后,**状态值被设置2**,这就是可以重入次数,在释放锁的时候,需要通过CAS将状态值减1,直到状态值为0,表示当前线程释放该锁 171 | 172 | ### 非公平锁和公平锁在ReetrantLock里的实现过程是怎样的 173 | 174 | 如果一个锁是公平的,那么锁的获取顺序就应该符合请求的绝对时间顺序,FIFO。 175 | 176 | 对于非公平锁,只要CAS设置同步状态成功,则表示当前线程获取了锁,而公平锁还需要判断当前节点是否有前驱节点,如果有,则表示有线程比当前线程更早请求获取锁,因此需要等待前驱线程获取并释放锁之后才能继续获取锁。 177 | 178 | ### 自旋锁、自适应自旋、锁消除、锁粗化、轻量级锁、偏向锁、重量级锁概念 179 | 180 | `自旋锁`:开启线程执行一个忙循环,直到需要更新的值为期待值为止 181 | `自适应自旋`:自旋时间不再固定,由前一次在同一个锁上的自旋时间及锁的拥有者状态来决定,比如在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也很有可能再次成功,进而它将自旋等待更长时间,以期望成功获取锁,如果很少成功获得过锁,那很可能会忽略掉自旋过程,以避免CPU资源浪费。 182 | `锁消除`:JIT在运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行消除 183 | `锁粗化`:如果虚拟机探测到有一串零碎的操作都对同一个对象加锁,将会把加锁同步的范围扩展到整个序列的外部 184 | `轻量级锁`:加锁是通过同步对象的对象头进行操作的,首先会在当前线程的栈帧中建立一个名为锁记录的空间,存储锁对象目前的Mark Word拷贝,会加Displaced前缀,然后通过CAS尝试将对象的Mark Word更新为指向Lock Record的指针,如果成功,就获得了该对象的锁,如果失败,会检查Mark Word是否指向当前线程的栈帧,如果是就说明已经获得了锁,如果没有就说明有其他线程抢占,轻量锁就会膨胀成重量级锁;解锁也是通过CAS来操作,就是将Mark Word 替换为原来的值 185 | `偏向锁`:锁偏向于第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他的线程获取,则持有偏向锁的线程将永远不需要再同步。-XX:+UseBiasedLocking 开启偏向锁 186 | 187 | `重量级锁`:也叫互斥锁,一种悲观锁,会阻塞线程,通过对象内部的monitor锁来实现,monitor锁依赖底层操作系统的MutexLock互斥锁来实现 188 | 189 | ### AbstractQueuedSynchronizer的作用 190 | 191 | 抽象同步队列简称AQS,是实现同步器的基础组件,并发包中的锁都是基于其实现的,关键是**先进先出的队列,state状态**,并且定义了 ConditionObject ,拥有两种线程模式,**独占模式和共享模式** 192 | 193 | - AQS核心思想 194 | 195 | 如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制使用CLH队列实现的,即将暂时获取不到锁的线程加入到队列中 196 | 197 | > CLH(Craig,Landin,and Hagersten)(3个人名)队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS是将每条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node)来实现锁的分配, 并保持了上下节点,当前请求资源的线程 198 | 199 | 200 | 201 | 202 | 203 | ### JDK8新增的锁 204 | 205 | StampedLock 提供了三种模式的读写控制,当调用获取锁的系列函数时,会返回一个long型变量,支持在一定条件下三种模式的相互转换 206 | 写锁writeLock: 一个排它锁或者独占锁,并且写锁不可重入 207 | 悲观读锁readLock: 共享锁,在没有线程独占获取写锁的情况下,多个线程可以同时获取该锁,如果已经有其他线程持有写锁,则其他线程请求读锁会被阻塞 208 | 乐观读锁tryOptimisticRead: 在操作数据前并没有通过CAS设置锁的状态,仅通过位运算测试 209 | 210 | -------------------------------------------------------------------------------- /4.JVM.md: -------------------------------------------------------------------------------- 1 | # 4.JVM知识 2 | 3 | [TOC] 4 | 5 | > 《深入理解Java虚拟机:JVM高级特性与最佳实践(最新第二版)》 6 | 7 | ### JVM运行时内存区域划分 8 | 9 | image-20190922235827314 10 | 11 | 线程独享区域:程序计数器,本地方法栈,虚拟机栈 12 | 13 | 线程共享区域:元空间(<=1.7方法区), 堆 14 | 15 | 16 | 程序计数器:线程私有,是一块较小的内存空间,可以看做是当前线程执行的字节码指示器,也是唯一的没有定义OOM的区块 17 | 18 | 本地方法栈: 用于执行Native 方法时使用 19 | 虚拟机栈:用于存储局部变量,操作数栈,动态链接,方法出口等信息 20 | 21 | 元空间:存储已被虚拟机加载的类元信息,常量,静态变量,即时编译器编译后的代码等数据依旧存储在方法区中,方法区位于堆中 22 | 23 | 堆:存储对象实例 24 | 25 | 26 | 27 | **示例:** 28 | 29 | ```java 30 | /** 31 | * @author: jujun chen 32 | * @description: 使用了CGLIB来动态生成类,元空间存储类信息,-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m 33 | * 如果只设置堆的大小,并不会溢出 34 | * @date: 2019/4/7 35 | */ 36 | public class JavaMetaSpaceOOM { 37 | 38 | static class OOMObject{} 39 | public static void main(final String[] args) { 40 | while (true){ 41 | Enhancer enhancer = new Enhancer(); 42 | enhancer.setSuperclass(OOMObject.class); 43 | enhancer.setUseCache(false); 44 | enhancer.setCallback(new MethodInterceptor() { 45 | @Override 46 | public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 47 | return methodProxy.invokeSuper(o,objects); 48 | } 49 | }); 50 | enhancer.create(); 51 | } 52 | } 53 | 54 | } 55 | ``` 56 | 57 | 58 | 59 | ### OOM,及SOE的示例、原因,排查方法 60 | 61 | ```java 62 | //OOM -Xmx20m -Xms20m -XX:+HeapDumpOnOutOfMemoryError 63 | public class OOMTest { 64 | public static void main(String[] args) { 65 | List objList = new ArrayList(); 66 | while(true) { 67 | objList.add(new Object()); 68 | } 69 | } 70 | } 71 | 72 | //SOE栈异常 -Xss125k 73 | public class SOETest() { 74 | static int count = 0; 75 | public static void main(String[] args) { 76 | try { 77 | stackMethod(); 78 | } catch(Error err) { 79 | err.printStackTrace(); 80 | System.out.println("执行count=" + count); 81 | } 82 | } 83 | private static void stackMethod() { 84 | count ++; 85 | stackMethod(); 86 | } 87 | } 88 | ``` 89 | 90 | - OOM排查:如果能看到日志,可以从打印的日志中获取到发送异常的代码行,再去代码中查找具体哪块的代码有问题。如果没有记录日志,通过设置的 -XX:+HeapDumpOnOutOfMemoryError 在发生OOM的时候生成.hprof文件,再导入JProfiler能够看到是由于哪个对象造成的OOM,再通过这个对象去代码中寻找 91 | - SOE排查:栈的深度一般为1000-2000深度,超过了深度或者超过了栈大小就会导致SOE,通过打印的日志定位错误代码位置,检测是否有无限递归,发生了死循环等情况,修改代码 92 | 93 | ### 如何判断对象可以回收或存活 94 | 95 | 判断是否可以回收,或者存活主要是看: 96 | 97 | 1. 堆中是否存在该实例 98 | 2. 加载该类的classloader是否已经被回收 99 | 3. 该类的java.lang.Class对象在任何地方没有被引用,也就是不能够通过反射方法获取该类信息 100 | 101 | ### 哪些对象可以作为GC ROOT 对象 102 | 103 | 1. 虚拟机栈(栈帧中的本地变量表)中引用的对象 104 | 2. 本地方法中JNI引用的对象 105 | 3. 方法区中的静态变量和常量引用的对象 106 | 107 | ### 常见的GC算法 108 | 109 | 1. 标记-清除算法:先标记出需要回收的对象,再清除这些被标记了的对象,缺点是:标记清除过程效率不高;会产生内存碎片 110 | 2. 复制算法:将内存划分成同等大小两块,只使用其中一块内存,当这一块的内存快用完后,将已存活的对象复制到另外一块内存,再对已使用的内存空间进行一次清理 111 | 3. 标记-整理算法:标记出已存活的对象,将对象移动到内存一端,再对端以外的内存进行清理回收 112 | 4. 分代收集算法:年轻代使用复制算法,永久代使用 标记-清除或者标记-整理算法 113 | 114 | ### 常见的JVM性能监测分析工具 115 | 116 | 1. jps 117 | 能够查看正在运行的虚拟机进程,并显示虚拟机的执行主类及进程ID 118 | 119 | 2. jstat [option vmid [interval[s|ms] [count]] ] 120 | 可以显示本地或者远程虚拟机中的类装载、内存、垃圾收集、JIT编译等运行数据 121 | 122 | 3. jinfo 123 | 实时查看和调整虚拟机的各项参数 124 | 125 | 4. jmap 126 | 生成堆转储快照 127 | 128 | 5. jhat 129 | 130 | 生成页面分析导出的堆存储快照 131 | 132 | 6. jstack 133 | 用于生成虚拟机当前时刻的线程快照 134 | 135 | 7. jstatd 136 | 137 | 启动RMI服务端程序,代理本地的Java进程,供远程计算机连接调式 138 | 139 | 8. 查看当前JVM使用的垃圾收集器 140 | 141 | java -XX:+PrintFlagFinal -version 或者 java -XX:+PrintCommandLineFlags -version 142 | 143 | 9. jconsole 144 | 145 | Java监视和管理控制台,能够监控内存,线程,类等 146 | 147 | 10. jvisualvm 148 | 149 | 多合一监视工具 150 | 151 | > 更多资料请学习官网:https://docs.oracle.com/en/java/javase/11/tools/index.html 152 | 153 | ### JVM优化 154 | 155 | 1. 响应时间优先:年轻代设的大些,直到接近系统的最低响应时间限制。年轻代设大,可以减少到达年老代的对象。对于永久代的设置需要参考:永久代并发收集的次数、年轻代和永久代回收时间比例,调整达到一个合适的值 156 | 2. 吞吐量优先:年轻代设的大些,永久代较小 157 | 158 | ### 什么时候会触发FullGC 159 | 160 | 1. 永久代空间不足 161 | 2. 手动调用触发gc 162 | 2. 元空间不足 163 | 164 | ### 类加载器有几种 165 | 166 | 1. Bootstrap ClassLoader(C++实现) 167 | 负责加载JDK自带的rt.jar包中的类文件,它是所有类加载器的父加载器,Bootstrap ClassLoader没有任何父类加载器。 168 | 2. Extension ClassLoader(ExtClassLoader)负责加载Java的扩展类库,也就是从jre/lib/ext目录下或者java.ext.dirs系统属性指定的目录下加载类。 169 | 3. System ClassLoader(AppClassLoader)负责从classpath环境变量中加载类文件,classpath环境变量通常由"-classpath" 或 "-cp" 命令行选项来定义,或是由 jar中 Mainfest文件的classpath属性指定,System ClassLoader是Extension ClassLoader的子加载器 170 | 4. 自定义加载器 171 | 172 | ### 什么是双亲委派模型?双亲委派模型的破坏 173 | 174 | 一个类在加载的时候,首先会将加载请求委派给父加载器,只有当父加载器反馈无法加载完成这个请求时,子加载器才会尝试自己加载 175 | 双亲委派模型的破坏指的是不按照双亲委派模型来加载类,比如JNDI,它的代码由启动类加载器加载,但JDNI需要调用部署在ClassPath的JNDI接口,但启动类加载器是不知道这些代码的,所以就有了线程上下文类加载器(Thread Context ClassLoader),可以通过java.lang.Thread类setContextClassLoader设置类加载器,通过这个父加载器就可以请求子类加载器完成类加载的动作。 176 | 177 | ### 类的生命周期 178 | 179 | 类的生命周期一个有7个阶段:加载、验证、准备、解析、初始化、使用、卸载 180 | 181 | - 加载: 182 | 加载阶段,虚拟机需要完成以下3件事 183 | 184 | 1. 通过类的全限定名来获取此类的二进制字节流 185 | 186 | 2. 将字节流所代表的静态存储结构转化为方法区的运行时数据结构 187 | 188 | 3. 在内存中生成代表这个类的java.lang.Class对象,作为方法区这个类的各种数据访问入口 189 | 190 | 191 | 192 | - 验证:分4个验证 193 | 194 | 1. 文件格式验证,验证是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理 195 | 196 | 2. 元数据验证,对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言规范的要求 197 | 198 | 3. 字节码验证,通过数据流和控制流分析,确定程序语义是否合法、符合逻辑 199 | 200 | 4. 符合引用验证,是对类自身以外的信息进行匹配性校验(常量池中各种符合引用) 201 | 202 | 203 | 204 | - 准备:正式为类变量分配内存并设置初始值的阶段,这里设置初始值是数据类型的默认值 205 | - 解析:虚拟机将常量池中的符号引用替换为直接引用的过程 206 | - 初始化:执行类构造器的过程 207 | 208 | ### 强引用、软引用、弱引用、虚引用 209 | 210 | 1. 强引用:大部分使用都是强引用,当内存不足时,会OOM,程序异常终止,也不会随意回收具有强引用的对象 211 | 2. 软引用:内存足够时,不会清除对象,在内存不足时就会回收这些对象 212 | 3. 弱引用:弱引用的对象,在发生GC的时候,就会被回收 213 | 4. 虚引用:虚引用主要用来跟踪垃圾回收的活动,虚引用必须和引用队列联合使用。 214 | 215 | ### 编译器会对指令做哪些优化? 216 | 217 | 编译器优化分编译期和运行期 218 | 219 | - 编译期: 220 | 1.标注检查,检查变量使用前是否已被声明、变量与赋值之间的数据类型是否能够匹配,对常量进行折叠 221 | 2.数据及控制流分析,检查诸如程序局部变量在使用前是否有赋值、是否所有的受检异常都被正确处理等问题 222 | 3.将语法糖还原为基础的语法结构 223 | 4.生成字节码 224 | - 运行期: 225 | 即时编译器JIT会把运行频繁的代码编译成与本地平台相关的机器码,并进行各种层次的优化 226 | Client Compiler: 会进行局部性的优化,分三阶段:第一阶段,一个平台独立的前端将字节码构造成一种高级中间代码表示HIR,HIR使用静态单分配(SSA)的形式来代表代码值,在字节码上做方法内联,常量传播等基础优化;第二阶段,从HIR中产生低级中间代码,在这之前会做空值检查消除,范围检查消除等。第三阶段,在LIR上分配寄存器,并在LIR上做窥孔优化,最后产生机器码 227 | Server Compiler: 会执行无用代码消除、循环展开、循环表达式外提、消除公共子表达式、常量传播、基本块重排序、范围检测消除、空值检查消除,另外还能根据解释器或Client Compiler提供的性能监控信息,进行一些不稳定的激进优化,比如守护内联、分支频率预测等 228 | 229 | - 几种经典的优化技术: 230 | 231 | 1. 公共子表达式消除 232 | 如果一个表达式E已经计算过,并且从先前的计算到现在E中所有变量的值都没有发生变化,那么E的这次出现就成为公共子表达式 233 | 234 | 2. 数组范围检查消除 235 | 编译期就判断数组是否在合理的范围内,如果在,那就可以在循环中把数组的上下界检查消除。另外还有隐式异常处理,虚拟机会注册一个Segment Fault信号的异常处理器,但如果代码经常为空,消耗时间比判空慢,但虚拟机会根据运行期收集到的信息选择使用判空还是隐式异常处理 236 | 237 | 3. 方法内联 238 | 就是把目标方法的代码复制到发起调用的方法之中,避免发生真是的方法调用 239 | 240 | 4. 逃逸分析 241 | 分析对象动态作用域,对象是否作为调用参数传递到其他方法中(方法逃逸),是否有被其他线程访问(线程逃逸)。如果没有以上情况,虚拟机会做一些高效优化:栈上分配、同步消除(去掉同步措施)、标量替换(将对象成员变量恢复到原始类型) 242 | 243 | ```java 244 | public void test() { 245 | //obj 对象只有在这个方法内部使用,并没有做为参数传递到其他方法中 246 | Object obj = new Object(); 247 | } 248 | ``` 249 | 250 | 5. 锁消除 251 | JIT检测到方法是在单线程环境中执行时,会将已有的锁消除,提高性能 252 | 253 | 6. 标量替换 254 | 将原本需要分配到堆上的对象拆解成若干个基础数据类型(标量),并将这些基础数据类型作为局部变量存储在栈上。标量通常指的是不可再分解的数据类型,如int、long、float、double以及引用类型(reference)等。这种优化技术特别适用于那些生命周期短、作用域小、且不会逃逸出当前方法或线程的对象 255 | 256 | 257 | 258 | ### Serial、Parallel、CMS、G1收集器特点 259 | 260 | image-20191008191348602 261 | 262 | img 263 | 264 | image-20191008202251538 265 | 266 | - Serial 267 | 268 | 单线程收集器,在进行垃圾收集时,必须暂停所有的工作线程直到结束,该收集器停顿时间长,-XX:+UseSerialGC 年轻代使用串行垃圾收集器,-XX:+UseSerialOldGC 老年代使用串行垃圾收集器 269 | 270 | - Parallel 271 | 272 | 采用多线程来扫描并压缩堆,停顿时间短,回收效率高,-XX:+UseParNewGC 使用并发标记扫描垃圾回收器;能够提高应用吞吐率 273 | 274 | > JDK8 默认使用:年轻代UseParallelGC,老年代UseParallelOldGC 275 | 276 | - CMS 基于“标记-清除”算法,一共分初始标记、并发标记、重新标记、并发清除,并发重置5个阶段;能够降低STW,提高用户体验 277 | 278 | 在初始标记、重新标记阶段需要STW,并且CMS收集器占用CPU资源较多,无法处理浮动垃圾 279 | 280 | 并发重置阶段重新初始化CMS数据结构和数据,为下次垃圾回收做准备 281 | 282 | 在并发标记和并发清理阶段可能会出现垃圾回收还没执行完,垃圾回收又被触发的情况,此时会发生“concurrent mode failure”,垃圾收集器进入STW,用serial old 进行回收。 283 | 284 | > (-XX:CMSInitiatingOccupancyFraction 调整老年代占用多少触发回收;-XX:+UseCMSCompactAtFullCollection 默认开启,在即将触发FullGC前对内存碎片进行整理;-XX:CMSFullGCsBeforeCompaction设置执行多少次不压缩的FullGC后,来一次带压缩的的碎片整理) 285 | 286 | - G1 可以跟用户程序并发进行垃圾收集;分代收集,将堆划分成多个大小相等的独立Region区域;空间整合,默认就会进行内存整理;可预测的停顿,G1跟踪各个Region的回收获得的空间大小和回收所需要的经验值,维护一个优先列表; 287 | 288 | 289 | 290 | ### G1 垃圾收集分类 291 | 292 | **YoungGC:** 293 | 294 | YoungGC并不是在现有的Eden区放满了就马上触发,G1会计算现有的Eden区回收大概要多久时间,如果回收时间远小于参数-XX:MaxGCPauseMills 设定的值,那么增加年轻代的region,继续给新对象存放,不会马上做Young GC,直到下一次Eden区放满,G1计算回收时间接近参数-XX:MaxGCPauseMills设定的值,就会触发Young GC 295 | 296 | **MixedGC** 297 | 298 | 不是FullGC,老年代的堆占有率达到参数(-XX:InitiatingHeapOccupancyPercent)设定的值则触发,回收所有的Young和部分Old(根据期望的GC停顿时间确定old区垃圾收集的优先顺序)以及大对象,正常情况G1的垃圾收集是先做MixedGC,主要使用复制算法,需要把各个region中的存活的对象拷贝到别的region里去,拷贝过程中如果发现没有足够的空region能够承载拷贝对象就会触发一次Full GC 299 | 300 | **Full GC** 301 | 302 | 停止系统程序,然后采用单线程进行标记、清理、和压缩整理,好空闲出来一批Region来供下一次MixedGC使用,这个过程非常耗时。(Shenandoah已经优化成多线程收集,Shenandoah可以认为是G1的升级版本) 303 | 304 | 305 | 306 | ### ZGC 307 | 308 | ZGC 是JDK11 中加入的低延迟垃圾收集器,支持16TB级别的堆,停顿时间不超过1ms,没有采用分代算法,清理过程大致分为:并发标记、并发预备重分配、并发重分配、并发重映射。 309 | 310 | ZGC 堆空间分页模型(无分代):小页面、中页面、大页面 311 | 312 | **一次ZGC流程:** 313 | 314 | 标记阶段:初始标记、并发标记、再标记,初始标记和再标记会STW 315 | 316 | 转移阶段:并发转移准备、初始转移、并发转移 317 | 318 | **ZGC常见触发时机:** 319 | 320 | - 基于分配速率的自适应算法(主要):ZAllocationSpikeTolerance控制 321 | - 基于固定时间间隔:ZCollectionInterval参数控制 322 | - 主动触发规则:Zproactive控制 323 | - 启动预热:关键词warmup 324 | 325 | -------------------------------------------------------------------------------- /5.Java Reflect_IO.md: -------------------------------------------------------------------------------- 1 | # 5.Java 反射、IO 2 | 3 | ### 反射 4 | Class类: 反射的核心类、可以获取类的属性,方法等信息 5 | Field类: Java.lang.reflec包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值 6 | Method类:Java.lang.reflec包中的类,表示类的方法,可以用来获取类中的方法信息或者执行方法 7 | Constructor类:Java.lang.reflec包中的类,表示类的构造方法 8 | 9 | 获取Class对象的3种方法: 10 | 11 | ```java 12 | //1 13 | Person p = new Person(); 14 | Class clazz = p.getClass; 15 | 16 | //2 17 | Class clazz = Person.class; 18 | 19 | //3 20 | Class clazz = Class.forName("类的全路径"); 21 | ``` 22 | 创建对象的两种方法 23 | 1.使用Class对象的newInstance(),这种方法需要Class对象对应的类有默认的空构造器 24 | 2.调用Constructor对象的newInstance(),先通过Class对象获取构造器对象,再通过构造器对象的newInstance()创建 25 | 26 | > 扩展:[【读码JDK】-带你详细了解lang.Class类(一)_java.lang.class类-CSDN博客](https://itsaysay.blog.csdn.net/article/details/125228566) 27 | 28 | ### 请说明如何通过反射获取和设置对象私有字段的值? 29 | 30 | 通过类对象的getDeclaredField()方法获取字段对象,然后通过字段对象的setAccessible(true)将其设置为可以访问,接下来就可以通过Class对象的getMethod方法获取get/set方法来获取/设置字段的值 31 | 32 | 33 | 34 | ### BIO、NIO区别 35 | BIO(Block IO): jkd1.4以前的IO模型,它是一种阻塞IO 36 | NIO(NoN-Block IO):JDK1.4以后才有的IO模型,提高了程序的性能,借鉴比较先进的设计思想,linux多路复用技术,轮询机制 37 | AIO(Asynchronous IO):JDK1.7以后才有的IO模型,相当于NIO2,相当于NIO2,学习Linux epoll模式 38 | 39 | ### Java NIO的原理 40 | 1.多路复用技术:建立连接—发送数据—服务端处理—反馈 41 | 2.轮询机制(Select模式) 42 | 3.SelectionKey: 牌号,时间的标识,唯一的身份标识 43 | 4.Buffer(数据缓冲区) 44 | 45 | Channel实现:FileChannel(文件IO)、DatagramChannel(UDP)、SocketChannel(Client)、ServerSocketChannel(Server) 46 | 47 | ```java 48 | //实例 49 | try(ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) { 50 | serverSocketChannel.socket().bind(new InetSocketAddress(3388)); 51 | 52 | Selector selector = Selector.open(); 53 | serverSocketChannel.configureBlocking(false); 54 | serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); 55 | System.out.println("服务器准备就绪,开始监听,端口3388"); 56 | 57 | while (true) { 58 | int wait = selector.select(); 59 | if (wait == 0) 60 | continue; 61 | 62 | Set keys = selector.selectedKeys(); 63 | Iterator iterator = keys.iterator(); 64 | ByteBuffer byteBuffer = ByteBuffer.allocate(1024); 65 | 66 | while (iterator.hasNext()) { 67 | SelectionKey key = iterator.next(); 68 | if (key.isAcceptable()) { 69 | //do something 70 | } else if (key.isReadable()) { 71 | //do something 72 | } else if (key.isWritable()) { 73 | //do something 74 | } 75 | 76 | iterator.remove(); 77 | } 78 | 79 | } 80 | } catch (Exception e) { 81 | e.printStackTrace(); 82 | } 83 | ``` 84 | 85 | ### 什么是AIO 86 | 87 | AIO 是基于Proactor模型的,就是异步非阻塞模型。 88 | 89 | 每个连接发送过来的请求,都会绑定一个buffer,然后通知操作系统去异步完成读,此时你的程序是会去干别的事儿的,等操作系统完成数据读取之后,就会回调你的接口,给你操作系统异步读完的数据。 90 | 91 | 然后你对这个数据处理一下,接着将结果往回写。写的时候也给操作系统一个buffer,让操作系统自己获取数据去完成写操作,写完以后再回来通知你。 -------------------------------------------------------------------------------- /7.Data Structure.md: -------------------------------------------------------------------------------- 1 | # 7.数据结构 2 | 3 | > 《数据结构与算法分析 java语言描述(原书第3版)》 4 | 5 | ### 如何构造一致性哈希算法 6 | 7 | 8 | 9 | ### 二叉树结构 10 | 11 | 二叉树每个节点至多有两个节点,左节点永远比右节点小,并且小于根节点。 12 | 13 | 查找最好时间复杂度O(longN), 最坏O(N) 14 | 15 | 插入删除操作时间复杂度跟查找差不多 16 | 17 | ### 平衡二叉树(AVL) 18 | 19 | 左右子树的高度差不超过1,并且左右子树都是平衡二叉树,超过1就旋转。 20 | 21 | 比二叉树稳定,查找时间复杂度O(logN) 22 | 23 | 插入操作最多需要旋转1次,时间复杂度O(logN)左右 24 | 25 | 删除时间复杂度O(2logN) 26 | 27 | ### 红黑树 28 | 29 | 每个节点上都有节点颜色,可以是红色或者黑色;根节点必须是黑色;每个红色节点的子节点,父节点是黑色;从任一节点到每个叶子节点的所有路径都包含相同数目的黑色节点。 30 | 31 | 查找效率最好情况下是O(logN),最坏情况下比平衡二叉树要差一些,但也比二叉树要好 32 | 33 | 插入和删除操作改变树的平衡性概率小于平衡二叉树 34 | 35 | ### B+树 和 B-树 36 | 37 | B+树 的中间节点不保存数据,所以磁盘页能容纳更多节点元素; 38 | 39 | B+树查询必须查找到叶子节点,B树只要匹配到即可不用管元素位置,因此B+树查找更稳定 40 | 41 | 对于范围查找来说,B+树只需遍历叶子节点链表即可,B树却要重复地中序遍历 42 | 43 | > 效率总结:https://blog.csdn.net/z702143700/article/details/49079107 44 | > 45 | > 区别对比:https://blog.csdn.net/wyqwilliam/article/details/82935922 46 | 47 | -------------------------------------------------------------------------------- /8.DataBase.md: -------------------------------------------------------------------------------- 1 | # 8.数据库 2 | 3 | > 《高性能Mysql(第三版)》 4 | 5 | ### 数据库三大范式、反模式 6 | 7 | 1. 强调属性的原子性约束,要求属性具有原子性,不可再分解 8 | 2. 强调记录的唯一性约束,表必须有一个主键,并且没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分 9 | 3. 强调属性冗余性的约束,即非主键列必须直接依赖于主键 10 | 11 | 反模式:如果完全按照三大范式来设计表结构,会导致业务涉及表增多,查询数据需要多表联合查询,导致sql复杂,性能变差,不利于维护,也不利于分库分表,比如会在表中冗余存储城市id对应的城市名称 12 | 13 | http://blog.720ui.com/2017/mysql_core_07_anti-pattern/ 14 | 15 | ### Mysql 架构图 16 | 17 | image-20191020162238485 18 | 19 | ### InnoDB存储结构 20 | 21 | 逻辑存储单元分为表空间(TableSpace) -> 段(segment) -> 区(extent) -> 页(page) 22 | 23 | Mysql 8.0 InnoDB架构图 24 | 25 | image-20191020223620225 26 | 27 | - 表空间:所有数据都存在表空间中,表空间分系统表空间和独立表空间。 28 | 29 | 系统表空间 30 | 31 | 在安装数据库的时候默认会初始化一个以ibdata1命名的系统表空间,存储所有数据的信息以及回滚段信息,ibdata1默认的大小是10MB,在高并发情况下,会有性能影响,建议初始大小调整为1GB。 32 | 33 | `相关教程参考:https://blog.csdn.net/demonson/article/details/79863166` 34 | 35 | 独立表空间 36 | 37 | 设置参数innodb_file_per_table = 1 ,目前MySQL默认都是独立表空间,每个表都有自己的表空间文件,存储对应表的B+数数据、索引和插入缓冲等信息,其余信息还是存储在共享表空间中 38 | 39 | 撤销表空间 40 | 41 | 包含撤销日志,初始化的时候会创建两个默认的撤销表空间 42 | 43 | 通用表空间 44 | 45 | 可以存储多个表的数据,相比独立表空间更节约元数据的内存开销 46 | 47 | 临时表空间 48 | 49 | 分会话临时表空间和全局临时表空间。会话临时表空间,在第一个请求中,会话临时表空间从临时表空间池分配给会话,最多两个临时表空间,一个用于用户创建的临时表,另一个用于优化器创建的内部临时表,当会话断开时,临时表空间将被释放进入临时表空间池中;全局临时表空间,用于存储用户创建的临时表的更改数据,用于回滚,在正常关闭或初始化中止时被删除,并在每次启动服务器时重新创建 50 | 51 | - 段 52 | 53 | 表空间由段组成,一个表通常有数据段、回滚段、索引段等,每个段由N个区和32个零散的页组成 54 | 55 | - 区 56 | 57 | 由连续的页组成,每个区大小固定1MB 58 | 59 | - 页 60 | 61 | 一个区由64个连续页组成,页默认大小16KB 62 | 63 | ### 存储引擎的 InnoDB与MyISAM区别,优缺点,使用场景 64 | 65 | ACID: 66 | 67 | 原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability) 68 | 69 | | 存储引擎 | InnoDB | MyISAM | 70 | | -------- | --------------------------- | ------------------------------------------------- | 71 | | 存储文件 | .frm表定义文件 .ibd数据文件 | .frm表定义文件
.myd数据文件
.myi 索引文件 | 72 | | 锁 | 表锁,行锁 | 表锁 | 73 | | 事务 | ACID | 不支持 | 74 | | CRUD | 读写 | 读多 | 75 | | count | 扫表 | 专门存储的地方 | 76 | | 索引结构 | B+Tree | B+Tree | 77 | 78 | ### 建立索引的原则 79 | 80 | 1. 最左匹配原则,直到遇到范围查询(>, <, between, like)就停止,比如a = 1 and b = 2 and c >3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,abd的顺序可以任意调整 81 | 2. = 和 in可以乱序,比如a = 1 and b =2 and c = 3建立(a, b, c) 索引可以任意顺序,mysql查询优化器会帮你优化 82 | 3. 尽量选择区分度高的索引,区分度公式count(distinct col)/count(*) ,表示字段不重复的比例,比例越大我们的扫描记录越少,比例一般是需要join的字段要求是0.1以上,即平均1条扫描10条记录 83 | 4. 索引不能参与计算,比如from_unixtime(create_time) = '2014-05-29' 就不能使用到索引,因为b+tree中存的都是数据表中的字段值,但进行检索时,需要把素有元素都应用到函数才能比较,成本大,应该改成create_time = unix_timestamp('2014-05-29') 84 | 5. 尽量扩展索引,不要新建索引,比如表中已经有a索引,现在要加(a,b)索引,只需要修改原来的索引即可 85 | 86 | ### 索引失效情况总结 87 | 88 | 1. 遵守最左匹配原则,中间断索引,使用范围查询 89 | 2. 在索引列上做计算 90 | 3. 索引字段使用 != 或者 <> 91 | 4. 索引字段使用 is null 或者 is not null 92 | 5. 使用通配符 %开头 93 | 6. 索引字段是字符串,查询条件没有使用字符串 94 | 7. 索引字段使用or 95 | 96 | https://blog.csdn.net/wuseyukui/article/details/72312574 97 | 98 | ### B+Tree 索引 和 哈希索引 限制 99 | 100 | B+Tree索引: 101 | 102 | 分两类,聚集索引和 普通索引 103 | 104 | 聚集索引,在创建表的时候,会创建一个主键,这个主键就是聚集索引,在索引叶子节点中存放了数据信息。InnoDB会给没有创建主键的表选择第一个不包含null值的唯一索引作为主键,如果唯一索引也没有,就会为该表创建一个6字节的rowid作为主键 105 | 106 | 普通索引,索引叶子节点并不包含所有行的数据,只保留键值,通过键来查找行数据 107 | 108 | - 全值匹配,和索引中的所有列进行匹配 109 | - 匹配最左前缀 110 | - 匹配列前缀,可以只匹配某一列的值开头部分 111 | - 匹配范围值,如果匹配的列不是主键,只能使用第一个索引来匹配范围,否则不走索引,如果匹配列是主键,可以不按照索引顺序来,走的是主键索引 112 | - 精确匹配某一个列并范围匹配另外一列 113 | 114 | 哈希索引: 115 | 116 | - 哈希索引只包含哈希值和行指针,而不存储字段值,所以不能使用索引中的值来避免读取行。不过,访问内存中行的速度很快 117 | - 哈希索引数据并不是按照索引值顺序存储的,所以也无法用于排序 118 | - 哈希索引不支持部分索引列匹配查找,因为哈希索引始终使用索引列的全部内容来计算哈希值 119 | - 只支持等值比较查询,包括 =、 in()、<=>,不支持范围查询 120 | - 数据访问速度快,当哈希冲突时,必须遍历链表中的所有行指针,直到查询到符合条件的行 121 | - 哈希冲突多的话,一些索引维护操作的代代价很高 122 | 123 | ### 事务隔离级别,设置事务方法 124 | 125 | 1. read uncommitted(未提交读) : 可以看到未提交的数据,脏读 126 | 127 | 2. read committed (提交读):只能读取已提交的数据,但多次读取的数据结果可能不一致,导致幻读 128 | 3. repeatable read(可重复读):默认级别,可以重复读,解决了脏读问题,但会有幻读 129 | 4. serializable(可串行化):最高隔离级别,强制事务串行执行,避免幻读问题 130 | 131 | 查询当前会话级别:select @@tx_isolation; 132 | 133 | 查看系统当前隔离级别:select @@global.tx_isolation; 134 | 135 | 设置当前会话隔离级别:set session transaction isolatin level repeatable read; 136 | 137 | 设置系统当前隔离级别:set global transaction isolation level repeatable read; 138 | 139 | ### 什么是MVCC, MySQL的MVCC原理 140 | 141 | MVCC即多版本并发控制,它能在很多情况下避免加锁操作,降低开销,不同的存储引擎实现方式不同,有乐观并发控制和悲观并发控制 142 | 143 | MySQL的InnoDB引擎,通过在每行记录后面保存两个隐藏的列来实现,一个列保存了行的创建时间,一个保存了行的过期时间(或删除时间)。实际存储的是系统版本号,每开始一个新的事务,系统版本号都会自动递增,事务开始时刻的系统版本号会作为事务的版本号,用来和查询到的每行记录的版本号进行比较。该MVCC只使用在repeatable read 和 read committed下 144 | 145 | 保存这两个额外的系统版本号,使大多数读操作都不用加锁,并且也能保证只会读到符合标准的行。缺点是需要额外的存储空间和维护工作。 146 | 147 | ### Mysql死锁 148 | 149 | 死锁是两个或者多个事务在同一资源上互相占用,并请求锁定对方资源,从而导致互相等待的现象。 150 | 151 | 死锁示例: 152 | 153 | ```sql 154 | #事务1 155 | start transaction; 156 | update stockprice set close = 45 where stock_id = 4 and date = '2019-1-1'; 157 | update stockprice set close = 20 where stock_id = 3 and date = '2019-1-3' 158 | 159 | #事务2 160 | start transaction; 161 | update stockprice set high = 36 where sockt_id = 3 and date = '2019-1-3'; 162 | update stockprice set hight = 60 where stock_id = 4 and date = '2019-1-1'; 163 | ``` 164 | 165 | 两个事务分别执行两个更新语句,都执行第一个语句,锁定了该行数据,但该行数据将做为对方事务执行下条语句的条件,所以当事务继续执行第二条语句的时候,因为需要的条件所在行已被另外一个事务锁定,这是死锁现象 166 | 167 | 避免死锁的方法: 168 | 169 | - 约定以相同的顺序访问表 170 | - 大事务分小事务 171 | - 一个事务中,一次锁定资源 172 | - 锁升级,采用表锁 173 | 174 | ### Msyql 执行SQL 过程 175 | 176 | ![img](https://mmbiz.qpic.cn/mmbiz_png/UtWdDgynLdbAUKxPhOt5w3a5p8wcZ9a3TBdpJ75T5aUIjZVUyV1WTSJKBBaibVMicVKkjBOX0uLuqXgYTTkYZVicw/640?tp=webp&wxfrom=5&wx_lazy=1&wx_co=1) 177 | 178 | 1. 客户端发送一条查询给服务器 179 | 2. 服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果。否则进入下一阶段 180 | 3. 服务器端进行SQL解析,预处理,再由优化器生成对应的执行计划 181 | 4. MySQL根据优化器生成的执行计划,调用存储引擎的API来执行查询 182 | 5. 将结果返回给客户端 183 | 184 | ### 如何优化sql翻页 185 | 186 | 1. 只让用户一页页翻,不能跳页 187 | 2. 确定每页的边界值,通过where条件查询来优化 188 | 3. 使用延迟关联,通过使用覆盖索引查询返回需要的主键,再根据这些主键关联原有表获得需要的行 189 | 190 | ```sql 191 | select name,sex,rating from mysql_test a inner join ( 192 | select id from mysql_test where sex='F' order by rating limit 20000,100 193 | ) as x USING(id) 194 | ``` 195 | 196 | ### 如何优化SQL语句 197 | 198 | 1. 先看表的数据类型是否设计的合理,遵守选取数据类型越简单越小的原则 199 | 2. 表中的碎片是否整理,[MySQL表的碎片整理和空间回收](https://www.cnblogs.com/kerrycode/p/10943122.html) 200 | 3. 表的统计信息是否收集,只有统计信息准确,执行计划才可以帮助我们优化SQL 201 | 4. 查看执行计划,检查索引的使用情况,没有用到索引,创建索引 202 | 5. 创建索引需要判断这个字段是否适合创建索引,遵守[建立索引的原则](#建立索引的原则) 203 | 6. 创建索引后,通过explain分析,前后性能变化 204 | 205 | ### 如何分析explain执行计划 206 | 207 | 先查看type列,如果出现all关键词,就代表sql执行全表扫描 208 | 209 | 再看key列,如果null代表没有使用索引 210 | 211 | 再看rows列,如果越大,代表需要扫描的行数越多,相应耗时就长 212 | 213 | 最后看 extra列,是否有影响性能的 Using filesort 或者 Using temporary 214 | 215 | explain 各个字段含义:https://blog.csdn.net/weixin_34062469/article/details/94498678 216 | 217 | ### slect * from a left join b on 条件 和 select * from a left join b where 条件一样么,为什么 218 | 219 | 不一样,返回的结果不一样。 220 | 221 | select * from a left join b on 条件 会返回 a 中没有匹配的数据 222 | 223 | select * from a left join b where 条件 只返回where中匹配的数据 224 | 225 | https://www.cnblogs.com/caowenhao/p/8003846.html 226 | 227 | ### Mysql 主从同步延迟问题 228 | 229 | 主从同步延迟产生的问题:插入新数据后,立马查询会查不到数据 230 | 231 | 1. 主从同步开启**并行复制** 232 | 2. 调整代码,不要插入后,先查询,再更新,如果要更新,插入后直接更新 233 | 3. 拆库,降低库的并发量,在并发量小的时候(500/s),延迟可以忽略不计 234 | 4. 这个查询操作直连主库 235 | 236 | 237 | 238 | 239 | 240 | -------------------------------------------------------------------------------- /Bug分享/1.Lock Transactional.md: -------------------------------------------------------------------------------- 1 | # 不当使用Redis锁产生的问题 2 | 3 | # 前言 4 | 5 | 春节放假期间,一个项目上的积分接口被刷,而且不止一个人在刷,并且东西也被兑走,放假晚上被人叫起来排查问题,通过这个人的积分明细观察,基本一秒就能获取一次,远远超过了积分规则限定的次数,这肯定是用脚本了,虽然后期联系死活说自己是正常途径获取。由于是业主,我们还是决定自己来承担这个损失,被项目方从合同中扣除奖品费用1万余元。 6 | 7 | # 问题原因 8 | 9 | 先说下接口的逻辑层次结构: 10 | 11 | --controller 积分获取接口,用PointController表示 12 | 13 | --service 积分获取接口service,用PointService表示 14 | 15 | 我用伪代码来表示整个调用逻辑: 16 | 17 | *PointController* 18 | 19 | ```java 20 | @RestController 21 | public class PointController { 22 | 23 | @Resource 24 | private PointService pointService; 25 | 26 | @PostMapping(/addPoint) 27 | public Response addPoint() { 28 | //分布式锁,使用redis的NX命令 29 | RedisDistributedLock lock = new RedisDistributedLock(); 30 | //创建一个3s过期,100ms休眠的锁 31 | if(lock.lock("POINT_KEY", 3000L, 100L)) { 32 | try { 33 | //调用 34 | pointService.addPoint(); 35 | } catch (Exception ex) { 36 | e.printStackTrace; 37 | } finally { 38 | //解锁 39 | lock.unlock("POINT_KEY"); 40 | } 41 | } 42 | return Response.ok(getLastPoint()); 43 | } 44 | } 45 | ``` 46 | 47 | 1. 创建一个分布式锁对象,该分布式锁使用redis的`NX`命令实现 48 | 2. 随后创建一个3s过期的分布式锁,以便锁住该新增积分的请求 49 | 3. 最后在新增积分执行完后,在finally中释放锁 50 | 4. 最后返回该用户的最终积分 51 | 52 | *PointService* 53 | 54 | ```java 55 | public class PointService { 56 | 57 | @Transactional(rollbackFor = Exception.class) 58 | public void addPoint() { 59 | //查询积分规则 60 | PointRule pointRule = getPointRule(); 61 | //查询用户该积分项的积分获取记录总数 62 | Integer total = getPointRecords(); 63 | //判断该用户的积分记录总数是否大于 积分规则限定的次数 64 | //大于则不处理,返回 65 | if(total - pointRule.getRuleTimes >= 0) { 66 | return; 67 | } 68 | 69 | //生成积分记录 70 | int insert = insertPointRecords(); 71 | //更新用户总积分 72 | if(insert > 0) { 73 | updateUserPoint(); 74 | } 75 | } 76 | } 77 | ``` 78 | 79 | PointService 中的添加积分逻辑: 80 | 81 | 1. 首先查询该项目积分规则,查询用户该积分项的积分获取记录总数 82 | 2. 判断该用户的积分记录总数是否大于 积分规则限定的次数,大于则不处理,返回 83 | 3. 生成积分记录 84 | 4. 更新用户总积分 85 | 86 | 87 | 88 | 该添加积分的逻辑整体上看好像没什么问题,也确实在一切正常的情况下运行是不会有问题的。 89 | 90 | 如果PointService 中的添加积分逻辑在分布式锁有效期3s内执行完,是不会有问题的。 91 | 92 | 但如果PointService中的添加积分逻辑超过3s...那是不是后续请求又可以获取锁了,这也正是这次事故的原因。 93 | 94 | 95 | 96 | `因为PointService中的添加积分逻辑超过了3s,并且上一个请求的事务还未提交,后续请求已经获取锁进入PointService,在查询积分记录后,判断还是满足规则,继续执行后续的逻辑,造成用户能够获取多次积分。` 97 | 98 | 99 | 100 | # 问题处理 101 | 102 | 原因总结一下: 103 | 104 | 1. 添加积分逻辑处理时间过长 105 | 2. 分布式锁超时 106 | 107 | 108 | 109 | 第一个问题:逻辑改动过大,需要时间调整,没有采用 110 | 111 | 第二个问题:换成Redisson,因为redisson在即使超时的情况下也会续锁,避免锁超时 112 | 113 | 114 | 115 | # 你以为问题真的解决了吗 116 | 117 | 如果把上面的代码换成Redisson后,代码一般是这样的 118 | 119 | *PointController* 120 | 121 | ```java 122 | @RestController 123 | public class PointController { 124 | 125 | @Resource 126 | private PointService pointService; 127 | 128 | @PostMapping(/addPoint) 129 | public Response addPoint() { 130 | RLock redissonClientLock = redissonClient.getLock("addPoint"); 131 | try { 132 | redissonClientLock.lock(); 133 | //调用 134 | pointService.addPoint(); 135 | } catch (Exception ex) { 136 | e.printStackTrace; 137 | } finally { 138 | //解锁 139 | redissonClientLock.unlock(); 140 | } 141 | return Response.ok(getLastPoint()); 142 | } 143 | } 144 | ``` 145 | 146 | 你觉得还会有问题吗?事实证明,这段代码确实没问题了。 147 | 148 | 但是如果你把锁加到pointService 的addPoint方法里面,你觉得会不会有问题? 149 | 150 | > 如果这样做,执行到finally中,释放了锁,但实际该方法还没彻底执行完,还没提交事务,此时下一个阻塞的请求获取了锁,还是会造成锁失效的现象,所以应该把锁加在有事务的方法外面。 151 | 152 | # 总结 153 | 154 | 一方面因为忙于做项目,忽略了代码Review,另一方面测试的时候没有对接口进行并发测试,或者根本没有测出来,第三没有监控工具监控长事务,以及频繁请求。 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /Other Interview.md: -------------------------------------------------------------------------------- 1 | # 大厂面试题 2 | 3 | > 这里会持续收集一些大厂的面试题,欢迎大家补偿,回答。😂 4 | 5 | #### 阿里巴巴 6 | 7 | 1. 分布式锁在项目里哪些地方用到,怎么实现的 8 | 2. JVM怎么监控 9 | 3. OOM没有heap文件怎么办 10 | 4. 进行没有挂,但没响应了怎么查原因 11 | 5. 堆栈溢出一般在什么情况下发生,怎么应对 12 | 6. Netty零拷贝怎么用的?原理是什么?哪些数据结构会用零拷贝? 13 | 7. 微服务每个模块怎么划分,领域边界怎么确定,如何建模? 14 | 8. Dubbo踩过哪些坑,分别是怎么解决的? 15 | 9. 事务有哪些特性? 16 | 10. 怎么理解原子性? 17 | 11. 乐观锁和悲观锁的区别?这两种锁在Java和MySQL分别是怎么实现的? 18 | 12. HashMap为什么不是线程安全的? 19 | 13. 怎么让HashMap变得线程安全? 20 | 14. jdk1.8对ConcurrentHashMap做了哪些优化? 21 | 15. redis主从机制了解么?怎么实现的? 22 | 16. 水平拆分后查询过程描述下 23 | 17. 如果落到某个分片的数据很大怎么办? 24 | 18. 哈希取模会有什么问题么? 25 | 19. 拆分后主键怎么保证惟一? 26 | 27 | 28 | 29 | #### 滴滴 30 | 31 | 1. Redis 数据类型与结构,平时用哪些? 32 | 2. Redis为什么高效? 33 | 3. Redis 只用一个线程吗?在32核的机器上会不会浪费? 34 | 4. Redis的List、Set为什么使用跳表而不用复杂度更低的其他结构 35 | 5. Redis Hash结构底层实现?假设一个超大的对象放不下怎么办? 36 | 6. Java HashMap 1.8的改进 37 | 7. LRU策略,底层实现 38 | 8. 消息中间件了解哪些? 39 | 9. RocketMQ分布式事务功能的客户端让你来封装怎么封装? 40 | 10. Spring Cloud链路追踪怎么做的?底层怎么实现的? 41 | 11. Dubbo链路追踪怎么做? 42 | 12. MINA和Netty对比,各有什么优劣 43 | 13. Netty怎么调优,怎么提升并发上限 44 | 14. 说说TCP滑动窗口干嘛用的? 45 | 15. 通讯序列化和反序列化了解哪些框架?优缺点是什么? 46 | 16. Dubbo SPI怎么实现的? 47 | 17. 16G内存的机器,长连接应用如果用CMS参数怎么配置 48 | 18. G1平时怎么用,说说原理? 49 | 19. Mysql Innodb索引说下 50 | 20. 1亿条数据查第900页怎么查,如何优化? 51 | 21. 分库分表一般按什么原则分 52 | 53 | 54 | 55 | #### 美团 56 | 57 | 1. Dubbo架构图 58 | 2. Dubbo调用原理 59 | 3. B+Tree画图 60 | 4. 手写二叉树前中后序遍历 61 | 5. Redis数据类型 62 | 6. Redis集群搭建过程 63 | 7. Redis哨兵如何配置,运行原理 64 | 8. Redis主备如何配置 65 | 9. JVM运行内存模型,栈帧的局部变量表有哪些内容 66 | 10. ConcurrentHashMap 1.7 和 1.8 区别 67 | 11. Mysql事务特性,隔离级别 68 | 12. 转账场景,ACID体现在哪里 69 | 13. Spring MVC原理 70 | 14. Spring Bean生命周期 71 | 15. 初始化Bean 和 销毁Bean调用方法怎么配置?XML配置Bean有哪些标签? 72 | 16. 自己设计一个MVC如何设计 73 | 17. Mybatis \$ 和 \#的区别 74 | 18. 如何防止SQL注入,Spring是如何防止SQL注入的? 75 | 19. 如何做SQL注入 76 | 20. Zuul如何配置路由 77 | 21. 有没有手写过JDBC 78 | 22. 数据库分库分表 79 | 23. 1亿条数据的数据表,怎么添加字段 80 | 24. 如何优化SQL 81 | 82 | 83 | 84 | #### 京东 85 | 86 | - 线程池的原理,为什么要创建线程池? 87 | - 线程的生命周期,什么时候会出现僵死进程; 88 | - 什么实现线程安全,如何实现线程安全; 89 | - 创建线程池有哪几个核心参数?如何合理配置线程池的大小? 90 | - synchronized、volatile区别、synchronized锁粒度、模拟死锁场景、原子性与可见性; 91 | - JVM内存模型,GC机制和原理;GC分哪两种;什么时候会触发Full GC? 92 | - JVM里的有几种classloader,为什么会有多种? 93 | - 什么是双亲委派机制?介绍一些运作过程,双亲委派模型的好处;(这个我真的不会...) 94 | - 什么情况下我们需要破坏双亲委派模型; 95 | - 常见的JVM调优方法有哪些?可以具体到调整哪个参数,调成什么值? 96 | - JVM虚拟机内存划分、类加载器、垃圾收集算法、垃圾收集器、class文件结构是如何解析的; 97 | 98 | - 红黑树的实现原理和应用场景; 99 | - NIO是什么?适用于何种场景? 100 | - Java9比Java8改进了什么; 101 | - HashMap内部的数据结构是什么?底层是怎么实现的? 102 | - 说说反射的用途及实现,反射是不是很慢,我们在项目中是否要避免使用反射; 103 | - 说说自定义注解的场景及实现; 104 | - List和Map区别,Arraylist与LinkedList区别,ArrayList与Vector 区别; 105 | 106 | - Spring AOP的实现原理和场景;(应用场景很重要) 107 | - Spring bean的作用域和生命周期; 108 | - Spring Boot比Spring做了哪些改进?Spring 5比Spring4做了哪些改进;(惭愧呀,我们还在用Spring4,高版本的没关心过) 109 | - Spring IOC是什么?优点是什么? 110 | - SpringMVC、动态代理、反射、AOP原理、事务隔离级别; 111 | 112 | - Dubbo完整的一次调用链路介绍; 113 | - Dubbo支持几种负载均衡策略? 114 | - Dubbo Provider服务提供者要控制执行并发请求上限,具体怎么做? 115 | - Dubbo启动的时候支持几种配置方式? 116 | - 了解几种消息中间件产品?各产品的优缺点介绍; 117 | - 消息中间件如何保证消息的一致性和如何进行消息的重试机制? 118 | - Spring Cloud熔断机制介绍; 119 | - Spring Cloud对比下Dubbo,什么场景下该使用Spring Cloud? 120 | 121 | - 锁机制介绍:行锁、表锁、排他锁、共享锁; 122 | - 乐观锁的业务场景及实现方式; 123 | - 事务介绍,分布式事物的理解,常见的解决方案有哪些,什么事两阶段提交、三阶段提交; 124 | - MySQL记录binlog的方式主要包括三种模式?每种模式的优缺点是什么? 125 | - MySQL锁,悲观锁、乐观锁、排它锁、共享锁、表级锁、行级锁; 126 | - 分布式事务的原理2阶段提交,同步异步阻塞非阻塞; 127 | - 数据库事务隔离级别,MySQL默认的隔离级别、Spring如何实现事务、 128 | - JDBC如何实现事务、嵌套事务实现、分布式事务实现; 129 | - SQL的整个解析、执行过程原理、SQL行转列; 130 | 131 | - Redis为什么这么快?redis采用多线程会有哪些问题? 132 | - Redis支持哪几种数据结构; 133 | - Redis跳跃表的问题; 134 | - Redis单进程单线程的Redis如何能够高并发? 135 | - Redis如何使用Redis实现分布式锁? 136 | - Redis分布式锁操作的原子性,Redis内部是如何实现的? 137 | 138 | 139 | 140 | #### 某公司 141 | 142 | 1面 143 | 1、Object的方法 144 | 2、jdk1.8比1.7做了哪些改变 145 | 3、volatile原理 146 | 4、工作中用到的redis数据类型及场景 147 | 5、工作中用到的线程池及原理、每个参数是怎么设置的 148 | 6、工作中用到的Redis锁及原理 149 | 7、slect * from a left join b on 条件 和 select * from a left join b where 条件一样么,为什么 150 | 8、热点商户的缓存穿透怎么解决,排队后面的请求等待时间过程怎么办 151 | 9、hashmap的put过程和扩容过程 152 | 10、用list users = new ArrayList<>()来说明类加载过程和整个过程中内存各区域的变化 153 | 11、线上用的垃圾回收器是啥,分几个阶段,哪个阶段stop the world,eden里还有什么 154 | 12、设计一个高可用、幂等、安全、高性能的接口需要分别考虑什么 155 | 13、Spring IOC bean初始化过程 156 | 14、mybatis的执行过程 157 | 15、事务隔离级别和mvcc 158 | 16、redis集群现在有10台机器,新加入5台,数据是怎么同步的 159 | 17、redis的持久化方式、redis的过期策略 160 | 18、redis和memcache的区别 161 | 19、mysql有哪些索引类型 162 | 20、lock和synchronized区别,生产还用过juc下的哪些类,场景 163 | 21、AtomicInteger的原理 164 | 2面 165 | 1、redis lru是怎么实现的,如何手写一个lru 166 | 2、B树和B+树的区别,mysql为啥使用B+树 167 | 3、红黑树的特性及变换 168 | 4、生产上的分布式事务怎么做的 169 | 5、分布式限流 170 | 6、mq积压如何保证消费到最新的消息,mq如何保证消费顺序 171 | 7、lambda写一个排序 172 | 8、mysql能发生死锁么,为什么 173 | 9、生产上的服务降级做了么,怎么做的 174 | 10、缓存的双写一致性怎么保证,生产是怎么用的,有什么问题,怎么解决 175 | 11、生产的不停机分表怎么做的,怎么支持跨时间查询,有无其他更好的分表方式 176 | 12、说一下下单的整个流程 177 | 13、如何解决超卖 178 | 14、线上发生过jvm问题么,如何排查的,引起原因是什么 179 | 15、线程池的核心参数及原理 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 阅读介绍 2 | 3 | > 这里搜罗了网上的一些面试题,还有一些相关知识点 4 | > 5 | > 里面的一些问题如感觉有不对的地方,欢迎指正。 6 | > 7 | > 如果觉得有帮助,麻烦动动你的小手给颗小星星 8 | 9 | ### Java面试题整理 10 | 11 | | 基础 | 并发 | 锁 | JVM | 设计模式 | 数据结构 | 反射/IO | 面经 | Spring | Spring Boot | 12 | | ------------------------------------------------------------ | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | ------------------------------------------------------------ | :----------------------------------------------------------: | :----------------------------------------------------------: | 13 | | [🍼](https://github.com/jujunchen/Java-interview-question/blob/master/1.Java%20Based.md) | [🍭](https://github.com/jujunchen/Java-interview-question/blob/master/2.Java%20Concurrent.md) | [🍩](https://github.com/jujunchen/Java-interview-question/blob/master/3.Java%20Lock.md) | [🌮](https://github.com/jujunchen/Java-interview-question/blob/master/4.JVM.md) | [🍱](https://github.com/jujunchen/Java-interview-question/blob/master/6.Design%20Pattern.md) | [🧀](https://github.com/jujunchen/Java-interview-question/blob/master/7.Data%20Structure.md) | [🥐](https://github.com/jujunchen/Java-interview-question/blob/master/5.Java%20Reflect_IO.md) | [🍜](https://github.com/jujunchen/Java-interview-question/blob/master/Other%20Interview.md) | [🍬](https://github.com/jujunchen/Java-interview-question/blob/master/10.Spring.md) | [🍫](https://github.com/jujunchen/Java-interview-question/blob/master/11.Spring%20Boot.md) | 14 | 15 | | 数据库 | Redis | 消息队列 | 分布式 | Zookeeper | Dubbo | Spring Cloud | Mybatis | Maven | 16 | | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------------------------------: | 17 | | [🌽](https://github.com/jujunchen/Java-interview-question/blob/master/8.DataBase.md) | [🍔](https://github.com/jujunchen/Java-interview-question/blob/master/9.Redis.md) | [🍡](https://github.com/jujunchen/Java-interview-question/blob/master/14.Message%20Queue.md) | [🎂](https://github.com/jujunchen/Java-interview-question/blob/master/19.Distribute_MicroService.md) | [🍯](https://github.com/jujunchen/Java-interview-question/blob/master/16.Zookeeper.md) | [🥛](https://github.com/jujunchen/Java-interview-question/blob/master/12.Dubbo.md) | [☕️](https://github.com/jujunchen/Java-interview-question/blob/master/13.Spring%20Cloud.md) | [🍿](https://github.com/jujunchen/Java-interview-question/blob/master/15.Mybatis.md) | [🍹](https://github.com/jujunchen/Java-interview-question/blob/master/17.Maven.md) | 18 | 19 | ### 一些官方文档地址 20 | 21 | Java:https://docs.oracle.com/en/java/index.html 22 | 23 | Spring:https://spring.io/guides 24 | 25 | Redis :https://redis.io/documentation 26 | 27 | Dubbo:http://dubbo.apache.org/zh-cn/docs/user/quick-start.html 28 | 29 | ShardingJDBC:https://shardingsphere.apache.org/document/current/cn/features/ 30 | 31 | ### 在线阅读 32 | 33 | 使用语雀提供了较好的阅读体验 34 | 35 | https://www.yuque.com/itsaysay/mzsmvg 36 | 37 | ### 电子书 38 | 39 | `愿在编程的道路上,越走越远,一起共勉` 40 | 41 | https://github.com/jujunchen/ebook 42 | 43 | ### 学习资料 44 | 45 | [学习资料地址](https://github.com/jujunchen/Java-interview-question/tree/master/学习资料) 46 | 47 | #### 交流平台 48 | 49 | 阿提说说:[阿提说说-CSDN博客](https://itsaysay.blog.csdn.net/) 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /media/006y8mN6ly1g8xdtvdrcyj31jy06adjs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/006y8mN6ly1g8xdtvdrcyj31jy06adjs.jpg -------------------------------------------------------------------------------- /media/006y8mN6ly1g8xdwn9fq8j31ki0r8nfb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/006y8mN6ly1g8xdwn9fq8j31ki0r8nfb.jpg -------------------------------------------------------------------------------- /media/006y8mN6ly1g8xe5miksnj30w201w74f.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/006y8mN6ly1g8xe5miksnj30w201w74f.jpg -------------------------------------------------------------------------------- /media/006y8mN6ly1g8xetz5v5jj31so04sgmx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/006y8mN6ly1g8xetz5v5jj31so04sgmx.jpg -------------------------------------------------------------------------------- /media/006y8mN6ly1g8xf7p2kg1j30h004omxn.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/006y8mN6ly1g8xf7p2kg1j30h004omxn.jpg -------------------------------------------------------------------------------- /media/006y8mN6ly1g8xfievgsdj31kk03awf9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/006y8mN6ly1g8xfievgsdj31kk03awf9.jpg -------------------------------------------------------------------------------- /media/006y8mN6ly1g8xfrevz58j30v602yaah.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/006y8mN6ly1g8xfrevz58j30v602yaah.jpg -------------------------------------------------------------------------------- /media/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/01.png -------------------------------------------------------------------------------- /media/252461fbb6d64d3dbc1914b7eadbfb86.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/252461fbb6d64d3dbc1914b7eadbfb86.jpeg -------------------------------------------------------------------------------- /media/36465fd7d91b3a4aeb3b28c3777649e6.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/36465fd7d91b3a4aeb3b28c3777649e6.jpeg -------------------------------------------------------------------------------- /media/4935fcc0a209fd1d4b70cade94986f59.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/4935fcc0a209fd1d4b70cade94986f59.jpeg -------------------------------------------------------------------------------- /media/6650aa32de0def76db0e4c5228619aef.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/6650aa32de0def76db0e4c5228619aef.jpeg -------------------------------------------------------------------------------- /media/IMG_082BD9A3B24F-1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/IMG_082BD9A3B24F-1.jpeg -------------------------------------------------------------------------------- /media/distributed-system-request-sequence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/distributed-system-request-sequence.png -------------------------------------------------------------------------------- /media/dubbo-keep-connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/dubbo-keep-connection.png -------------------------------------------------------------------------------- /media/dubbo-not-keep-connection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/dubbo-not-keep-connection.png -------------------------------------------------------------------------------- /media/dubbo-service-invoke-road.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/dubbo-service-invoke-road.png -------------------------------------------------------------------------------- /media/image-20191114193034340-3731511.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114193034340-3731511.png -------------------------------------------------------------------------------- /media/image-20191114193034340.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114193034340.png -------------------------------------------------------------------------------- /media/image-20191114194022209.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194022209.png -------------------------------------------------------------------------------- /media/image-20191114194055084.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194055084.png -------------------------------------------------------------------------------- /media/image-20191114194125306.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194125306.png -------------------------------------------------------------------------------- /media/image-20191114194139915.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194139915.png -------------------------------------------------------------------------------- /media/image-20191114194157527.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194157527.png -------------------------------------------------------------------------------- /media/image-20191114194224919.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194224919.png -------------------------------------------------------------------------------- /media/image-20191114194236837.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194236837.png -------------------------------------------------------------------------------- /media/image-20191114194247158.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194247158.png -------------------------------------------------------------------------------- /media/image-20191114194335314.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194335314.png -------------------------------------------------------------------------------- /media/image-20191114194356825.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194356825.png -------------------------------------------------------------------------------- /media/image-20191114194415039.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194415039.png -------------------------------------------------------------------------------- /media/image-20191114194430674.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194430674.png -------------------------------------------------------------------------------- /media/image-20191114194439833.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194439833.png -------------------------------------------------------------------------------- /media/image-20191114194449725.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194449725.png -------------------------------------------------------------------------------- /media/image-20191114194503521.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194503521.png -------------------------------------------------------------------------------- /media/image-20191114194740033.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194740033.png -------------------------------------------------------------------------------- /media/image-20191114194815842.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194815842.png -------------------------------------------------------------------------------- /media/image-20191114194918523.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194918523.png -------------------------------------------------------------------------------- /media/image-20191114194952076.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114194952076.png -------------------------------------------------------------------------------- /media/image-20191114195007116.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114195007116.png -------------------------------------------------------------------------------- /media/image-20191114195010955.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114195010955.png -------------------------------------------------------------------------------- /media/image-20191114195023197.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114195023197.png -------------------------------------------------------------------------------- /media/image-20191114195045400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114195045400.png -------------------------------------------------------------------------------- /media/image-20191114195113356.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114195113356.png -------------------------------------------------------------------------------- /media/image-20191114195209444.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114195209444.png -------------------------------------------------------------------------------- /media/image-20191114195228161.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114195228161.png -------------------------------------------------------------------------------- /media/image-20191114195305300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114195305300.png -------------------------------------------------------------------------------- /media/image-20191114195334883.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114195334883.png -------------------------------------------------------------------------------- /media/image-20191114195346681.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114195346681.png -------------------------------------------------------------------------------- /media/image-20191114195421280.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114195421280.png -------------------------------------------------------------------------------- /media/image-20191114195509483.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114195509483.png -------------------------------------------------------------------------------- /media/image-20191114200036013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114200036013.png -------------------------------------------------------------------------------- /media/image-20191114203012441.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114203012441.png -------------------------------------------------------------------------------- /media/image-20191114203913199.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114203913199.png -------------------------------------------------------------------------------- /media/image-20191114204200585.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/image-20191114204200585.png -------------------------------------------------------------------------------- /media/serialize-deserialize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/media/serialize-deserialize.png -------------------------------------------------------------------------------- /大厂面经/Interview Exp1.md: -------------------------------------------------------------------------------- 1 | # “四面四杀”面经 2 | ## 前言(经历) 3 | 4 | 毕业五年了,已经将近两年没有面试了,这次想在自己职业生涯5~8年的阶段在一个大厂的核心部门的某个细分领域沉下心来,总结出自己在复杂领域模型设计的方法论,为未来转型业务架构师打下基础,所以简历投的也不多,只有某里、某团、某滴(简历没过),下步准备再刷刷算法试试某条和拼夕夕,除了某团某个大数据部门方向确实不是很匹配(三面仅仅聊了半个小时,部门的主方向主要是一些某团大数据团队在做的一些事情,而我确实对大数据中间件不是很感兴趣,但在此也要谢谢大数据部门的三轮面试官大佬,他们确实问的问题更偏底层,深度也是这次经历面试最深的,面试收获也是不少),其他技术面试都已经通过,也算是比较顺利的面试经历。 5 | 6 | 7 | 8 | ## 自我介绍 9 | 10 | 这次面试总结下基本都需要三~四轮技术面试,每轮都有点算法问题,也顺道介绍下自己,15年软件工程毕业,工作四年半了,一直呆在二线城市,没有大厂经验,闲来无事喜欢看些大厂或者技术大佬的原创博客,有点闲暇时间对自己偏爱的领域(中间件、稳定性保障体系、云原生等)会啃下几本大簿头的书,下面总结下面试遇到的一些问题,希望大家们有所收获。 11 | 12 | 13 | 14 | ## 面试内容 15 | 16 | 17 | 18 | ### 某团核心业务部门 19 | 20 | 21 | 22 | 一面 23 | 24 | 1、自我介绍 25 | 26 | 2、稳定性这边的概念,做了哪些工作 27 | 28 | 3、如何做的全链路跟踪的 29 | 30 | 4、稳定性能否保障100% 出现故障怎么降低损失 做了哪些努力 31 | 32 | 5、线上故障排查 每10分钟crash一次 如何排查 可能出现哪些原因 33 | 34 | 6、实际的gc调优要求,什么指标需要gc调优 35 | 36 | 7、cpu飙升怎么判断 37 | 38 | 8、网关qps 如何支持 39 | 40 | 9、concurrenthashmap 如何并发 size如何实现的 size++是否线程安全 41 | 42 | 10、redis 大key如何调优,如何监控,如何解决 43 | 44 | 11、哪些(一些驱动包和通用组件)是你自己主动提出来做的,咋做的,如何收获同事们的反馈 45 | 46 | 47 | 48 | 二面 49 | 50 | 1、权限模型,如何设计的,有什么亮点,通过位运算对比角色具有的功能点和具体角色,位运算这里怎么做的,做过bitmap吗,异或、与或的区别 51 | 52 | 2、redis 有些数据类型,sorted set 平时咋用,怎么做延时队列 53 | 54 | 3、学生与学科,查询某个学生的所学学科情况,某学科对应的学生,怎么设计这个数据结构在redis里 55 | 56 | 4、redis如何实现一个二叉树 57 | 58 | 5、如何解决大key问题,key多,value大如何处理 59 | 60 | 6、mysql的事务隔离级别,rr如何实现,给你一个sql描述下加锁过程(数据库级别,索引类型),mysql有哪些锁,啥叫gap锁,生产上遇到过死锁问题吗,举一个gap锁死锁的例子,如何避免死锁 61 | 62 | 7、mysql为啥要用b+树,有啥优势,hash索引的优点、缺点,生产上用过hash索引吗 63 | 64 | 8、手写一个多线程死锁的代码(java) 65 | 66 | 9、中间件做过哪些努力,可靠性消息服务是如何做的,原理画图,能否保证mq的100%高可用,如果想保证mq的100%高可用还可以在目前的基础上做哪些努力,有哪些想法,使用redis、mysql兜底也不可靠的话怎么解决(异地容灾,同城双机房?) 67 | 68 | 10、有啥问题要问我(聊了聊组内情况,负责业务,主要的技术挑战等等) 69 | 70 | 71 | 72 | 三面 73 | 74 | 1、中台负责哪些模块,saas 和 中台有什么区别,中台负责的责任,saas做的比较好的国外公司、国内公司,对标的企业,元数据是干啥的 75 | 76 | 2、中台如何做业务的抽象,如何划分领域模型 77 | 78 | 3、商家的灰度分为几个维度,技术上怎么实现,具体细节 79 | 80 | 4、如何解决不同商家的某个接口具体实现,更改某段逻辑会对其他商家造成影响,什么是贫血模型,什么是贫血模型的失忆症 81 | 82 | 5、kafka原理讲下,源码看过吗,使用java写的吗,从哪个版本从scala改成java,如何达到的高吞吐、低延迟,kafka的消费者再平衡过程能描述下吗,会出现哪些问题,kafka生产者有哪些参数可以配置,生产kafka做过哪些调优,线上出现哪些生产问题,如何排查的,如何解决的,如何推动的 83 | 84 | 6、spark 做rdd聚合比mapreduce的优势在哪里,为啥快,如果down机spark内数据还在吗,如何设计一个学生表hbase的列族 85 | 86 | 7、微服务链路跟踪的技术框架如何选型,为啥使用jaeger 不用 cat或者skywalking ,trace_id如何传递的,原生的threadlocal,InheritableThreadLocal有啥问题,为啥threadlocal key要用弱引用,强引用的话能否解决内存泄漏的问题,为啥不用强引用,为啥用阿里的TransmittableThreadLocal,内部是如何实现的 87 | 88 | 8、看过哪些中间件的源码、书籍,哪些书写的不错 89 | 90 | 9、为啥要离开目前的公司,职业规划(三年一个坎,五年一个坎,八年一个坎,准备在五到八年的阶段到大厂的核心部门熟悉一个细分领域,沉淀出自己领域建模的方法论) 91 | 92 | 10、如果换一个领域的话,怎么快速的熟悉这个领域的知识(ddd的领域建模过程) 93 | 94 | 11、有啥要问的 95 | 96 | 97 | 98 | ### 某团大数据团队 99 | 100 | 101 | 102 | 一面 103 | 104 | 1、手撸一个lru,各种细节 105 | 106 | 2、spring 核心功能 ioc 和 aop 实现原理 107 | 108 | ioc 解决了什么问题 实现方式是怎么样的?ioc 实现流程?如何解决循环依赖的问题 ? 109 | 110 | aop解决了什么问题 ?分哪几种?如何区分?性能有啥差距 ? 111 | 112 | 3、jvm内存划分有啥好处?元空间堆外内存好处 ? 113 | 114 |   (1)之前不管是不是需要,JVM都会吃掉那块空间……如果设置得太小,JVM会死掉;如果设置得太大,这块内存就被JVM浪费了。理论上说,现在你完全可以不关注这个,因为JVM会在运行时自动调校为“合适的大小”; 115 | 116 |   (2)提高Full GC的性能,在Full GC期间,Metadata到Metadata pointers之间不需要扫描了,别小看这几纳秒时间; 117 | 118 |   (3)隐患就是如果程序存在内存泄露,像OOMTest那样,不停的扩展metaspace的空间,会导致机器的内存不足,所以还是要有必要的调试和监控 119 | 120 | 4、简单介绍垃圾回收 时机 分代的好处 121 | 122 | 5、kafka 的架构 通过什么手段达到消息的不丢不重 123 | 124 | 6、broker 宕机恢复 扩容瓶颈 步骤 线上出现过什么故障 如何排查 调优 125 | 126 | 127 | 128 | 二面 129 | 130 | 1、稳定性保障如何做,你在其中的职责,汇报关系 131 | 132 | 2、做的项目难度复杂度比较高的项目,项目主要的目标,技术架构,为何要服务拆分,依据什么原则,自己如何评价所作事情的效果,同事如何评价,有何标准 133 | 134 | 3、mysql删除一条数据的步骤,mysql的隔离级别,rr是如何实现的、原理,rr的加锁读和不加锁读描述下步骤,redo、undo会出现一致性问题吗,怎么解决的 135 | 136 | 4、生产中遇到过有关数据库事务的故障吗,死锁,描述下故障的原因,如何排查的,如何解决的,如何推动的 137 | 138 | 5、redis底层数据结构有哪些,为减少内存做了哪些努力,redis hash、跳表有哪些与jdk不一样的地方 139 | 140 | 6、redis集群架构,哨兵的原理,如何做到slave业务端的无感知扩容,主观down、客观down的过程 141 | 142 | 7、每个 Sentinel 都需要定期执行的任务有哪些,主观宕机的条件,quorum和真正达到fail over的条件是什么关系,Slave选举与优先级 143 | 144 | 8、redis主从复制的大致过程,redis Sentinel 能保证不丢数据吗,为什么 145 | 146 | 9、sql在线笔试,有一个表A 是昨天的数据快照表,表B是今天的数据增量表,通过select语句生成今天的数据快照表 147 | 148 | 10、手撸两个字符串的最大公共子序列,如何计算时间复杂度、空间复杂度 149 | 150 | 11、对带团队有没有想法、心德,如果让你带四人小团队,人员构成怎么选择 151 | 152 | 12、最近学习的技术,看的哪写书,ddd解决了什么问题,描述下ddd,聚合根的目的、实体与值对象的关系,怎么划分领域的上下限,为什么要学rancher、k8s 153 | 154 | 155 | 156 | 三面 157 | 158 | 聊了聊部门主营业务和方向,感觉未来不想放弃在java稳定性保障、中间件、业务领域的技术沉淀,从事一个陌生的大数据组件私有化(某团内部版本与社区版偏离有点远)升级、改造,所以也还挺尴尬的,一二面没有聊清楚具体的方向,感觉也挺耽误大佬时间的 159 | 160 | 161 | 162 | ### 某团核心部门二 163 | 164 | 165 | 166 | 一面 167 | 168 | 1、java 如何写一个十进制转二进制的算法 169 | 170 | 2、集合 171 | 172 | 继承结构 有哪些实现类 接口 每个实现类的具体实现 原理 173 | 174 | arraylist linkedlist hashmap hashset 175 | 176 | 3、数据结构 对比 优点 177 | 178 | 4、hashmap的底层实现 179 | 180 | 5、为啥数组+链表 单纯数组可以吗 哈希表的几种实现方式说下,优缺点 181 | 182 | 6、链地址优点 183 | 184 | ​ (1)resize方便,直接位运算即可 185 | 186 | ​ (2)空间换时间 187 | 188 | ​ (3)删除方便,链表删除元素 189 | 190 | 7、链表解决了啥问题 191 | 192 | 8、put操作的流程 ?get、rehash的过程? 193 | 194 | ​ hash值怎么取的=>object对象的方法=>jvm对象头 195 | 196 | 大于8变成红黑树,红黑树、平衡树、二叉树的对比,为啥用红黑树不用 平衡树? 197 | 198 | 9、并发包 aqs 199 | 200 | ​ aqs解决了啥问题 201 | 202 | ​ 基于aqs的实现类 203 | 204 | ​ 可重入锁能重入多少次 205 | 206 | ​ 手画下可重入做的自旋入队过程 207 | 208 | 10、countdownlach的源码 如何实现 209 | 210 | ​ 具体实际工作啥时候能用 211 | 212 | 11、重入锁的原理,可以重入多少次 源码如何实现 213 | 214 | 12、数据库的表结构,权限系统设计 215 | 216 | ​ sql优化手段 217 | 218 | ​ 什么列上加索引 219 | 220 | 更新操作注意哪些事项=>更新字段要加索引,避免死锁=>怎么避免死锁=>生产怎么排查死锁=>有哪些死锁案例 221 | 222 | 13、索引与锁的关系,一条sql如何判断加的什么锁 223 | 224 | 14、redis 用来干啥 225 | 226 | 15、缓存如何使用 多级缓存,数据库与缓存的 227 | 228 | 16、二级缓存更新步骤 通过什么组件实现本地缓存同步 229 | 230 | 17、缓存有效时间怎么考虑 为啥这么设计 231 | 232 | 18、缓存对象大概多大 大key如何报警 大key如何拆分 大key如何删除 233 | 234 | 19、啥是热key 如何报警 如何规避 235 | 236 | 20、稳定性方面的工作 237 | 238 | 21、mq在设计方面考虑 239 | 240 | 22、如何高可用 高可靠不丢消息 幂等 顺序等 241 | 242 | 243 | 244 | 二面 245 | 246 | 忘记了,上来就说看到我被xx部门录取了,我说是的(窃喜,不会细问我了吧,没想到又锤我了一个多小时,不过面试官人都很nice) 247 | 248 | 249 | 250 | 三面 251 | 252 | 忘记了,只记得面试官人很nice 253 | 254 | 255 | 256 | 四面 257 | 258 | 1、具体负责哪些工作,公司做那块业务的,对标的企业、产品,技术团队有多少人,中台还是中间件,业务中台还是中间件比较多 259 | 260 | 2、稳定性保障都是负责哪些工作,人员组织权限遵循什么规范,观察哪些指标,报表的数据权限怎么做(元数据) 261 | 262 | 3、5-15-30可灰度、可降级、如何实现的,做了些工作,和其他产品有什么对标,怎么优化,怎么实施 263 | 264 | 4、如何获取其他业务团队的反馈,需求 265 | 266 | 5、中台网关,不同的业务都走你们的网关,如何做的业务级别的资源隔离,网关下面的业务的服务,如何做的服务的聚合,怎么做的领域拆分,领域聚合,提供应用服务给业务方 267 | 268 | 6、换工作的原因 269 | 270 | 7、还在看哪些公司的机会 271 | 272 | 8、哪些问题要问我 273 | 274 | 275 | 276 | 277 | 278 | ### XX巴巴 279 | 280 | 281 | 282 | 一面 283 | 284 | 1、个人介绍 285 | 286 | 2、稳定保障的定义 287 | 288 | 3、订单量的监控 289 | 290 | 4、数据库调优做过哪些 291 | 292 | 5、redis调优做过哪些 293 | 294 | 6、热key报警怎么处理 295 | 296 | 7、多级缓存 本地缓存中key的数量很多 oom 如何考虑 缓存不一致的的问题 如何优化 297 | 298 | 8、热key监控如何做的,大促提前如何准备 299 | 300 | 9、代表性的事故,如何排查 301 | 302 | 10、redis锁的调用原理 watchdog机制 303 | 304 | 11、mq 的选型 305 | 306 | 12、kafka的整体架构 消费者如何记录提交offset 307 | 308 | 13、eureka的原理 309 | 310 | 14、springcloud dubbo选型 311 | 312 | 15、sentinel的原理 如何做的qps限流 313 | 314 | 16、innodb索引 数据结构 315 | 316 | 317 | 318 | 二面 319 | 320 | 1、可靠性消息服务中间件是干啥的?架构原理是? 321 | 322 | 2、如何收获同事们的评价? 323 | 324 | 3、rocketmq的架构?kafka的架构?有什么区别,如果有个broker挂掉了,线上如何操作,如果不操作会出现什么问题,操作的时候需要注意啥,为什么要都从leader节点复制数据,复制时有无限制? 325 | 326 | Kafka如何存储的,消费者是怎么消费的,消费者组,统一消费者记录offset,如果消费者组有新的消费者加入或者删除的过程 327 | 328 | 4、服务拆分的原则,划分领域的标准,如何从需求中提炼出实体、值对象、聚合根、领域上下限,什么是一个实体(有唯一标识),实体与值对象的区别(是否有生命周期,可修改) 329 | 330 | 5、项目中遇到哪些性能问题,热key、大key如何做预警,如何解决,如何拆分 331 | 332 | 6、二级缓存框架如何设计,如何做本地缓存预热,get、delete/update操作缓存的过程,qps多少,本地缓存如何做的淘汰策略,能保持数据一致性吗,如果不能保证的话有强一致性的需求有哪些方案 333 | 334 | 类微博的feed流 推拉结合的方案 335 | 336 | 7、稳定性保障的工作,挑战最大的问题(有关事务等待时间超过redis分布式锁的时间,导致的数据异常的问题),如何排查出来的这个问题,怎么解决的,怎么推动的,怎么验收 337 | 338 | 8、再举一个线上排查难的故障(举了一个ng转发X-forward-proto协议在spring boot 2.2+netty的一个bug,通过tcpdump出进流量和出流量的对比,一步步分析) 339 | 340 | 再举一个例子(说了下微服务链路跟踪中间件jager在spring boot 2.x @Async注解使用的线程池出现的内存泄露问题,提了mr,自己做了源码的hack解决了问题) 341 | 342 | 9、对线上高可用做的一些总结和经验,如何建设一个稳定性保障的平台和机制,熔断、降级、限流、灰度具体的实现,整体方案设计评审等等、机器的容量水位等等 343 | 344 | 10、平时怎么学习的,都看哪些书,有什么收获,沉淀 345 | 346 | 11、有没有问题及补充的 347 | 348 | 349 | 350 | 三面 351 | 352 | 忘记了 353 | 354 | 355 | 356 | 四面 357 | 358 | 只记得让设计一个rpc框架,消费者和提供者的线程有几种 359 | 360 | 361 | 362 | 机哥后话 363 | 364 | 365 | 366 | 不少的小伙伴现在陷入了一种死局,为了应付面试而去学习,导致在他的知识体系中都是零散的知识点,不成结构,这样会导致什么呢?你不论是和别人讨论或者说是技术分享,都很浅薄......就知道那么个点,点到即止了,聊不下去,挖不出什么有价值的思考输出和想法~ 367 | 368 | 所以建议准备面试的小伙伴能够以体系化的方式去复习和学习,当然 369 | 370 | 群内有不少小伙伴拿到了很不错的offer,我都在尽力催着他们快写给我投稿,后续会给大家带来不错的有质量的面经,这样子我就可以不用写技术文章啦~美滋滋...... 371 | 372 | 373 | 374 | 小伙伴最后总结 375 | 376 | 通过这一轮的面试实战,我总结下某大厂核心部门简历评估、技术面试的要求有几方面 377 | 378 | 379 | 380 | 简历评估、初筛 : 381 | 382 | 1、学校背景,top 20学校 软件工程专业加分,211学校加分 383 | 384 | 2、职业经历,是否具有互联网从业背景,自毕业以来一直待在BATJ&TMD&FLAG加分,P6~P6+本科毕业3年到五年 P7~+本科毕业5~8年 385 | 386 | 3、项目背景,有中间件研发背景加分,开源组件贡献者加分,项目深度广度、与现有业务匹配度加分 387 | 388 | 4、其他因素,是否跳槽频繁,kpi得分等等 389 | 390 | 391 | 392 | 第一轮技术面试考察 393 | 394 | 1、java基础、并发基础、中间件原理、jvm、分布式协议、mysql等 395 | 396 | 2、系统设计能力,系统架构的设计、模块功能的划分、微服务的划分、高可用、可拓展性、稳定性的考虑 397 | 398 | 3、编程、算法能力(时间空间复杂度的分析) 399 | 400 | 401 | 402 | 二面 403 | 404 | 1、中间件原理 405 | 406 | 2、生产事故原因的深度、广度、协调推动其他部门的能力、方法 407 | 408 | 3、分布式系统设计,高并发等考虑因素 409 | 410 | 4、工作经历,工作中遇到的最难的问题,如何排查、解决、协调、推动、获取同事们的反馈 411 | 412 | 413 | 414 | 三面 415 | 416 | 1、软素质,沟通协调能力,人品 417 | 418 | 2、项目把控能力,团队成员结构选择,进度把控,风险分析 419 | 420 | 3、学习能力,主动学习的热情,拿到结果的学习才叫学习 421 | 422 | 4、职业规划,职业性(是否靠谱),自驱力,责任心,主动拿结果的想法 423 | 424 | 我也和大家一样在职业生涯初期走过很多弯路,毕业两年多时阿里的一个面试官对我的影响很深,可能没有他的催促和鞭策我可能现在也没有找到努力的方向。我也很能理解大家们职业发展上的迷茫,在这里我也想分享下我自己的一些学习技术的经验,那就是不要痴迷于某项新技术的语法糖或骚操作,尽量从某个领域的大簿头的书开始看起,虽然看的慢,但是对搭建自己的技术体系具有比较重要的作用,博客、知乎、github等学习到的知识总感觉是碎片化的知识,对提升自己的知识广度有帮助,但是对实际生产、工作当中、面试中用到的技术深度、触类旁通的能力得不到锻炼。能够在这个浮躁的社会沉下心来,多看几本专业的书,你其实已经比很多很多人要强了,不要着急,稳扎稳打,争取做生活和工作当中,家人、同事心目中比较“靠谱”的那个人,祝大家在生活、工作中,幸福美满,天天开心~。 425 | 426 | 在此也谢谢机哥、斌哥、暴扣哥等大佬在技术、为人方面的指导与内推,谢谢大佬!!! 427 | 428 | 在此推荐一些某些领域深度和可靠性比较高的书,也欢迎大家给我推荐比这几本更可靠、更有深度的书,谢谢大家。 429 | 430 | 431 | 432 | JAVA基础:《Effective Java》《JAVA编程思想》《数据结构与算法分析》 433 | 434 | JAVA并发基础:《JAVA并发编程实践》 435 | 436 | Spring :我还是建议看看源码,aop和ioc两条腿开始看 437 | 438 | Mysql :《高性能mysql》《innodb技术内幕》 439 | 440 | Redis :《Redis的设计与实现》 441 | 442 | Mq :《Apache Kakfa实战》 《Rocketmq 实战与原理解析》《深入理解Kafka》 443 | 444 | 分布式原理及Zookeeper:《从Paxos到Zookeeper》 445 | 446 | JVM :《深入理解java虚拟机》 447 | 448 | 设计模式 :《大话设计模式》 449 | 450 | 领域驱动设计 :《实现领域驱动设计》 -------------------------------------------------------------------------------- /大厂面经/Interview Exp2.md: -------------------------------------------------------------------------------- 1 | # 阿里三次面试经验和总结 2 | > 该问来自公众号:大数据肌肉猿 3 | 4 | ### 一、投递简历 5 | 6 | 1. **找内推**。大公司投简历尽量找内推,无论是校招还是社招。校招可以去牛客网或知乎找,社招可以在微博、知乎或者找猎头也可以。内推不代表给你的简历加buff,而是能给面试进度加个进度条,便于追踪。 7 | 8 | 2. **不重复投递简历**。我在公司里帮HR调研过一段时间的招聘系统,招聘系统一般会自带去重功能。也就是你找人内推了,自己又在官网投了一次,这样简历来源会从内推渠道转化为官网投递,而有些公司会优先筛选内推的,所以重复投简历显得很没必要。大家在找人内推的时候,他们会跟你说你内推完就不要再去官网投递了,也是这个道理。 9 | 3. 这边补充一个我在我星球里分享的投递玄学,很多同学都说很好用。 10 | 11 | image-20191213213621574 12 | 13 | 14 | 15 | ### 二、准备面试 16 | 17 | 1. 阿里内推的简历是不用去做官网的面试题,包括技术和素质,但做完面试题好像会加快这个内推流程。我在内推完的一星期都没动静,于是去做了官网的面试,做完的第二天就收到了面试通知。我也有几个朋友他们没做面试题的,比我晚几天收到了面试通知。 18 | 19 | 2. **记录面试过程**。这是一个师兄给我的经验,要记录面试过程中面试官问的以及自己回答的,方便面后复盘。从自我介绍到回答问题,看自己的语速、表达,逻辑等等方面是否存在可以改进的问题。由于苹果手机没有录音功能,于是买了根录音笔。 20 | 21 | ![image-20191213213740733](https://tva1.sinaimg.cn/large/006tNbRwly1gaf3qac1erj30yq0u04cl.jpg) 22 | 23 | 3. **做好热身**。阿里是我第一家面试的大厂,也是我第一次远程面,然后我又非常想去,所以导致我很慌,很紧张。我在接到面试通知后到第一次面试只有5天时间,导致我这5天时间只睡了10个小时,天天泡在通宵自习室,早上回宿舍洗个澡,天天在刷题。 24 | 25 | ![image-20191213213805148](https://tva1.sinaimg.cn/large/006tNbRwly1gaf3qh2hocj30yq0kkn64.jpg) 26 | 27 | 假如我在投递阿里之前,先投一些我意向没那么强的大厂,或者我准备阿里面试的时候就不会那么慌,乱了手脚。这也就是为什么说正式面试之前的热身多么重要,我在三面的时候也被说了简历写的不好什么的,这也是没做好的热身的后果啊。 28 | 29 | 4. **写博客或者文档,建立自己的复习体系**。如果平时学习以及面试准备的时候没做好整理和总结的工作,那么在复习时会非常痛苦,会像无头苍蝇。 30 | 31 | image-20191213213928996 32 | 33 | 34 | 35 | ### 三、技术一面 36 | 37 | 1. 一面是真正的纯技术,面试官就是根据他的问题来的,从Java的类、集合问到JVM、多线程,再到大数据框架,全都是岗位要求的技能,也可以看出这些问题都是面试官提前准备好的,而不是按照我简历上面去问的。 38 | 39 | 2. 在回答问题的时候,如果是自己比较熟练,平时深入学习过的,可以回答的详细一点,多一点。毕竟面试时间有限,都是一个小时,会的答的多,不会的比重就减少。所以在有几个问题上我都回答的比较详细,并且跟我做的项目进行联系展开来说。 40 | 41 | 一面只有两个问题没回答好,其他我自己都挺满意的,所以在面试结束后面试官让我等二面通知,我也立马看了官网进度条的变化,激动~ 42 | 43 | ### 四、健身房里的技术二面 44 | 45 | 1. 我在一面结束后,手机立马将静音调成了震动+最大音量,生怕错过了面试电话。每当校招季的时候,牛客网总会出现类似“010 - **** 这个电话是哪家大厂”的帖子,很多校招的面试都由面试官自己去协调的,比如我的两面都是技术面试官打我电话的,所以有时候错过了就真的错过了。 46 | 47 | 2. 在下午三点,我在健身房换好衣服刚要训练的时候,一个杭州的电话突然出现在屏幕上,吓得我赶紧躲在衣柜角落带上耳机开始跟面试官进行交流。面试官一上来连让我自我介绍也没有,直接介绍了他是谁,然后就开始面试了。 48 | 49 | 二面比一面多了几题算法和项目场景题,算法讲思路就可以,一部分Java和大数据的问题,但一面和二面的问题都不重叠,由此可见一面的面试记录他那里也有的。二面面试官问了40分钟让我等通知,然后就挂了,连给我反问的机会都没有。 50 | 51 | 因为我珍惜这个面试机会,所以就算在健身房也跟面试官直接聊上了,没跟他约其他的面试时间,而从面试过程来看,面试官时间很急,好像每个时间点都安排好了一样。在我学习群里,也有很多人因为这种情况错过了大厂面试,有些是没接到电话,有些是跟面试官约了时间,最后不了了之,所以大家且面且珍惜啊,对于自己想去的厂子,还是得多关注一下。 52 | 53 | image-20191213214128396 54 | 55 | 56 | 57 | ### 五、产品经理的死亡三面 58 | 59 | 两面技术面完了之后,帮我内推的小姐姐说我前两面不错,都拿了A,三面真的是我最「无语」、收获最大也是最有意义的一次面试,虽然被惨虐,但对我的帮助还是挺大。 60 | 61 | 1. **项目业务**。面试官先让我对项目进行介绍,然后一个劲地问我业务流程,人员分工这些,还问了我对项目有没有什么看法,能不能改进。说实话我被问懵了,虽然我对项目的技术栈都还算了解,但一个劲地问我业务一下子就转不过来。所以除了技术,大家对自己项目的业务也要去关注一下。 62 | 63 | 2. **项目架构**。面试官问我这个项目能承受多大的并发量,压测数据是多少,问我:“衡量一个系统的稳定性是什么?”。我当时心想:这些是测试干的吧,架构师思考的吧,关我一个开发什么事啊。但现在想想,一个好的开发工程师是应当具备这些知识的,也要带着这些问题进行开发,无论从宏观角度还是用户思维,替系统和用户考虑。在面试结束之后,我马上去图书馆借了本《大型网站技术架构:核心原理与案例分析》这本书,用了一下午通读完,又用一星期时间对这本书的内容进行整理,整理完之后什么QPS、负载均衡、秒杀架构等等顺手捏来。 64 | 65 | 3. **符合岗位的项目**。我面的是大数据开发工程师,但我简历上只有两个web分布式项目,于是被面试官百般蹂躏,一直问我简历上为什么没有大数据项目,项目能更好地巩固理论,为什么理论懂那么多却不去做相关项目等等。反正被问的很惨。我心想:不是说大厂都注重理论基础吗?不是说项目不重要吗?太天真的,那是建立在有项目的基础上。前段时间群里有个小兄弟基础很好,也是因为项目被面试官挂了,补了项目之后开挂一般。 66 | 67 | image-20191213214535975 68 | 69 | 我在三面面试完之后,隔天就开始安排大数据项目的学习,边学边面,后面的一些大厂面试都很顺利。 70 | 71 | 72 | 73 | 三面面试官在结束面试之前问我还有什么想问的,于是我把积攒了很久问题问了出来: 74 | 75 | 76 | 77 | a. 我问了阿里maxcompute里的一个自研消息队列,问他这个跟其他消息队列组件有什么区别。 78 | 79 | 面试官回答:我之前做技术的,但我现在是产品经理,已经不做技术很久了,但我组里的其他在做,所以这个我不太清楚。 80 | 81 | 82 | 83 | b. Dubbo社区最近又活跃起来了,是不是又要重新大力发展Dubbo? 84 | 85 | 面试官回答:这个我也不知道。 86 | 87 | 88 | 89 | ### 六、总结 90 | 91 | 1. 阿里的面试官都挺好,面试的内容是我面试那么多家以来最全面的,问题也没有特别刁钻,都比较符合工作场景。 92 | 93 | 2. 项目很重要,项目是敲门砖也是面试的大头,如果我没有简历上的两个项目的话,估计简历都很难被捞起来,而且进入到3面。很多面试题都是从项目角度去提问的,而且回答的时候也可以结合项目回答,这个很加分。 94 | 95 | 3. 除了项目所用技术之外,也要关注项目的业务以及架构,最好是能融合在一起讲清楚。这边推荐两本书:《**大数据之路:****阿里巴巴大数据实践**》和《**大型网站技术架构:****核心原理与案例分析**》,看完会收获很多。 96 | 97 | 4. 只有多面试,你才能将原有的「我以为」思维变成「原来是这样」。很多东西并不是你想的那样,需要有人去给你当头棒喝才会醒悟。 -------------------------------------------------------------------------------- /大厂面经/Interview Exp3.md: -------------------------------------------------------------------------------- 1 | # 我的阿里第一面,电话+机试 2 | ## 起因 3 | 4 | 2月28日在Boss上,有个阿里的大佬找我打招呼说可以帮我内推,我想也没想就把简历给他了,然后就一直忘记这事了。因为我觉得我一个垃圾学校的小垃圾,怎么会有面试机会,亏人家还让我准备一下,我也抛到九霄云外了。 5 | 6 | 7 | 8 | 9 | 10 | ![img](https://tva1.sinaimg.cn/large/007S8ZIlly1gfu5i6sop9j30e40ii74p.jpg) 11 | 12 | 13 | 14 | 15 | 16 | 然后也收到了阿里的内推消息 17 | 18 | 19 | 20 | 21 | 22 | ![img](https://tva1.sinaimg.cn/large/007S8ZIlly1gfu5i6fxyrj30hs099dg6.jpg) 23 | 24 | 25 | 26 | 27 | 28 | ## 开始第一轮电话面 29 | 30 | 然后在3月4号的晚上8点钟(看来阿里的工作时间确实长,我估计面试也是他们kpi的一部分吧),一个来自杭州的陌生电话打过来 31 | 32 | ### 面试官 33 | 34 | > xxx,你好,我是杭州阿里巴巴xxx的,我想问你现在有没有时间,我来简单的给你做个面试,你这边先来个自我介绍 35 | 36 | ### 我 37 | 38 | > 当时我还没意识到是内推,因为我早已经忘的差不多了,还以为是啥新的诈骗方式,直到他说它是来给我面试的,然后说有人内推过我的简历,我这才想起几天前的事情。然后我巴拉巴拉的做了一个传统的自我介绍,就是那些套路,之类的,然后面试官开始问问题了 39 | 40 | ### 面试官 41 | 42 | 你对多线程了解吗,说说你对Synchronized和lock,说说他们之间的区别 43 | 44 | ### 我 45 | 46 | > 其实这个问题,应该算是很基础的问题了,我就说了一下,一个乐观锁,一个是悲观锁,然后说了一下Synchronized的锁升级的过程(这个还行我自己觉得),然后我说了一下 Synchronized 锁方法 ,静态方法,同步代码块的一些区别(这个点其实我没答上来,有点忘记了。就是在JVM里面的标记位不同的区别),然后是lock这点我也没答上,这个应该说他的几个实现,然后跟面试官聊聊他的底层实现原理,但是我这个是目前真的不是很熟悉,因为平时不用,可能前面走马观花的看了,但是这次面试是突击,所以真的对于lock就是知道他是aqs实现的具体的全忘记了 47 | 48 | ### 面试官 49 | 50 | > 然后面试官说lock不熟,没事,那你还有没有用过什么东西来保证线程安全 51 | 52 | ### 我 53 | 54 | > 然后突然想到了一下CAS,然后说了一下CAS,这个我感觉说的7788吧,至少怎么保证安全的我说出来,先在本地线程记录原来的值和计算之后的值,去刷到主存的时候,先比较原来的值。但是他让我说底层原来的时候,我又好像说错了,我把他和voliate搞混了,我竟然说是因为有一个内存总线,真的是尴尬呀,能够说让其他的本地线程无效,在Cpu层面(这就是那种靠背的结果,哎),其实CAS的底层是一个lock指令来实现的再多核系统中,反正就这样扯。。被我扯到了分布式锁。。。我感觉自己拉开话题的技术还是可以的,哈哈 55 | 56 | ### 面试官 57 | 58 | > 你说你们公司用的redisson来实现分布式锁,如果不用redisson你能实现分布式锁嘛,自己用redis,或者你给我说说redission是怎么实现分布式锁的 59 | 60 | ### 我 61 | 62 | > 当时我就在想,我怎么把自己从一个坑,挖到另外一个坑,因为redisson的底层源码,我是真的没看,这个我是真说不出来,然后我就说怎么实现分布式锁,用exist 和 setNX命令,还有加超时时间,然后用lua脚本做成一个原子性操作,来实现一个分布式锁,这个我以前自己做过demo,然后现在手写不出来,但是至少做过,印象还是深点。然后我就搭了一下,然后他又说,那你还有什么方法保证原子性呢?我其实也不清楚他想问的是啥,我就随便搭了个事务。。。。 63 | 64 | ### 面试官 65 | 66 | > 我看你对redis 蛮熟悉的,那我们就来聊聊redis,说说他的数据结构 67 | 68 | ### 我 69 | 70 | > 我靠,终于来了个会的了,哔哩吧啦的说了一下,然后他又问了一些基础的东西,比如说缓存穿透这些,这些其实还好,毕竟自己有试过。 71 | 72 | ### 面试官 73 | 74 | > 既然你对redis那么熟悉,你知道为啥redis那么快嘛 75 | 76 | ### 我 77 | 78 | > 其实这个问题是为后面做铺垫的,我搭 单线程 内存 IO多路复用,妈的这个IO多路复用我只是以前看书的时候看过,我根本还不是很熟悉这个东西,然后他就盯着这个问了。。。然后我就尴尬的一批。就没问我了,可能知道了我的深度了吧,哈哈 79 | 80 | ### 面试官 81 | 82 | > 那你对多线程方面的知识,还有哪些了解的,比如线程池,或者原子性的类这些 83 | 84 | ### 我 85 | 86 | > 我心里,一万字曹尼玛,又来多线程,然后我说了几个我自己并不是很熟悉的原子类,然后聊到底层,又不会(还是太菜),然后聊线程池,然后聊线程池的创建,线程池的运行过程,然后他的优化啥的,然后聊了一下,感觉我也没啥深度,就终于不再跟我聊多线程了,(目前为止,就聊了2个东西 redis和多线程,redis的东西,至少我感觉比多线程要好很多),然后面试官,又开始问了 87 | 88 | ### 面试官 89 | 90 | > 我看你用的rabbitmq 说说你是如何保证消息的可靠性的 91 | 92 | ### 我 93 | 94 | > 这个其实还是很简单,从发送端就是 confirm机制,接收端就是用的ack机制,然后引用到我们自己项目用的Aop把失败的消息存到redis中,并通知相关负责人去处理,这样,然后我来聊到了 我用它来做分布式事务的可靠消息最终一致性,因为这些东西都是我自己引申过去说的,肯定是我比较会的,说到了如何去做它的幂等,防止重复消费,然后中间还插了一下rocketmq ,可惜我不是很熟悉,它里面的事务机制,稍微说了下 然后说了一下它的持久化机制啥的,最后它问了一个啥问题,说假设你什么都做到最好的情况下,怎么样才能更好的保证消息的可靠,包括你的服务器被炸了,断点,啥的。。。完成不知道再问啥,然后mq就没问了,其实看着说的简单,但是实际聊的东西还是有点的,什么死信队列啥的都是有设计到的。 95 | 96 | ### 面试官 97 | 98 | > 我看你对JVM调优有了解,我们聊聊JVM吧,然后因为垃圾回收算法,垃圾回收器。 99 | 100 | ### 我 101 | 102 | > 这个还好毕竟自己有看过这方面的知识,然后就把JVM的知识说了一遍,反正就是自己知道各种扯 103 | 104 | ### 面试官 105 | 106 | > 说说你是怎么定位线上问题的定位吧,比如说CPU 或者是内存 107 | 108 | ### 我 109 | 110 | > 其实我这块没怎么实战过,还是看过一些人家的解决方案,然后我就靠着记忆 111 | > 112 | > Cpu:通过 top 命令找到 CPU 消耗最高的进程,并记住进程 ID。再次通过 top -Hp [进程 ID] 找到 CPU 消耗最高的线程 ID,然后找到线程ID是十进制的,把他转换成十六进制,然后用jstack找到当前线程的jstack.log的快照,然后分析他的问题。 113 | > 114 | > 内存:其实对于内存的话无非就是2种一直是内存溢出,另外一种是内存不健康,就是内存泄露 内存溢出的情况可以通过加上 -XX:+HeapDumpOnOutOfMemoryError 参数,该参数作用是:在程序内存溢出时输出 dump 文件。有了dump文件,我们找问题就很简单了,比如我们用MAT等等,找到原因 如果是内存泄露的话就得具体分析了 比如你的young GC的频率,和Full GC的频率 ,如果是和平时完全不一样的话,我们也可以用MAT去分析一下看是否是每个对象占用的内存特别大,并且还没有回收他,然后找到这个对象去分析他的逻辑,并且来解决这种内存泄露的问题 115 | 116 | ### 面试官 117 | 118 | > 聊聊MySQL吧,平时怎么做查询,优化 119 | 120 | ### 我 121 | 122 | > 反正就是那些套路 什么索引啥的,说到索引了,那你对b+数熟悉吗,我。。。。又是挖坑给我,我擦。我就其实我不懂,我因为没有准备去面试题。。。。唉(还是不能注重形式) 123 | 124 | ### 面试官 125 | 126 | > 没关系,我们来聊聊MySQL的隔离级别 127 | 128 | ### 我 129 | 130 | > 我又把那几个背了一下(还好这个好记得,因为真的是死背的以前) 131 | 132 | ### 面试官 133 | 134 | > 那你给我说说 可重复读的底层实现原理嘛 135 | 136 | ### 我 137 | 138 | > 我擦,又掉坑里面去了。。。。唉我就只好说,还没空去了解这块 139 | 140 | ### 面试官 141 | 142 | > 没关系 我看你用的SpringCloud 聊聊他的组件吧 143 | 144 | ### 我 145 | 146 | > 然后我有哔哔哔啦 把这些基础的 平时工作的这些分布式组件给他说了 147 | 148 | ### 面试官 149 | 150 | > 那你给我说说 注册中心怎么保证自己的高可用的 151 | 152 | ### 我 153 | 154 | > 其实这个还好,以前背过哈哈 我就把自己对2pc的选举过程崩溃恢复,数据同步的过程扯了一遍 155 | 156 | ### 面试官 157 | 158 | > 既然你对2pc 这么熟悉。我给你个场景,你说说看这种情况怎么处理,就是因为网络原因,出现了双主问题。 159 | 160 | ### 我 161 | 162 | > 我的内心的崩溃的,其实我都不知道再说啥了反正,不过有一点我是知道的,肯定是再瞎说,因为我自己也真不知道自己再说什么了,然后只能说,这个不是很清楚 163 | 164 | ### 面试官 165 | 166 | > 好点,没事。那你说 对于分布式系统来说,除了我们经常说的2pc 3pc还有什么更好的方法来做数据一致性 167 | 168 | ### 我 169 | 170 | > 然后我又不知道要说啥了,又只能说不知道了 171 | 172 | ### 面试官 173 | 174 | 然后又问了下Spring ,对于Spring的一些源码的理解 175 | 176 | ### 我 177 | 178 | > 我靠,终于问到一个我会的了,然后我就Spring容器的初始化过程 和Spring单例bean的注入过程,和循环依赖讲了一下。这个它竟然没往死里问我了,哈哈(看来平时看点源码还是有点用的) 179 | 180 | ### 面试官 181 | 182 | 你现在有电脑吗,我们来做个机试吧, 183 | 184 | ### 我 185 | 186 | > 然后我说我没带电脑,我想着就说算了吧,谢谢您的好意,我反正也过不了,然后它就再三约我明天晚上来做,我就说 没有补全 我代码都写不全的,但是它还是邀请我参加,我就只能答应了,然后就挂了电话 187 | 188 | ## 开始我的阿里第一次机试,估计也是最后一次(哈哈) 189 | 190 | 当时我跟这个面试官约的是3月5号 8点以后,看来在阿里工作也是蛮长时间的,但是人家工资高,哪里像我们做的多,工资少,不过人家水平高,这个没办法 191 | 192 | 到了8点,面试官主动给我打了个电话,然后把机试题目发到了我邮箱,然后高速我看着我写,我心理拔凉的,担心啥也写不来: 193 | 194 | ![img](https://tva1.sinaimg.cn/large/007S8ZIlly1gfu5i86bi4j30hs043mx4.jpg) 195 | 196 | 197 | 198 | 199 | 200 | 然后题目其实很简单 是力扣上的24题,但是我当时做的时候并不知道,我也不能百度,可惜我在那瞎写写了30来分钟,但是也是完成没有搞懂再干嘛: 201 | 202 | ![img](https://tva1.sinaimg.cn/large/007S8ZIlly1gfu5i77tfgj30hs043mx4.jpg) 203 | 204 | 205 | 206 | 207 | 208 | 最后只能选择放弃: 209 | 210 | ![img](https://tva1.sinaimg.cn/large/007S8ZIlly1gfu5i7p4s6j30hs0gg0t3.jpg) 211 | 212 | 213 | 214 | 215 | 216 | ## 结束我的阿里面试旅程: 217 | 218 | ![img](https://tva1.sinaimg.cn/large/007S8ZIlly1gfu5i8qribj30hs06oq2y.jpg) 219 | 220 | 221 | 222 | 223 | 224 | ## 结尾 225 | 226 | 哈哈,其实还是自己太菜了,虽然说我连一面都没过(菜是原罪),但是这次面试给我的帮助还是很大,让我在没有准备的情况下知道了自己的水平,应该算是比较真实了把,还有一点就是我们工作中大都是CV大法,导致我很多的基础代码都不是很会,基础不扎实,虽然这个机试是算法,但是我很多简单代码没有补全都不会,很多简单工作的实现都是百度,导致自己的动手能力弱了很多。这点以后要改,我呢?把这次经历分享给大家,希望大家要引以为戒。好好学习,扎实基础。 227 | 228 | 作者:六脉神剑 229 | 230 | 链接:https://juejin.im/post/5e60f6d05188254963276acc 231 | 232 | 来源:掘金 -------------------------------------------------------------------------------- /大厂面经/Interview Exp4.md: -------------------------------------------------------------------------------- 1 | # 我的奇葩面试经历:HR竟然主动提价,比预期高了5K,我一脸懵逼... 2 | 3 | 本文是minus同学投稿的面试经验分享,在此感谢minus同学分享自己的面经供广大同学参考。 4 | 5 | ## 写在前面 6 | 7 | 本文是楼主前两个月 N 家公司的面试经历,总结复盘了面试现场,个人认为干货还是不少,在此和大家分享。 8 | 9 | ps:至于标题所说的薪资,是面试过程中一个有意思的小插曲,但是确有其事,不是标题党。。。这里先卖个关子,请各位看官往后看! 10 | 11 | ## 自报家门 12 | 13 | 先做个自我介绍,楼主坐标帝都,5年经验,跳槽之前在一家传统小公司,年薪21万。 14 | 15 | 这次面试前前后后大概两个月的时间,面试了大概 6 家公司,命中 4 家,最终去了一家估值 70 亿美金的生鲜电商独角兽,年薪42万,刚好翻倍。 16 | 17 | ## 面试过程 18 | 19 | 话不多说,直接进入面试现场! 20 | 21 | 1、好未来 22 | 23 | 开始面试第一天上午投递好未来,下午3点面试,一共面试了3轮,问的问题比较多。 24 | 25 | 第一轮 26 | 27 | 面试官看了我的简历,首先让我画出eureka的执行流程,这块在之前的准备过程中有深入看过,因此比较流畅的画出来并配合解释说明。 28 | 29 | 之后问到项目中使用分布式锁解决缓存重建并发的问题,并要求画出实际的执行流程,数据库也问的比较多,像事务的隔离级别,MySQL实现可重复读的原理,索引等。 30 | 31 | 面试官给出了一个场景,在数据库主从同步的情况下,如果从库同步主库的数据延迟比较高,怎么才能在写到主库后立刻能够读取到数据。 32 | 33 | 我解释了主从同步的原理,并以此说明主库到从库的复制一定是有延迟的,因此要保证当写到主库的时候立刻能读到数据,要么就直接配置那个接口读数据的话直接走主库,因为这种写完主库立刻要读取数据的场景比较少,可以做些特殊配置。 34 | 35 | 另一种方案就是在往主库写数据的时候,可以直接往内存缓存中写一份,设置一个较短的过期时间,后面可以直接从缓存中读到数据。我说完之后,面试官也没给出评价,就这么过去了 36 | 37 | 此外,还问到一些基础性的问题,比较印象深刻的是:在加锁的时候,用什么锁对象是内存占用最小的,我说是Object对象,面试官说不对,我一时没想出来,面试结束后和朋友探讨,觉得应该是长度为 0 的 byte 数组 38 | 39 | 其他还问到了Collections.sort()使用的排序算法,aqs,线程池,ThreadLocal等等问题,主要都是一些考察基本功的问题,一轮面试就这么过去了! 40 | 41 | 42 | 43 | 第二轮 44 | 45 | 面试官更关注对一些技术的理解,问到了ElasticSearch的一些基础以及它和mysql的区别在哪里;eureka 和 zookeeper 做服务发现的区别在哪里; 46 | 47 | 还问了分布式限流有哪些方案,以及用线程池进行限流的缺陷是什么,项目中系统日志的处理;还有 JVM 模型,JMM 模型,垃圾回收机制,垃圾收集器等问题。 48 | 49 | 之后聊了一些设计模式的使用,在项目中使用了哪些设计模式,对设计模式的几个原则的理解。 50 | 51 | 第二轮结束后,由于第三轮的面试官在开会,所以等了一段时间,等面试官来了之后,只聊了很短时间,面试官就说还有别的事,今天先到这里了。 52 | 53 | 主要问到了上家公司的加班情况,对加班的认识,职业规划,也问了几个技术问题,像tomcat的优化这块,自我感觉答的不是很好。 54 | 55 | 整个面试从3点到7点,有点虎头蛇尾的感觉,结束后也没有消息了。 56 | 57 | 58 | 59 | 2、58 到家 60 | 61 | 面试一共三轮,上午10点过去,两轮技术面,下午两点过去,等了一会,然后跟hr聊了有半个多小时,HR说明在一周之内会有结果。 62 | 63 | 64 | 65 | 第一轮 66 | 67 | 第一轮面试官的问题主要集中在基础上,我大概罗列了问到的一些问题,不同的简历不同人肯定问的也不太一样,有兴趣的同学可以参考看看。 68 | 69 | 主要是 jvm 模型,锁的原理,synchronized 和 reentrantlock的区别,偏向锁/轻量级锁/重量级锁的原理,能否从偏向锁直接升级成重量级锁。 70 | 71 | java并发包里有哪些类,如何使用,线程池原理和参数配置,jvm调优,堆大小的设置,多线程的线程数的设置,volatile原理,threadlocal原理和使用。 72 | 73 | redis和zookeeper如何实现分布式锁,redis的数据类型,一些具体命令,比如要获取一个有序列表的前10个元素应该用什么命令。 74 | 75 | 数据库索引的使用,聚簇索引和非聚簇索引,没有主键的话数据如何组织。 76 | 77 | B+ 树的原理,Innodb 引擎和 myisam 引擎的区别和使用场景,数据库隔离级别和原理,MySQL的分库分表,mq的可靠性和顺序性,es插入数据的原理等。 78 | 79 | 80 | 81 | 第二轮 82 | 83 | 第二轮是部门leader来面试,这轮面试主要集中在框架源码上,我画出了源码的执行流程,之后面试官在一些点深问,因为这块我看的比较全面,问的问题基本都答出来了 84 | 85 | 然后这里面试官还问了在源码中我有学到什么东西,我讲了使用配置类代替 properties 文件,volatile 在单例模式中的使用,内存的多级缓存机制,线程池的各种不同应用场景,MeasureRate统计一分钟内心跳次数,批处理机制等。 86 | 87 | 这里我的回答主要集中在代码编写层面,也可以从架构层面说下学到了哪些,我觉得后者更有高度。 88 | 89 | 最后我向面试官咨询了这个岗位具体做的事情,部门是基础服务部,面试官画图给我说明了部门内部一些项目划分,技术栈的使用,后续的规划等内容,并约我下午继续跟hr聊 90 | 91 | 92 | 93 | hr面 94 | 95 | 下午跟hr的面试,hr顺着简历上的公司一个个聊,问了离职原因,公司情况,如何向上司提出离职的,团队规模,是否带团队。 96 | 97 | 还问了上午面试的岗位知不知道具体要做什么,之后hr说了下公司的一些情况,上班时间,福利,加班情况,问了我现在的薪资情况,期望薪资,我问了下出结果的时间,hr说一周之内。 98 | 99 | 第二周的周五下午六七点的时候,这家公司hr给我打电话,告诉我面试通过了,之后提到了给我的薪资,算下来竟然只给了我一个5%的涨幅。 100 | 101 | hr给出的解释是,因为我前家公司上一年只发了12薪,而他们有12薪和两个多月的绩效,用14个月的薪水除以12,算下来平均到每个月也能达到我期望薪资的水平。 102 | 103 | 这个计算方法实在是膈应人,虽然hr后来表示可以跟CEO申请提高每月的base(大概提高到10%的水平吧),不过当时我已经有较为满意的offer了,还是决定不去这家了。 104 | 105 | 106 | 107 | 3、某生鲜电商独角兽 108 | 109 | 由于前面说了薪资,就不说具体公司名字了。这家公司我面试了两天,一共三面,第一天笔试加初面,然后第二天有两轮复试。 110 | 111 | 112 | 113 | 第一轮 114 | 115 | 一面主要还是基础,集中在IO / 并发 / 缓存 / redis / zookeeper / 分布式 / JVM / 数据库等。 116 | 117 | 其中问到 redis 的单线程模型的时候,我这块了解的不是很清楚,只是知道使用NIO的方式,然后以自己的理解去说了,面试官表示这可能是我看过别的框架的模式,跟redis搞混了,不过也算是答上来一些了。 118 | 119 | 之后聊了一些项目的情况,比如每日的访问量有多少,qps多少,订单量多少等数据,据此得出数据库的访问压力如何。另外也深入问了使用分布式事务的一些问题,还有分布式事务在时间上的性能。 120 | 121 | 所以这里给各位兄弟强调一下,对自己的项目一定要非常熟悉,各个点都要考虑到。 122 | 123 | 一面跟面试官聊的还挺好,面试官也表示我的基础还不错,问我是不是平时都有学习,之后就是约二面了,由于当时已经下午1点了,后面的面试官也在中午休息,而我下午也还有别的面试,因此hr跟我约第二天来复试 124 | 125 | 126 | 127 | 第二轮 128 | 129 | 二面的面试官也聊了基础和一些设计上的问题,比如同时访问三个有相同功能的api,要求将执行最快的结果返回,有哪些方式,这块主要还是考察对并发编程,并发控制的理解和掌握,有一些并发控制的类能够做到; 130 | 131 | 其他的还问到了,要开发一个新的api,需要考虑哪些方面,把所有要考虑的地方都说出来,大家可以说下边界处理,高可用,并发问题,可扩展性,幂等性,重试机制等等,可以说的非常多。 132 | 133 | 总体问了有6块内容吧,面试官一边问也一边在记录,一些基础的问题这里就不再多说了。 134 | 135 | 136 | 137 | 第三轮 138 | 139 | 三面的面试官问的要更底层一些,Java线程与内核线程的关系,与进程的关系;关于并发我所了解的方方面面。 140 | 141 | 对于这个,我从为什么有并发,并发问题产生的根源,解决并发问题的一些理论,Java中解决并发问题的方式,不同方式的适用场景和对比等方面进行了回答。 142 | 143 | 另外还问到redis的几种数据类型,以及每种数据类型的底层实现,跳表这种数据结构如何插入数据, hash如何扩容。 144 | 145 | 这块我跟面试官说具体扩容规则不太了解,然后向面试官说了我了解的Java中的HashMap 的扩容规则和具体实现。 146 | 147 | tips:面试时如果遇到自己不太熟悉的部分,可以稍作变通,把自己熟悉的内容和面试官的问题结合起来。 148 | 149 | 之后又问了一些小的知识点,有的也没答好,像 copyOnWrite 就不知道用来做什么,然后就是一些为什么离职之类的问题,对未来职业发展的考虑等。 150 | 151 | 之后面试官问我有什么想了解的,也问了我的期望薪资,我说了具体的数,也表示没想要太多,更看重平台的发展,最后面试官说明天hr会打电话给我 152 | 153 | 154 | 155 | HR面 156 | 157 | 最后就是跟hr的沟通了,第二天hr打来电话告知面试通过,然后问了我期望薪资,沟通入职时间,之后加微信,按照hr的要求提供了一些材料,第二天就收到offer了 158 | 159 | ps:最终楼主选择了这家公司,除了很有竞争力的薪资之外,我还很看重这家公司的发展平台,因为他们有非常大的用户量,会遇到各种技术挑战,是很好的提升锻炼的机会。 160 | 161 | 然后这里有一个开篇提到的小插曲:当时HR电话问我期望薪资的时候,我说25K。 162 | 163 | 结果后续加微信聊天时,HR告诉我技术面试的反馈很好,决定给我28K,一个月还有2500的补助,算下来一个月有30K,发14个月。这种HR主动加薪的事情我还是第一次见,意外之喜,哈哈! 164 | 165 | 166 | 167 | 4、玩吧 168 | 169 | 这家公司的职位是去做app后台的,用户量也不错,面试一共两轮技术面,最后是hr面。 170 | 171 | 172 | 173 | 第一轮 174 | 175 | 一面的时候,网络这块问的比较多,三次握手,四次挥手什么的,还有整个网络请求的执行流程,数据包的大小,对长连接的理解等。 176 | 177 | 然后数据库这块也问了一些,提供了一个场景,假如要实现一个最简单的朋友圈,用户可以看到朋友的朋友圈动态,朋友也可以看到用户发的动态,然后问表的设计。 178 | 179 | 我说了自己的实现,像用户表,好友表。面试官问有没有更好的方式,我没答上来,面试官表示这个轻易可能想不到,就问别的问题了,别的也没什么特殊的问题,都是一些基础的东西,大概聊了一个小时吧,就到了第二面了 180 | 181 | 182 | 183 | 第二轮 184 | 185 | 二面是技术总监面的,整体没怎么聊技术,就是一些个人素质上的考察。比如: 186 | 187 | 为什么会选择做开发,没做别的 188 | 189 | 用三个短语来描述自己的优点 190 | 191 | 说说自己的缺点 192 | 193 | 现在公司有系统稳定运行着,如果你发现了有新的技术能够改善现有系统,你会不会引进,会考虑哪些方面 194 | 195 | 日常学习的方式,看过哪些书 196 | 197 | 有没有带团队,描述下团队成员的优缺点,有没有改善 198 | 199 | 有没有面试过别人,会从哪些方面考察 200 | 201 | 职业规划是怎样的,想做技术管理还是技术专家 202 | 203 | 对shell熟不熟悉,写个word-count用到哪些命令 204 | 205 | 最后还聊了下公司的氛围,项目的情况等。然后也没啥特殊的,就过了。 206 | 207 | 208 | 209 | HR面 210 | 211 | 最后跟hr聊,主要还是说了下公司的福利待遇,公司的氛围,也问了我现在有没有offer,对他们的感觉怎么样。 212 | 213 | 然后问了之前公司的薪资和现在的期望薪资,最后加了微信,告诉我两天内给结果。最后也是成功通过了面试并拿到了offer。 214 | 215 | 216 | 217 | 5、友信金服-人人贷 218 | 219 | 这家公司面试有三轮,大同小异,这里简短的说一下。 220 | 221 | 222 | 223 | 第一轮 224 | 225 | 一面仍然是基础的考察,像CAS的理解,和它存在的问题,ConcurrentHashMap的锁机制,ElasticSearch倒排索引,eureka的底层源码,还有服务访问的重试机制等等。 226 | 227 | 228 | 229 | 第二轮 230 | 231 | 二面上来问了垃圾回收的问题,类似下面的代码: 232 | 233 | 问a和b能否被垃圾回收? 234 | 235 | 这里主要考察jvm如何判断一个对象是否可以被回收,是通过引用计数还是可达性分析,引用计数的方式会产生像上面代码一样的循环引用的问题,所以jvm没有采用这种方式。 236 | 237 | 第二个问题是,如果有个跟java中原生的String一摸一样的类,包括包名,类名都是一样的,方法也是一样的,唯独比原生的String的方法多个打印输出语句。 238 | 239 | 然后把它放进项目的依赖中,在写程序的时候,导入String类,问到底执行的是Java原生的String的方法还是自己写的String方法。 240 | 241 | 对于这个问题,可以考虑下Java中类加载的双亲委派模型。 242 | 243 | 然后就聊了项目的一些架构,问的比较细,要求我对每块都详细画图解释。 244 | 245 | 最后就是让画一个spring cloud技术栈所有框架的整体执行流程图,并对hystrix的限流熔断机制做了解释说明,别的好像也没什么了 246 | 247 | 这之后二面算是结束了,面试官和我说了下自己团队的情况,人员情况,要做的项目的情况等。 248 | 249 | 250 | 251 | 第三轮 252 | 253 | 最后一面是业务总监面的,面试官让我说了下自己在公司做了哪些事情,我挑其中一个项目做了仔细说明,然后说了下职业规划,对行业的看法等等。 254 | 255 | 最后hr和我加了微信,同样说是两天内给结果,不过第二天他们就给出通过的结果了,然后发了offer。 256 | 257 | 258 | 259 | 6、某实时数据分析服务公司 260 | 261 | 这是一家做体育赛事的实时数据分析展示的公司,公司不大,去年拿了A轮融资,看网上整体评价还不错,就去试了试。 262 | 263 | 面试总共有技术两轮,hr一轮。去的时候首先是写笔试题。做完之后进入面试。 264 | 265 | 第一轮面试官没有聊太久,问的问题也比较偏基础,就是一些面试常问的问题,然后说了eureka的执行原理,说完之后,面试官就去叫技术总监了 266 | 267 | 第二轮面试是技术总监面的,技术点没问太多,主要集中在之前的笔试题上,笔试题包括sql的考察,还有几道算法题:找出有序数组中指定元素出现的次数;二叉查找树从小到大排序。因为时间的问题,我主要写了实现思路; 268 | 269 | 还有一题是,有16瓶水,其中一瓶有毒,小白鼠喝一滴有毒的水一小时后会死,要在一小时找出来哪瓶水有毒最少需要几只小白鼠。 270 | 271 | 在sql的考察这块,面试官看完我的答案后,又改了其中的需求,要求给出sql的实现,另外也问到了sql的执行效率。 272 | 273 | 这里给大家强调一下,我面的基本上每家公司面试都会问到数据库,所以这块还是挺重要的,需要重点去看。 274 | 275 | 然后关于找出有序数组中指定元素出现次数的问题,原来要求的时间复杂度是O(lgn),后来面试官说不要求任何时间空间复杂度,如何简单的实现,我给出的方案是用HashMap,相同的key每出现一次,value加1。 276 | 277 | 然后是小白鼠问题,说了解题思路,主要就是用位的思想,对16瓶水编码,实际只需要4个位就可以。 278 | 279 | 之后面试官还现场出了别的算法题,我基本都给出了结果,总体而言面试还比较顺畅,之后聊了下职业规划,技术发展,学习新技术的方法,面试官也聊了之后他们准备做的事情,并给我现场演示了他们的项目。 280 | 281 | 最后到了hr面,主要聊了下上家公司离职的原因,公司福利,上下班时间,我的期望薪水,还问到之前有没有带团队的经历等。 282 | 283 | 最终他们在第二周的周四才给出面试通过的结果并表示正在走offer流程,由于CEO不在,在薪资上还没最终确定,我因为有了更满意的offer,因此婉拒了。 284 | 285 | 286 | 287 | ## 总结 288 | 289 | 总结一下,这两个月的面试,我觉得最重要的就是基础和项目这两块,基础一定要扎实,否则第一轮面试可能都过不了。 290 | 291 | jvm,并发是非常高频被问到的地方,在开始面试之前一定要好好准备,另外也需要有自己非常熟悉的领域,在这个领域里面试官的一切问题你都可以hold住,我觉得,对于这种基础好,而且有自己长处的面试者,面试官没有理由不喜欢。 292 | 293 | 还有项目这块,对项目的细节一定要清楚,各种方案的设计思路,实现细节等等都要了如指掌,这样在面试官对各种细节的追问下不至于手忙脚乱。 -------------------------------------------------------------------------------- /大厂面经/Interview Exp5.md: -------------------------------------------------------------------------------- 1 | # 鸡哥的面经 2 | > 该文来自:【公众号:再见伐木机】 3 | 4 | **前言**:很多人的面经可能是自己的一些经验之谈,也可能是一坨很长的各个公司遇到的面试题,而我其实很了解大家的诉求与渴望,但并不是说你看了这篇文章就可以立刻变强,饭要一口一口吃,路要一步一步走,目前面试了几家独角兽和一线大厂,都拿到了offer,几乎是100%的成功率。 5 | 6 | 7 | 8 | 下面的内容第一部分是经验+学习方法,第二部分是如何准备你的面试 9 | 10 | 11 | 12 | **鸡汤**:我这个人挺爱玩游戏的,爱玩dota,玩了七八年了,也玩LOL,但是我经常会把游戏比做是人生,我从来没有主动点投降过,即使背靠的世界之树已经快凋谢,但是我坚信一定能找到对手失误的时候一波把别人打趴下。我经常挂在嘴上的口头禅:怕,你就会输一辈子。所以无论何时何地,保持自己的竞争意识,和自己比,亦或是和优秀的人比,都会不断促进自己的前进...... 13 | 14 | 15 | 16 | **现实**:这一段话其实是会有很多共鸣,当然这段话其实也是我在这篇文章快结尾的时候补上的,就是在职场,在人生中,不要轻易地看不起起任何一个人,也不要以第一印象去定夺一个人,别人受到了你的嘲讽,你的偏见,但别人也会因此暗下决心,请不要让第一印象,偏见暗自在黑暗中生长,可能别人会奋起直追,当别人超过你的实力的时候,别人回过头发现,其实去报复你,去反击你之前给过的偏见的时候,却已经没有这个必要,因为不在一个Level了,就像你当年在高处确看不起低处的人一样,别人他日站在高处发现为什么要去和低处的人比较,实属可笑。当然我身边有几个这样子的例子,经历过嘲讽,经历过不屑,每天只睡三四个小时去拼了命的前进,没有任何娱乐,虽然他已经成长为一个大牛,他却说曾经的偏见的眼光给他带来了激励,但同时也带来了深深的伤害...... 17 | 18 | 19 | 20 | **我的复习历程:** 21 | 22 | 阶段一(学习方法之“记忆宫殿-联想记忆”):在我一年前给自己定下要去XX公司的目标之后,不间断的准备了一年,这一年中,我到处在知乎,脉脉,网上,技术群中搜寻着别人的面试题,然后看,做,遇到不会的去查阅资料进行回答然后储备到自己的知识库里......一个惊人的数字:据不完全统计,我看过的面试题可能超过上千道(所以现在别人问我一个题目,基本上都能回答出来),当然一年之中的周六日大部分时间都是去公司学习,平常的节假日回家之后当然也是看书和学习,平常工作日一般会下班之后到家抽出1-2个小时继续学习;这一年中读了大概六七个框架的源码,看了不少的书,所有的视频都是两倍速的速度来训练,所以有些人看到我看视频的时候会觉得很疯狂,别人的语速太快了,都会问我别人讲的这么快你听得懂么?其实也是训练出来的,一开始是1.2倍,到1.5倍,到1.8倍,到最后的2倍,再快的话声音就会失真了;当然读书的速度也是成倍的提升,我记得在机场候机的两个小时刷完了一本书;依稀记得过年的几天假期也仍然保持着一天至少6个小时以上的学习时间,导致一些亲戚朋友过来串门的时候都觉得我很冷漠,不理别人,当然这不算什么,因为周围遇到的几个人会更拼,有些人工作日一天持续3-4个小时学习,非工作日10个小时,有些人甚至一天可能只睡4-5个小时的时间..... 23 | 24 | 25 | 26 | 正所谓 取法其上,得乎其中;取法其中,得乎其下,但其实这一年的成长远超过我前两年浑浑噩噩的工作及生活。 27 | 28 | 29 | 30 | **ips:**我当年考驾照的科目一也是这样,一晚上刷了上千道题目,第二天去考试,你可以理解为题海战术,但不仅仅是题海战术,这个时候我引申出我的学习方式的第一大杀器----“记忆宫殿”之“空间联想” 31 | 32 | 33 | 34 | 我其实高中甚至大学的学习方法很烂,因为一直找不到我自己的学习方法,都是题海战术,靠熬夜,靠多写题目去和别人拼,后来发现成绩并没有提高,当时的我多渴望有人直接告诉我一个完美的学习方法,那我直接按照做就好了,然而事实是我在毕业之后,工作的时候才真正找到了属于我的学习方法。 35 | 36 | 37 | 38 | 所谓“记忆宫殿”之“空间联想”,并不是像卷福那样把知识点都放在脑子中,想像成自己熟悉的各个地方存放,我这里的“记忆宫殿”也是脑海中的一片连续的内存空间,像数组一样,这时候我每吸纳一个知识点,我会立刻在这片连续的内存空间中找到能和这个知识点强引用,软引用,弱引用关联的地方,将他们像树形结构一样串起来,所以当我以后想到一个知识点之后,我会立即联想到与他各种关联的知识点,脱口而出的不再是某个单一的知识点,而是既有水平横向的对比,又有纵向垂直分析的过程。 39 | 40 | 41 | 42 | 上述描述可能会有点抽象,这时候我举一个例子:假设我现在脑海中有一个知识点(为了通俗易懂,我的例子尽量平易近人),这个知识点是这样,一个结构CopyOnWriteArrayList,基于一把独占锁的读写不互斥的线程安全的结构[不清楚的可以专门看一下源码或者找网上博客去看一下],而这里我们要汲取的知识点并不是它作为一个结构被我们记住,而是它其中的思想(写时复制),所以每次当我听到COW这个东西,我大脑中的那COW一片区域会有大量相关的知识点出来,比如redis的RDB主从复制也是用的COW这种思想,说白了是一个快照的思想,而我这时候突然又提到了“快照”,这时候脑袋中的知识点很快的将关联的mysql的MVCC涌现出来,就这样一层关联一层,错综复杂,层峦叠嶂,但也丝丝入扣,环环相连,成为一颗不断壮大的知识树...... 43 | 44 | 45 | 46 | 阶段二(学习方法之“口若悬河-刻意练习”): 上面说过了第一阶段其实已经把自己的目标定下来了,但是遇到一个很现实的问题,你所有遇到的面试其实都是一个和别人交流的过程,你必须将自己的优势完全展示出来,并且是让人能听的简单易懂的方式,所以第二阶段的“刻意练习”分为两部分,第一部分我会将自己学到的知识点刻意拿出来和别人讨论,比如同事,比如在一些技术群,这样不仅在交流的过程中,你会发现自己哪里说的不够严谨,不够规整,不够深入,或者说别人也会依据你所说的提出一些问题,如果你不能游刃有余的回答出来,说明这个知识点掌握的还是不够好; 47 | 48 | 第二部分其实就是“技术分享”,在团队中技术分享,或者参加线下的技术分享,这里有个好处就是,当你进行技术分享的时候,你会带着压力,你必须不仅仅是分享这个知识点,他相关的点,他横向涉及的点,以及你分享过程中别人会提问你的点,还有就是如果将这个知识点讲给一点都没接触过这个知识点的人等等,其实分享一次挑战难度会非常的大,你必须花十倍百倍的精力去准备一场面试分享,其实后来面试的时候发现,这其实也算一个加分项,你说你进行过技术分享,有时候别人会让你聊聊,甚至让你再进行分享一次,别人会觉得你是一个热爱技术,愿意进行交流的人...... 49 | 50 | 51 | 52 | **Tips:** 一些技术氛围比较好的技术群里面大家会经常讨论一些生产上遇到的或者面试中遇到的问题,这时候千万不要视而不见,参与进去,说出自己的想法,并且和别人讨论,让被人给你进行纠正等等,时间长了也是一种变相锻炼的过程 53 | 54 | 55 | 56 | 阶段三(学习方法之“兵临城下-三轮决战”):我是裸辞,所以各位朋友们,搞清楚自己目前的状态,好好分析自己的状态,我分析了一下自己的情况:1.没有经济压力 2.回家去家里附近的图书馆复习准备一个月,只管复习不用去考虑别的什么杂事,每天起很早开车去图书馆占座,八点到图书馆的时候,一层就已经排了将近200个人的队伍,等八点半正式开门,我们就蜂拥而上,冲进去抢占座位,30天时间只有两天没有抢到座位,又返回家中去学习,剩下的28天几乎是风雨无阻,雷打不动的从早上八点到晚上七点时间学习,当然目标很重要,第一天就把这一个月内要复习的东西全部罗列好,每天按计划进行,我上面说的三轮是这样子,我离职之前审视了一下自己,发现我整个知识栈体系相对于外面问的东西有几个薄弱环节,我就专门针对性的去复习,举个例子,JVM比较薄弱,我就第二遍刷了周志明的书,然后同时每天跟着救火大队长的JVM专栏,并且我会主动去把所有同学提出的问题都在评论区给予他们回答,来锻炼自己,然后回去知乎上把所有R大关于JVM的回答都浏览一遍,至此为止JVM常见,常用的在我这里都能解答。第二轮是把自己简历上每一个点吃透,项目吃透,能把机器配置到流量大小,每一个应用层的流量,极限的一些基本参数都得记住,同时每天挑一个重点面试题看,然后能表述出来。第三轮也就是最后一轮,自我面试,假设自己是面试官看到你的简历会问什么,越详细越好,找你的简历的每一个漏洞去问(下面我会详细的分析你该如何准备你的简历,你的项目,你所写的知识点),然后我之前收集的很多整轮面试题,我会专门挑一个小时时间,自我进行回答复述,算是自我演练面试的过程,事后进行复盘...... 57 | 58 | 59 | 60 | **总结学习方法:**好,我的经历和经验其实还有很多东西,但是文章毕竟只是文章,他无法去描述你所有的奋斗的过程。至此我要总结一下学习方法,这时候很多同学可能会说,你说的这些方法我都知道呀,我还是不行,这其实并不是鸡汤:你即使知道所有道理也过不好这一生,而是你能坐的下冷板凳,静下心来,不急不躁,毕竟改变最好的时间就是你看完整篇文章之后开始. 61 | 62 | 1.构建好自己的知识体系,空间联想,不断重复,记忆曲线 63 | 64 | 2.刻意练习,多交流,多接受不同的意见,拓展思路 65 | 66 | 3.明白自己哪一个环节薄弱,专项针对,比如我redis弱,那我这一段时间就狠抓redis,不要又看redis,又看zk,又学netty的 67 | 68 | 69 | 70 | **重点:**下面是你该如何准备你的项目?(这里我就不说单一的技术栈,知识点,这并没有什么意义,网上都能找到,很多面经都会有很多题目,这也是我整篇文章没有任何一道面试题的原因,而且现在慢慢的已经逐渐不太会问你单一的技术点了,都是结合生产实际,要你对你自己做的项目知根知底),下面我以问答的方式让你来准备你的项目。 71 | 72 | 1. 首先,你要简单能描述出你的项目 73 | 74 | (市场切入点是什么?怎么盈利?业务模式是什么?上下游的业务有了解么?这种业务模式你觉得会有什么问题?你的项目解决了什么问题?能否在墙上画出你的项目结构图,架构图) 75 | 76 | **Tips:**软件工程很重要,我是被问到画出ER图,系统流程图,泳道图等等 77 | 78 | (项目的日活?GMV?每天的访问量?一年营业额?合作商家大概多少?租户有多少?目前数据量多大?系统部署了多少台,机器是什么配置?每一层的流量大概是多少?比如打到mysql的流量有多大,mq的流量,redis的流量?线上的超时时间怎么配置的?重试怎么配置?幂等怎么做?db和cache在一致性怎么做?jvm垃圾收集用的什么算法?老年代新生代给了多大?有什么问题么?cms和g1的区别?线上为什么不用g1?目前的架构模型对于现有业务量有什么可优化的?有什么难点?以后如何扩容?数据库表的设计是怎么样的?违反了三范式会有什么问题,有什么好处?当前的数据库表设计有什么问题,有什么可优化的点?项目中有你负责模块的设计模式如何运用?能否画出这个设计模式的uml图?相比之下这种设计模式和另一种有什么区别?有什么优缺点?) 79 | 80 | tips:我这里没有细化任何一个框架知识点的问题,是因为一个知识点比如分库分表都会带来大量的问题,我这里着重整体的项目问题,这里起码要准备三个项目的亮点难点,尤其是大厂面试官,很挑剔,那种比较一般的难点就不要拿出来说了,反而会降分 81 | 82 | 83 | 84 | 2. 第二,对于你项目中运用技术的思考,架构选型,为什么选它,架构设计,为什么这么设计?拆分微服务的理由?为什么XX模块和XX模块没有拆开,或者拆开了?举个例子zk和eureka作为注册中心,你们选型用哪一种?针对你们业务量,和服务实例的数量应该选择哪一种?这两种模型不同,为什么说一个偏向于AP一个偏向于CP?会带来什么问题?引入新框架是否会带来新的挑战?出了问题是否能有人hold住?团队成员开发能否快速上手这个框架? 85 | 86 | 如果在面试官问你一个技术,你可以将为什么用它?你是怎么用的?用它有什么优点,缺点?备份方案?这种方式表达出来,别人会觉得你是有思考的,你相比其他竞争者是有优势的。 87 | 88 | 89 | 90 | 3. 常见问题的梳理 91 | 92 | 这部分就是很常见,外面也会必问的问题,很简单,比如spring相关的aop,ioc,mybatis相关的,dubbo,zk,netty,springcloud,springboot的starter,mq的,线程池,hashmap,并发相关的集合,CAS,volatile,synchronized(1.6之后的锁升级),原子类,网络的NIO,类加载过程,三次握手四次握手,一次http请求的过程,这些常见的问题起码应该烂熟于心,当然有些东西说的越深入越好,最好能涉及到硬件,震慑到面试官,比如每次我聊到CAS,会提到底层的MESI协议,会聊到高速缓存的结构,会聊到Modified,Exclusive,Shared,Invalid四种状态如何切换,会聊到缓存加锁之后引入的一些写缓冲器,和无效队列问题,再提到release,acquire,store,load屏障分别做了什么,怎么保证可见性,有序性等等等,所以聊到你擅长的,你就狠狠的喷。 93 | 94 | 95 | 96 | 4. 稍微深入的题目拓展 97 | 98 | 平常做一些稍微难的题目其实会拔高自己的思考的能力,我来举几个例子,我以AQS为例子 99 | 100 | 1.addWaiter和enq方法中新增一个节点为什么先将新节点的prev置为tail,再尝试cas,而不是cas成功之后来构造节点之间的双向链接? 101 | 102 | 2.唤醒节点为什么从tail往前遍历? 103 | 104 | 3.unparkSuccessor有新线程争锁是否有漏洞? 105 | 106 | 4.aqs如何保证队列活跃? 107 | 108 | 5.Propagate状态的节点存在的意义? 109 | 110 | 等等等 111 | 112 | 113 | 114 | 5. 自己简历上写的每一个知识点要吃的透透的,并且能够独立描述5min,还是要把别人能讲懂的那种 115 | 116 | 117 | 118 | 6. 自我攻防战,每天最好能针对你的项目找漏洞,再找到解决方案,类似“左右互搏”,有些游戏大神不都这样,每天可能只打两三把游戏,但是水平很高,是因为别人在脑海中打游戏,演练每一种情况,每一个细节,同时结合一些网上的面经,进行模拟考试,自我演练。 119 | 120 | 121 | 122 | 时间过得很快,文章已经接近了尾声,在复习和快速成长的一年中认识到了很多大佬,大家也对我都进行了很多的帮助,这里要十分感谢他们,也有很多朋友催我出一份面经,目前能想到的只有这么多,后续会继续补充,希望这篇文章对大家有帮助。 -------------------------------------------------------------------------------- /大厂面经/Interview Exp6.md: -------------------------------------------------------------------------------- 1 | # 一个小女子的大厂面经 2 | > 该文引用自:【公众号:Bella的技术轮子】,目前就职阿里巴巴 3 | 4 | ### 自序 5 | 6 | 这次面试的公司有一点点多,主要是因为毕业后前两份工作找的都很草率,这次换工作就想着,emm,毕业三年了,该找个工作好好沉淀几年了。 7 | 8 | 先说下这次面试的结果吧: 9 | 10 | - 到hr 面的: 11 | 阿里、美团、滴滴、金山云、每日一淘、火币、宜信、旺店通、黄包车、linkedMe 12 | 13 | - 其他: 14 | 15 | - - 小米(四轮技术面,大概4个小时的样子,大数据部门,不知道是不是四面的负责人嫌弃我木有大数据的经验,我确实木有哈) 16 | - 京东(电话面试一轮+现场两轮,面试完快中午一点了,说是让我先回家,后面让hr 电话联系我,一周后一面的面试官问我还考虑京东不,如果考虑的话,就进行后续,对不起,我已经不考虑了,希望以后有机会再合作,所以没有后续了) 17 | - 头条(二面完gg,我的算法确实菜哈,然后leetcode又只刷过10道题,去面头条,确实有些作死的节奏,实在是对不起帮我内推的石冲大佬) 18 | - 爱奇艺(电话面试一轮+现场两轮,到技术终面了,这个怪我,面试官也一直很忙,然后我俩就互相一直改面试时间,最后定的那个面试时间我还迟到了一个小时,还是时间到了才给hr 打电话说一个小时后才能到,虽然我知道这样做非常不好,但是当时情况比较复杂,自己根本忙不过来,一直在面试,也没有办法中途给hr 打电话说一下。一天面两家,两家离的还比较远的小伙伴吸取一下教训。我本来是想约第二天下午的,hr 就想当天,结果就晚上7:40开始二面了,面到9点,然后木有然后了) 19 | - 有赞(电话面试一轮+现场两轮,到技术终面了,面试官“base考虑杭州吗”,我“啊,你们北京不是也需要人吗,最好北京哈,杭州暂时不考虑”,然后木有然后了,哈哈。后面面阿里的时候我就自己打脸了,面试官“base杭州考虑吗”,我“面过阿里我就去杭州,面不过我就在北京”。爱,就要大胆的说出来。) 20 | 21 | 这次面试基本都是三~四轮技术面,很多都是每一轮都有至少一道算法题,所以准备换工作的小伙伴,算法可以搞起来了哈,leetcode easy和medium 难度的就ok了,当然如果你也要刷hard 难度的题,是更好的哈。我作为一名只刷过10道leetcode的渣渣,表示以后要好好刷leetcode了,拯救一下自己的智商。准备面头条的小伙伴,那就medium 和 hard难度的搞起来吧。你们加油,我就不想了。 22 | 23 | 群里有很多小伙伴怀疑我是985、211或者研究生毕业,都不是的哈,渣本(但是我还是很爱我的母校的),16年毕业,我一个妹子都可以做到的,你们更可以做到,所以相信自己,去努力就好了。这篇文章【原创公众号:Bella的技术轮子】主要是记录一下自己的面试经历,分享一些群里小伙伴们都很关注的面试题,然后文章末尾我会推荐一些书,完全免费推荐的哈,我个人感觉不错的,可以提升技术的,当然面试中也会对你有特别大的帮助。阿里的面试题不会分享哈,这次主要分享tmdj、以及其他公司的一些面试题,把我分享的这些面试题都掌握了,对想去面阿里的小伙伴的帮助也是非常非常大的。**当然,面试题只是起一个查漏补缺的作用,并不是让你直接去整理答案,去背答案的哈。一个合格的面试官,是会针对你的简历去问的,即每个人的面试题都是不一样的。** 24 | 25 | ### 头条 26 | 27 | 二轮技术面,17:00~20:25,晚饭时间hr 小姐姐还特贴心的带我体验了一把传说中的头条餐厅,不超过半小时 28 | 29 | 1. 聊项目,画项目架构图,画一个用户从发起请求 到接收到响应 中间经过哪些服务 每个服务做什么事情 的流程图 30 | 31 | 2. 讲项目中的难点、挑战,你是如何解决的 32 | 33 | 3. redis 中有几种类型 & 各自底层怎么实现的 & 项目中哪个地方用了什么类型,怎么使用的 34 | 35 | 4. redis如何实现分布式锁,zk如何实现分布式锁,两者的区别。如果service还没执行完,分布式锁在redis中已经过期了,怎么解决这种问题 36 | 37 | 5. synchronized底层实现,加在方法上和加在同步代码块中编译后的区别、类锁、对象锁 38 | 39 | 6. 锁升级的过程 40 | 41 | 7. java运行时区域 及 各个区域的作用、对GC的了解、java内存模型 及 为什么要这么设计 42 | 43 | 8. 对索引的理解,组合索引,索引的最佳实践 44 | 45 | 9. countDownLatch用过没有,在项目中如何使用的,对aqs 的了解 46 | 47 | 10. 写生产者消费者问题,考虑高并发的情况,可以使用Java 类库,白纸写代码 48 | 49 | 11. 如下图所示 50 | 51 | ![img](https://tva1.sinaimg.cn/large/006tNbRwly1gaf3r3kkw5j30ax0a474i.jpg) 52 | 53 | 12. 设计一个发号器,考虑集群和高并发的情况,要求发号器生成的id是递增趋势,通过id可以区分出来是今天生成的id还是昨天生成的id,但是生成的id中不能直接带有日期,要具有一定的混淆功能,白纸写代码 54 | 55 | 13. 一个二位数组,每个元素都可以往上下左右四个方向走,寻找最长递增路径。如下图所示,最长递增路径即红色字体路径。白纸写代码。 56 | 57 | ![img](https://tva1.sinaimg.cn/large/006tNbRwly1gaf3r7a51nj308b049mx5.jpg) 58 | 59 | ### 美团 60 | 61 | 电话面试(40分钟)+现场三轮技术面试(3.5小时)+hrbp面试(30分钟) 62 | 63 | 1. 数据库和缓存的一致性问题。先更新数据库,再更新缓存,若更新完数据库了,还没有更新缓存,此时有请求过来了,访问到了缓存中的数据,怎么办? 64 | 65 | 2. 聚簇索引/非聚簇索引,mysql索引底层实现,为什么不用B-tree,为什么不用hash,叶子结点存放的是数据还是指向数据的内存地址,使用索引需要注意的几个地方 66 | 67 | 3. mysql默认的事务隔离级别,mvcc,rr怎么实现的,rc如何实现的 68 | 69 | 4. mysql间隙锁有没有了解,死锁有没有了解,写一段会造成死锁的sql语句,死锁发生了如何解决,mysql有没有提供什么机制去解决死锁 70 | 71 | 5. 谈下对GC的了解,何为垃圾,有哪些GC算法,有哪些垃圾回收器,cms和g1的区别,emm,还有一个直击灵魂的问题,看过cms的源码吗,笑cry 72 | 73 | 6. 有没有排查过线上oom的问题,如何排查的 74 | 75 | 7. 有没有使用过jvm自带的工具,如何使用的 76 | 77 | 8. 假设有下图所示的一个full gc 的图,纵向是内存使用情况,横向是时间,你如何排查这个full gc的问题,怎么去解决你说出来的这些问题 78 | 79 | ![image-20191213093127572](https://tva1.sinaimg.cn/large/006tNbRwly1gaf3rby3pkj30i407sglt.jpg) 80 | 81 | 9. 说说对java中集合类的理解,项目中用过哪些,哪个地方用的,如何使用的 82 | 83 | 10. 对CAS的理解,CAS带来的问题,如何解决这些问题 84 | 85 | 11. volatile底层、synchronized底层、锁升级的过程、MESI 86 | 87 | 12. ehcache支持哪些缓存 88 | 89 | 13. juc有研究没有,讲一讲 90 | 91 | 14. 聊项目,画项目架构图,画一个用户从发起请求 到接收到响应 中间经过哪些服务 每个服务做什么事情 的流程图 92 | 93 | 15. 讲项目中的难点、挑战,如何解决的,项目这一块会问的特别细 94 | 95 | 16. 如何保证RocketMQ 消息的顺序性,如何解决重复消费问题 96 | 97 | 17. 项目中如何保证接口的幂等操作 98 | 99 | 18. 讲一讲对redis 的了解,项目中如何使用的,哪个地方使用的,为什么要使用 100 | 101 | 19. 哨兵机制、redis两种备份方式的区别,项目中用的哪种,为什么 102 | 103 | 20. 讲一讲对分布式锁的了解 104 | 105 | 21. 项目中系统监控怎么做的 106 | 107 | 22. 如何理解Spring中的AOP 和 IOC,以及DI,读过Spring源码没有 108 | 109 | 23. 读过MyBatis源码没有 110 | 111 | 24. 说一个你了解最多的框架,说出你的理解 112 | 113 | 25. 如何理解分布式事务,为什么会出现这个问题,如何去解决,了解哪些分布式事务中间件 114 | 115 | 26. 聊一聊对分库分表的理解 116 | 117 | 27. hystrix功能 & 在项目中怎么使用的 & hystrix 怎么检测断路器是否要开启/关闭 & hystrix 实现原理,除hystrix之外的其他熔断限流中间件有了解没有,了解多少说多少 118 | 119 | 28. dubbo有了解没有 120 | 121 | 29. 怎么理解java 中和 mysql 中的乐观锁、悲观锁 122 | 123 | 30. 一致性hash 124 | 125 | ### 滴滴 126 | 127 | 现场三轮技术面试+一轮hrbp面(4小时5分钟) 128 | 129 | 1. 聊项目,画项目架构图,画一个用户从发起请求 到接收到响应 中间经过哪些服务 每个服务做什么事情 的流程图,讲数据库设计 130 | 2. 处理过线上oom问题没有,如何处理的 131 | 3. 遇到过线上服务器cpu飙高的情况没有,如何处理的 132 | 4. 线上有没有遇到其他问题,如何处理的 133 | 5. 对线程池的理解,项目中哪个地方使用了,如何使用的,用的Excutor框架中的哪个实现类,为什么用这个 134 | 6. 对CAS的理解,CAS带来的问题,如何解决这些问题 135 | 7. volatile底层、synchronized底层、锁升级的过程、MESI 136 | 8. 对mysql索引的理解、对组合索引的理解、索引的最佳实践 137 | 9. 分布式锁的实现、对比redis分布式锁 & zk分布式锁 138 | 10. 唯一id如何实现的,snowflake实现原理,snowflake有哪些问题,如何避免根据订单号可以推算出今天的订单量 139 | 11. 如果线上一个功能是用栈结构实现的,使用过程中要注意哪些问题,为什么 140 | 12. 怎么理解线程安全 141 | 13. 怎么理解接口幂等,项目中如何保证的接口幂等 142 | 14. 怎么理解微服务,服务如何划分,可以从哪几个方面去划分,为什么这样划分,微服务带来了哪些好处,哪些坏处,如何看待这个问题 143 | 15. 如何理解网关,网关带来的好处和坏处,如何解决 144 | 16. hystrix功能 & 在项目中怎么使用的 & hystrix 怎么检测断路器是否要开启/关闭 & hystrix 实现原理 145 | 17. 怎么理解命令模式和观察者模式,手写一个观察者模式或者命令模式的代码,策略模式也行 146 | 18. 掌握哪些设计模式,常用哪些,项目中如何使用的,为什么用这个,不用那个,手写一个线程安全的单例模式 147 | 19. 如何设计一个秒杀系统 148 | 20. 如果我现在就是要实现每秒10w请求,不能熔断限流,如何去设计 149 | 21. 假设现在双十一零点,大量下单请求,如何对这些订单进行分库分表,为什么 150 | 22. 服务A调用服务B中一个接口,服务B调用服务C中一个接口,如何实现若服务B响应服务A成功,则服务C一定响应服务B成功,需要考虑系统性能问题 151 | 23. 递归使用中有什么需要注意的地方,递归写法一般可以用什么去替换 152 | 24. 有两个表,table a,table b,写sql查询出仅在table a中的数据、仅在table b中的数据、既在table a 又在table b 中的数据 153 | 25. spring 源码有了解没有 154 | 26. myBatis源码有了解没有 155 | 27. mysql事务隔离级别、mvcc 156 | 157 | 我:既然现在很多业务线都是Go了,有没有考虑把剩余的业务线也转成Go呀? 158 | 面试官:我认为,语言只是工具,语言不应该是影响开发的一个因素吧。 159 | 面试官说的很有道理。 160 | 161 | ### 京东 162 | 163 | 电话面试(30分钟)+现场两轮技术面试(1小时40分钟),面完12:50,说让我先回来,后续hr 电话和我联系,一周后一面的面试官问我还考虑京东吗,对不起,已经不考虑了,希望以后有机会再合作 164 | 165 | 1. 一个final修饰的属性,定义的时候没有初始化,在无参构造函数中初始化,可以吗,为什么 166 | 2. 说说对java中集合类的理解,项目中用过哪些,哪个地方用的,如何使用的,为什么不用其他的集合类 167 | 3. hashMap,concurrentHashMap底层实现, 168 | 4. list删除是怎么实现的,遍历的时候可以删除吗,为什么 169 | 5. redis中有哪些数据结构,了解过其底层怎么实现的吗,和java中相似的数据结构的对比 170 | 6. redis是单线程的还是多线程的,为什么这么快 171 | 7. redis hash中某个key过大,变为String类型的大key,怎么处理,使用中如何避免出现这种问题 172 | 8. 设计模式在项目中哪个地方用到了,怎么使用的,能不能画一个你熟悉的设计模式的UML图,手写单例模式,手写静态内部类实现的单例模式 173 | 9. 讲一讲mysql索引,实际工作中,哪些场景用了b+tree索引,哪些场景用了hash索引 174 | 10. explain 可以看到哪些信息,什么信息说明什么,explain的结果列讲一下 175 | 11. Spring源码看过没有,会多少讲多少 176 | 12. MyBatis源码看过没有,会多少讲多少 177 | 13. cas,cas的缺点,如何解决 178 | 14. aqs,countDownLatch如何实现 179 | 15. 线程池如何实现,核心线程数和最大线程数设置成多少,为什么这么设置,项目中哪个地方使用了线程池,使用时需要注意什么 180 | 16. mysql事务隔离级别,幻读,脏读,项目中用什么事务隔离级别,为什么 181 | 17. volatile底层原理、synchronized实现机制, 182 | 18. 对XA、TCC的理解,了解哪些分布式事务框架,有什么缺点 183 | 19. feign 和 dubbo,了解多少说多少 184 | 20. eureka 和 zookeeper,了解多少说多少 185 | 21. hystrix 和 sentinel,了解多少说多少 186 | 22. Spring cloud alibaba,了解多少说多少 187 | 23. 对分库分表、读写分离的了解,了解多少说多少 188 | 24. 画一下java 线程几个状态 及 状态之间互相转换的图 189 | 25. 聊项目,画项目架构图,画一个用户从发起请求 到接收到响应 中间经过哪些服务 每个服务做什么事情 的流程图,讲数据库设计 具体到部分表中有哪些字段【原创公众号:Bella的技术轮子】 190 | 26. emm 我们部门体量比较大,可能需要加班,到凌晨两三点的那种,也可能通宵,通宵是大促期间,你能接受吗 191 | 27. emm 也会加班到十点,这个不是大促期间,但也不是每天,非常态情况,你能接受吗,你在哪里住,过来要多久,有男朋友吗 192 | 一起去吃午饭吧,我们这边有员工餐厅,不了不了,我回家吃饭吧 193 | 194 | 下面是面试tmdj 之外的公司中遇到的一些问题哈,tmdj 中已经被问到的就不再重复写了,只写一下个别公司中我还记得的面试题 195 | 196 | ### others 197 | 198 | **火币**: 199 | 四轮技术面试+一轮hr 面试(4小时),后来hr 小姐姐和我说,她们正常是两轮技术面试,因为技术面试完面试官一直没有找到她,然后,emm,就又来了一轮技术面试,又来了一轮技术面试,笑cry 200 | 201 | 1. kafka 如何保证消息顺序消费、在consumer group 中新增一个consumer 会提高消费消息的速度吗、那如果我想提高消息消费的速度,我要怎么办 202 | 2. redis几种数据结构 及 底层,项目中如何使用的redis 203 | 3. 哨兵机制、选举算法 204 | 4. 一致性hash 205 | 5. redis是单线程的还是多线程的,为什么速度这么快 206 | 6. 多路复用的几种方式以及区别 207 | 7. 对线程池的理解,在项目中如何使用的,多个线程之间如何共享数据,多个进程之间如何共享数据 208 | 8. hashMap、concurrentHashMap的区别 及 底层实现、hashMap和hashTable 的区别 209 | 9. 什么是红黑树,什么是b-tree,为什么hashMap中用红黑树不用其他树 210 | 10. 对mysql 索引的理解,为什么mysql索引中用b+tree,不用b-tree 或者其他树,为什么不用hash 索引 211 | 11. 数据库和缓存的双写一致性问题 212 | 213 | **每日一淘**: 214 | 三轮技术面试+一轮hrbp 面 215 | 216 | 1. 用过哪些Object类的方法,如何使用的 217 | 2. java如何实现序列化的,Serialization底层如何实现的 218 | 3. countDownLatch如何实现的 219 | 4. 项目中监控报警机制如何做的,说说你的了解 220 | 5. 线上服务器cpu飙高,如何处理这个问题 221 | 6. 服务A调用服务B,用户请求服务A,发现返回较慢,如何定位这个问题 222 | 7. TIME_WAIT是什么状态还记得吗,什么情况下网络会出现这个状态 223 | 224 | **linkedMe**: 225 | 二轮技术面试+一轮hr面试 226 | 1.内核态 和 用户态、cas 和 sout 哪个用到了内核态和用户态的切换 227 | 2.哪些典型的应用用的是udp 228 | 3.线程池有了解吗,项目中如何使用的 229 | 4.计算密集型/IO密集型 任务 分别如何设置线程池的核心线程数和最大线程数,为什么这么设置 230 | 5.假如我下午5点要和5个人一起开会,但是这5个人现在都出去了,不在公司,但是今天会回来,问,我如何开这场会,用java 并发方面的知识回答 231 | 232 | **旺店通**: 233 | 5小时+,中午我还木有吃饭,下午面试时候真是饿的要死,而且下午脑细胞死了好多好多 234 | 235 | - 先机试(50分钟时间,三选二,不联网,明确告知机试不通过没有后续) 236 | - 一面给面试官讲一下自己机试题的思路,面试官运行看结果,然后问了几个问题(什么是B-tree,什么是B+tree之类的) 237 | - 笔试(10道选择题+2道数据库+2道算法题,30分钟) 238 | - 二面给面试官讲自己的机试题的思路,面试官运行看结果,然后给面试官讲笔试题,一道一道讲为什么这么写,过程中面试官可能会改题,然后问你怎么解决修改后的题,然后又问了几个题 239 | - 三面开始正常面试,但不是看简历问,一部分是简历上的,一部分是看面试官心情 240 | - hr面 241 | 242 | 当场给了offer,但是啊,从他家出来的时候的想法就是,早知道下午这个样子,不如中午吃个午饭,回家好好睡一觉 243 | 想去他家的小伙伴就好好写代码吧,多看java 中一些方法的实现,因为机试的题目都要求不能用java 中提供的方法,要自己写,然后还要好好准备算法 244 | 245 | ### 算法题 246 | 247 | 1. [1,1,2,2,3,4,4,5,5,5] 找出不重复的元素(黄包车) 248 | 249 | 2. 反转链表,要求时间复杂度O(N),空间复杂度O(1) (火币) 250 | 251 | 3. 非递归实现斐波那契数列 (爱奇艺) 252 | 253 | 4. 这一周股市价格为[2,6,1,4,8],求哪一天买入哪一天卖出,可获得最大收益,最大收益为多少 (爱奇艺) 254 | 255 | 5. 按照箭头方向查找二叉树 (金山云) 256 | 257 | ![image-20191213093225461](https://tva1.sinaimg.cn/large/006tNbRwly1gaf3rii4t6j30g70fhdgd.jpg) 258 | 259 | 6. 表a b c之间用id关联,求阴影部分的数据 (金山云)【原创公众号:Bella的技术轮子】 260 | 261 | ![image-20191213093243414](https://tva1.sinaimg.cn/large/006tNbRwly1gaf3rn9lbdj30hc08u3yv.jpg) 262 | 263 | 7. 一个整形无序数组,里面三个数只和等于一个目标值,求这三个数 (小米) 264 | 265 | 8. 链表问题 (小米) 266 | 267 | ![image-20191213093257647](https://tva1.sinaimg.cn/large/006tNbRwly1gaf3rr0yegj30h803i0st.jpg) 268 | 269 | 9. 扑克牌问题 (小米) 270 | 有十张扑克牌,从上面开始抽,抽出一张放桌子上,然后再抽出一张放扑克牌的最下面,这样循环往复的操作,直到手里的牌都没有了。这时,桌子上牌的顺序正好是1 2 3 4 5 6 7 8 9 10。要求写代码求出原顺序 271 | 272 | 10. 手写大顶堆 (linkedMe) 273 | 274 | 11. 手写LRU 算法 (火币) 275 | 276 | 12. 字符串相加 (滴滴) 277 | 两个数字类型的字符串,直接转int或者double肯定都放不下,然后求这两个数的和,返回值还是字符串,15分钟时间,要求无bug 278 | 279 | 13. 寻找目标值位置 (滴滴) 280 | 有一个二维数组,数组横向有序,纵向有序,求目标值的位置,10分钟时间 281 | 282 | 14. 求字符串“efabcbaefehiabcba”中最长的回文数,不去重(美团) 283 | 284 | 15. 反转int类型的值x,不要借用String,只用int 即可。&& 针对该程序,写出其应有的测试用例 (美团) 285 | 286 | 16. top K 问题(每日一淘) 287 | 288 | ### HR面 289 | 290 | 真诚待人,以真心换真心,不要弄虚作假,HR 问什么问题,如实回答即可。在回拒offer 时候,也请好好说话。 291 | 292 | ### tips 293 | 294 | 其实面试过程中,你是可以感受到哪些面试官是真的很欣赏你,哪些只是想找一个可以干活的人的,最后一定要去一个欣赏你的面试官那里,因为待遇真的会不一样(假装我体验过只是想找我干活的leader哈,很感激以前遇到的每一位leader 都很欣赏我,给我我想要的空间去做自己想做的事情,真的非常感谢你们)。 295 | 296 | 嗯,免费安利环节到了,学不了吃亏学不了上当哈 297 | 298 | 《深入理解Java虚拟机》《Java并发编程的艺术》《Java并发编程实战》《MySQL技术内幕 InnoDB存储引擎》《Redis设计与实现》《JVM G1源码分析和调优》《重新定义Spring Cloud实战》《Redis深度历险:核心原理与应用实践》《Spring技术内幕》《myBatis技术内幕》 299 | 《深入拆解Java虚拟机》等等等等,个人感觉极客时间和掘金小册还是有很多非常不错的专栏的,emm,不装了,上面这些书/专栏,有些我自己都木有看完呢,溜了溜了 300 | 301 | 亲爱的读者,面经已出,**如果觉得对自己有帮助,记得点“在看”哦,欢迎关注、收藏、转发、在看。** 302 | 不要只做马来人,记得和Bella 酱一起看书学习呀,一起成为更好的自己,想要的自己~ 303 | 304 | 有任何问题都可以在公众号后台给我留言或者加我微信好友(公众号菜单栏有Bella酱的联系方式)留言哦,不保证消息秒回,但是看到了一定会回复的哦~ -------------------------------------------------------------------------------- /大厂面经/Interview Exp7.md: -------------------------------------------------------------------------------- 1 | # 一年工作经验阿里三面 2 | 最近原来实习时候的Boss联系我,说他跳槽到了阿里,问我有没有兴趣面一个Java后台开发岗位。 3 | 4 | 考虑到我只工作了一年,现在去阿里肯定要降薪,因此也没有太强烈的意愿。但出于提升自我的角度考虑,参加了面试。 5 | 6 | 7 | 8 | #### **一面(电话面试一小时)** 9 | 10 | 首先做一个简单的自我介绍,主要包括学校经历和工作经历。我工作经历只有一年,大部分时间都是在做产品设计和UI/UX Design,因此隔着电话都能感受到面试官的shock。 11 | 12 | 13 | 14 | - Java基础。自动拆装箱如何实现,String,StringBuffer,StringBuilder的异同以及各自的实现。 15 | - JVM基础。JVM的内存模型,常见的垃圾回收算法。 16 | - 事务ACID,编程时如何保证事务,分布式情况下如何保证事务。 17 | - 由于分布式相关场景我没有接触过,因此面试官一直诱导我去设计实现一个分布式事务。 18 | - 数据库乐观锁和悲观锁。如何实现一个乐观锁。 19 | - 消息队列使用场景,Kafka的架构以及原理。 20 | - 什么是restful api,和rpc调用有什么区别。 21 | - 单例的几种写法。volatile关键字有什么作用。 22 | 23 | 24 | 25 | 以上就是电话面试的大体问题,面试完之后,又发给我三道算法题目,要求我一小时内完成,下面是三道算法题: 26 | 27 | - 翻转一个long类型数字。例如输入123456L,输出654321L。- Leetcode翻转integer的变种。考察能否正确处理溢出的情况。 28 | - 输入一个double,要求返回与它最接近的.49或.99的数字。例如12.77返回12.99,11.02返回10.99,12.61返回12.49。 29 | - 有三个线程ABC分别向一个数组中写入a,l,i,要求最终的写入结果形如alialiali...写入次数由A线程决定。 30 | 31 | 32 | 33 | 这三道题目做的还比较顺利,第二天面试官又联系我阐述一下第一题和第三题的思路,然后通知我可以参加下一轮了。 34 | 35 | 36 | 37 | #### **二面(电话面试一小时)** 38 | 39 | 二面主要考察了一些开放式的问题。 40 | 41 | - 首先还是自我介绍。主要是工作后的经历。介绍一下工作一年所在team的产品,我承担了什么职责。 42 | - 开放式问题。如何设计一个rpc框架。 43 | - 开放式问题。如何设计一个服务注册中心。 44 | - 集合类源码。HashMap是如何实现的,扩容的过程,为什么要扩容为2倍。HashMap中的链表替换为数组可以吗?时间复杂度相同吗? 45 | - 集合类源码。线程安全的HashMap是什么?(HashTable和ConcurrentHashMap)ConcurrentHashMap是如何实现的?(Java7分段锁和Java8的CAS+Lock)和HashTable相比有什么优势? 46 | - 红黑树的结构,时间复杂度是多少,如何计算的 47 | - 什么是CAS操作,如何实现一个自定义锁 48 | - 数据库设计。有一张很大的order表,如何设计能够提升查询效率(同时满足根据买家id和卖家id查询)? 49 | 50 | 51 | 52 | 二面也同样是一小时左右,面试过程还算顺利。只是当时我在厦门鼓浪屿的一家小餐馆吃晚饭,周围的嘈杂和闷热使我很烦躁,感觉面试官态度有些傲慢…… 53 | 54 | ps.一面二面结束后面试官都各种暗示我要疯狂加班能不能接受blabla…… 55 | 56 | 57 | 58 | #### **三面(电话面试一个半小时)** 59 | 60 | 二面结束后的第三天,就收到了现场三面的通知。然而我还在厦门旅行,因此改为了电话面试。 61 | 62 | 63 | 三面是一个大Boss,因此面试的问题都更考察一些分析问题的能力。 64 | 65 | - 介绍一下你工作一年学习到什么?所在项目的架构是什么样的?UI/UX设计有哪些规范(由于我说我学到了一些UI/UX设计方法,因此面试官就问了)? 66 | - 数据隔离级别,脏读幻读。 67 | - 线程池原理。 68 | - Synchronized的实现,锁的升级过程。 69 | - K8s的作用,K8s的底层架构。 70 | - 对我业余时间做的一些项目做了介绍。 71 | - 你觉得加入阿里你能给阿里带来什么? 72 | - 进入阿里你需要忍受很多困难,需要迎难而上,如果绩效考评拿到差评,你会怎么办? 73 | 74 | 75 | 76 | 三面总的来说也还算顺利,面试官也算和蔼。 77 | 78 | #### 79 | 80 | #### **总结** 81 | 82 | 整个流程从一面到三面结束大约持续了10天左右。总的来说,问题都是预期范围内的,虽然面试过程中问到了一些分布式相关问题,我都没有任何经验,这时候不要放弃,主动说出你的思路,然后在面试官的诱导下,相信你能说出属于的答案。 83 | 84 | 85 | 86 | 87 | 88 | **最后,是我总结的一些面试Java后台工程师必须要掌握的知识点。** 89 | 90 | #### **1. 集合类源码** 91 | 92 | - ArrayList:内部数据结构,数组扩容机制 93 | 94 | - LinkedList:内部数据结构,为什么使用双向链表 95 | 96 | - HashMap:内部数据结构,put方法的完整流程,扩容机制 97 | 98 | - LikedHashMap:内部数据结构,如何实现一个Cache 99 | 100 | - TreeMap:内部数据结构,时间复杂度 101 | 102 | - CurrentHashMap:内部数据结构,Java7分段锁,Java8 CAS+Synchronized 103 | 104 | 105 | 106 | #### **2. Java基础** 107 | 108 | - 自动拆装箱原理 109 | - String,StringBuffer和StringBuilder 110 | - Throwable 111 | - reader和stream 112 | - NIO 113 | 114 | #### 115 | 116 | #### **3. JVM基础** 117 | 118 | - JVM内存模型 119 | - 常见垃圾回收算法 120 | 121 | #### 122 | 123 | #### **4. 并发编程基础** 124 | 125 | - Synchronized关键字原理 126 | - wait,notify,sleep 127 | - 安全的终止线程以及线程的状态转换 128 | - 自定义Lock 129 | - 线程池原理 130 | 131 | #### 132 | 133 | #### **5. 数据库基础** 134 | 135 | - 数据库三范式,事务ACID,隔离级别,视图,索引 136 | - JPA实体状态 137 | - EntityManger 138 | 139 | #### 140 | 141 | #### **6. 网络基础** 142 | 143 | - TCP/IP 144 | 145 | 146 | 147 | #### **7. 常见设计模式** 148 | 149 | - 装饰者,模板方法,策略,工厂,状态 -------------------------------------------------------------------------------- /大厂面经/Interview Exp8.md: -------------------------------------------------------------------------------- 1 | # Google 面经分享 2 | > 该作者目前在阿里,P7 3 | 4 | 去年换工作的时候, 面试了一下 Google (这里说的是 Google 中国), 来了个 Google 面试六轮游, 结果是没通过. 🤣 现在分享下我参与面试的具体流程以及个人认为应该注意的事项, 希望对大家有所帮助. 5 | 6 | 7 | 8 | ## 个人相关背景 9 | 10 | 先介绍下自己相关背景, 985 本科, top2硕士(其实, 大公司都比较看重第一学历的). 在校期间, 科研也没啥能拿得出手的论文. 社招时, 4 年多工作经验, 面试时为大疆后端开发TL(带3~4个人而已). 11 | 12 | 13 | 14 | ## 面试流程 15 | 16 | Google 整体面试流程上基本如下: 17 | 18 | - Recruiter Prescreen → 19 | - Phone Interview (1~2 sessions) → 20 | - Onsite Interview (4~5 sessions, 1 week to receive feedback) → 21 | - Hiring Committee Review → 22 | - Offer Review → 23 | - Offer Delivery (Yippee!) 24 | 25 | 26 | 27 | 我一共经历了 1 轮电话面试, 5 轮 onsite, 如果算上前面的HR 的预筛选的话, 就是 7 轮. 28 | 29 | 30 | 31 | ## 简历投递 32 | 33 | 之前校招其实也参加过, 无奈门槛太高, 竞争压力太大, 连面试流程都木有进. 当初校招时直接网上刷题, 这个网站上其实还能看到往年的一些题目情况: *Google Code Jam*. 基本上分几轮, 每轮 top xx 的选手才有机会进入面试. 34 | 35 | 第一次换工作的时候, 其实也有找在 Google 的同学内推, 填了不少内推推荐理由呀等等, 最后简历都没过. 😿 当然, 简历没过肯定也有多种理由啦, 这个其实跟各个公司都一样. 比如人家需求是招聘 P7, 以你的工作年限经验等最多就 P6, 肯定不行; 还有比如希望是招聘机器学习等相关经验的等等, 岗位信息等不匹配也不行; 当然还有一种, 岗位描述等都相关, 确实简历没啥亮点, 太平庸, 也直接被 HR 给筛选掉了. 36 | 37 | 这次其实刚开始是没有考虑过面 Google 的, 机缘巧合在 linkedin 在有 Google 的 HR 联系, 说要不要试试 Google 的机会. 当然就抱着 “试试就试试” 的想法跟进面试流程啦. 既然要尝试, 当然还是需要认真对待, 修改简历. 防止手生, 肯定需要提前准备”刷题”的. 发简历给HR 小姐姐后, HR 小姐姐会给你一些准备材料供你参考, 这份材料还相对比较丰富, 直接会告诉你面试涉及到的知识点, 推荐书籍还有一些推荐参考的视频等.需要的小伙伴可以留言, 我整理下发给你(跟 HR 求证过, 这些资料是可以公开分享的哈). 38 | 其实, 时间有限, “刷题”准备不够, 当初预感估计面试面不下来. 不过真正走完所有面试流程, 发现其实面试题目没有想象中的**那么**难(然而, 我仍然没有过![image.gif](https://tva1.sinaimg.cn/large/007S8ZIlly1gfu5j0aee0j300100101y.jpg), 说明实力不足呀![image.gif](https://tva1.sinaimg.cn/large/007S8ZIlly1gfu5iz2ogoj300100101y.jpg)), 积极准备, 还是有希望的. 因为面试题目比较敏感, 不能直接分享原题哈, 不过我会根据我的理解, 找类似知识点和类似难度的题目分享一下. 39 | 40 | 41 | 42 | ## HR 面试 43 | 44 | 对, 第一轮就是 HR 面试, 上面流程中的 “Recruiter Prescreen”, 其实就是一些计算机相关基础的填空题和选择题. 几分钟的时间, 十几道题目. 面试过程中, 不需要给予明确的解释, 知道就是知道, 不知道就不知道. 题目可能会涉及到比如: 快排的时间复杂度是多少? 选择排序是稳定的排序算法吗? 等等之类的.这也是我参与的所有面试当中, HR 直接参与的”技术”面的. 我理解就通过这一轮面试可以用比较少的成本把一些不合适的候选人直接排除了. 当然这种方法可能不一定适用于所有公司. 45 | 46 | 47 | 48 | ## 电话面试 49 | 50 | 电话面试要求直接用 Google doc 共享写代码, 需要要求你有一个稳定的网络环境. 这轮面试我理解应该不会太难, 从我面试的经验来看也确实如此. 51 | 52 | 相比 onsite, 电话面试不能在一个很好的沟通环境下, 不能面对面和面试官进行交流. 当初我面试的一道题目和二叉树的遍历相关, 当然题目不会是直接写二叉树的先序/中序/后序/层次之类的遍历, 会有一个具体的业务场景在里边. 需要你分析这个具体的业务场景, 能够抽象出题目本质上就是 二叉树的遍历方法. 这道题目算是拿下了. 实际 coding 后, 面试官可能会根据你写的 code 去提问, 一些边界条件以及让你提优化方案. 53 | 54 | HR 小姐姐介绍的电话面试时 1-2 轮, 其实我理解, 这应该是需要看第一轮的面试官的反馈, 是否犹豫是否再安排一轮电话面试. 毕竟和 onsite 相比, 电话面试成本相对更低一些. 在线 code 其实在面试过程中, 还是蛮重要的环节. 从你 code 的细节, 包括 code style, 边界条件的判断, 哪怕是注释情况, 都能看出一些编程习惯. 我认为这个环节对于招聘一个写代码的工程师来说, 肯定是一个必不可少的环节(google 整个就搞了五六轮). 55 | 56 | 57 | 58 | ## 现场面试 59 | 60 | 电话面试通过后, HR 会很快跟你反馈沟通面试结果, 是否通过, 以及 onsite 的安排. 因为现场面试是 4-5 轮, 平均1 轮一小时的话, 需要 4-5 个小时, 其实还是蛮耗费精力的. 一般会沟通可以约 2 个半天或者 1 整天, 两个半天的好处是, 时间不会那么紧张, 前两轮后, 中途可以过几天再休整调整下再继续. 我当初就选择”快刀斩乱麻/早死早超生” 的方案直接约了 1 天时间搞定. 61 | 62 | ![img](https://tva1.sinaimg.cn/large/007S8ZIlly1gfu5j0s5l7j30ty0ngmyi.jpg) 63 | 64 | onsite 也基本上是在电脑上 coding. 你和面试官一人一个笔记本, code 时共享屏幕, 有时候题目面试官会在白板上写出. onsite 的题目, 明显就要比电话面试的题目难度高一些呢. 但实际上比我想象中的要简单些. 因为曾经想 Google 这样的公司面试恐怕连理解题目意思都要理解大半天吧. 可能也是社招的缘故, 社招整体感觉在算法的要求比校招就要低一些. 这只是我的主观感受啦. (确实自己在当面试官的过程中, 在算法这块对社招的同学预期也会低一些)我记得其中有一道题目就跟 leetcode 上的类似(再次声明不是原题, 也不 share 原题), leetcode 上那个题目应该是二维矩阵, 最短路径相关的. 用 dp 可以解决. 只不过, 一般题目会分为好几个小问题, 难度一般从易到难.同时也考察到了二叉树, 仍然围绕着二叉树的遍历进行. 需要熟知二叉树的各种遍历方式, 非递归的方法(递归比较容易, 一般不会让写这个). 在遇到二叉树相关问题的时候, 是否可以联想到二叉树的遍历上来.另外有一道系统设计的问题, “知识图谱”的概念, 围绕着”图”的相关算法, 这个要求在白板上写出设计方案和伪代码. 同时面试官会不断 push 你让你提出更优的解决方案. 有足够多的计算资源, 并行去跑, 以及具体怎么实现. 这道题目我回答的不好(当初也知道不好, 后面 HR 反馈也印证了这一点).还有一道题目, 是解决生活中的场景题目. 需要你抽象出这个问题, 用代码来解决. 一般这种题目, 就需要反复跟面试官去沟通和确认其中的场景, 怎样把业务抽象成算法. 记得之前面试 Amazon 的时候也有类似的题目(只不过当初面 Amazon 考察的是 OO Design, 而本题是具体算法实现).onsite 一共聊了 5 轮, 上午 2 轮, 下午 3 轮, 其中有两轮是英文面试(英文面试后面会说). 整体来说,工程师岗位面试会围绕如下几个方面进行(以下参考 HR 提供的面试指南): 65 | 66 | - Coding: 用熟悉的编程语言(不限)实现给定的题目. 会重点关注解题目过程中的理解和沟通能力; 67 | - 算法: 涉及到 排序/搜索/分治/动态规划/贪心/递归, 具体数据结构, 以及也有可能会涉及到 `Dijkstra` 和 `A*` 等算法, 需要会算法复杂度的分析; 68 | - 排序: 常见的排序算法, 时间/空间复杂度, 例如 快排/归并/堆排序/插入/基数排序等等; 69 | - 数据结构: 数组/连表/堆/栈/hash/数/二叉树等; 70 | - 数学: 可能会涉及到离散数学, 组合数学, 例如 N个中选k 个的方法等; 71 | - 图: 图的表达(例如矩阵/邻接表), bfs/dfs 等; 72 | - 递归: 递归和迭代的转换; 73 | - 其他: 设计和操作系统等; 74 | 75 | 以上这部分摘自 HR 提供的 `Google 工程师面试指南.pdf,文末附链接` 76 | 77 | 78 | 79 | ## 午饭 80 | 81 | 中午 HR 小姐姐会安排一个 Google 的工程师, 带你吃饭, 跟你聊天. 有任何疑问都可以跟他沟通. 不得不说, Google 的伙食还是蛮不错的. 我当初就跟小哥哥聊了下他在 Google 工作的感受. 82 | 83 | ![img](https://tva1.sinaimg.cn/large/007S8ZIlly1gfu5j19i1jj30u00mignq.jpg) 84 | 85 | 86 | 87 | ## 英文面试 88 | 89 | 英文面试, 单独拿出来说一下. 建议还是提前准备, 练习一下基本的口语. 不要因为面试过程中, 突然让你只用英语沟通, 让气氛变得紧张起来, 导致发挥不好. 自我介绍之类的肯定你可以提前准备, 然后就是你可以尝试比如拿其中的题目自己模拟一下面试场景. 主要是可能需要提前熟悉一下基本的计算机相关词汇, 不要到时候想表达确表达不出.整体来说, Google 的面试确实很难, 但确实也没我想象中的那么难. 但要求确实是很高的, 基本上一些边界 case 等也都是在考察范围内的. onsite 面试完后, 在第二天, 我就得到结果通知, 面试没通过. 事实来看没通过的结果反馈比通过反馈更快. HR 会反馈你哪里表现得不够好, 然后如果想进 Google, 就加油刷题, 说 1 年后, 可以再次尝试, 保持联系哦. 哈哈, 以上就是我这次完整的 Google 面试之旅, 虽然失败(实力还不够)了, 但还是有收获的. 如果大家有足够自信(当然也要有一定实力哈), 也可以找我帮忙内推, 我可以给在 Google 的同学帮忙或者直接给招聘的 HR 同学. 如果要面试 Google, 刷题是在所难免的了. 整体来讲, Google 的面试体验还是很不错的, 全程 HR 小姐姐悉心指导和及时反馈, 给 HR 小姐姐点赞 90 | 91 | [📎Google Interview.pdf](https://www.yuque.com/attachments/yuque/0/2020/pdf/710672/1589859743267-a66895f1-bd37-4437-8eeb-81933705ae9b.pdf) -------------------------------------------------------------------------------- /大厂面经/Interview Exp9.md: -------------------------------------------------------------------------------- 1 | # 5家面试3个offer 2 | 3 | 本人工作三年有余,承蒙领导信任,工作第二年就开始带团队了,团队规模从开始的3人到20+又到3人(政策及资金原因,期间做过聚合支付,也带团队从0到1干过支付+营销的完整产品,个人觉得自己实力比上不足比下有余,菜鸡高级开发。 4 | 5 | 由于校招到现在没面过试,所以不晓得目前市面上的面试都是啥套路,本次找工作整体流程就是,离职,在家看了两周的面试题,然后开始投简历,然后面了大概两周,一天只约一个,回来总结经验教训和知识盲点,比如有哪些回答本来可以答的更好,组织语言,下次再问我就一脸自信,无懈可击,两周时间,一共面了5家,拿个3个offer(还有一个最近面的,还没消息)。 6 | 7 | 8 | 9 | **题目与分析** 10 | 11 | 第一家:某某直聘 12 | 13 | 14 | 15 | ​ 一面的笔试和二面的问题比较中规中矩,都是常规问题,比如线程池参数、线程池原理、hashmap原理、类加载机制、CMS收集器、volatile原理(没问到MESI,只问到作用,明显仨,再就不问了),还有就是一些实际问题的处理,缓存双写一致性、分布式事务、IOC、AOP的原理、bean生命周期等等吧,吹的还可以。三面的时候有俩题没答好,一是不停机分表怎么做,并且基于时间分表后,跨表查询怎么做。这个当初回答是生产没做,如果想做可以怎样怎样;第二个问题是秒杀如何解决超卖,这个很久之前看过,当初一下子懵逼了,答个稀里糊涂。之后HR面,问我现在给你发offer,一周之内能入职么,我说不能,你家是第一家,得等我面完其他四五家的,然后。。。就没有然后了,这家就挂了。 16 | 17 | 18 | 19 | 回来认证总结了一下,对于第一个问题,我们做过基于mysql的统计分析,实现就是mysql binlog -> kafka -> storm -> es。这不完美解决么,因此再有人问我,就回答将数据全量同步到es中,随便查。第二个问题,其实也蛮简单,无非就是C层限流(令牌桶),biz层队列(排队),dao层检验,查询丢redis。事实证明,后续只要提到这都会问这俩问题,后续再无破绽。 20 | 21 | 22 | 23 | ​ 放出一面笔试题: 24 | 25 | 26 | 27 | \- 两个数组,求交集 28 | 29 | \- 一个包含全部select from where group by having order by 的简单sql 30 | 31 | \- 给定两个数组,只有一个字符不同,其余字母值和顺序都相同,设计一个方法,高效找到这个字符 32 | 33 | \- 实现死锁 34 | 35 | 36 | 37 | 第二家:某菜网 38 | 39 | 40 | 41 | ​ 当初校招差一点就去了他家,校招给钱很多,不过社招实在是扣,曲折的线路,转盘道差一点走丢了,共享办公区,茶水间面试,写算法没有纸,体验有一些不太好。 42 | 43 | 44 | 45 | ​ 一面,笔试+面试,面试还是那些问题,没啥可说的(主要我是没记住),笔试题如下: 46 | 47 | 48 | 49 | \- 删除单链表中的元素 50 | 51 | \- 实现懒加载,线程安全的单例 52 | 53 | \- 设计数据库表,存放学生、课程、学生的课程及成绩,并给出sql语句,查询平均成绩大于85的所有学生 54 | 55 | \- 有一台双核CPU,2G内存,1TB硬盘的机器和一个800G的文件,格式如下,求访问量最多的TOP100的IP地址和访问次数,简述解题方法。 56 | 57 | \- 192.168.1.1 GET/HTTP/1.1 200 580 "-" "Mozilla/5.0" 58 | 59 | \- 手写LRU缓存,要求输出请求未命中的次数 60 | 61 | 62 | 63 | ​ 二面,有俩问题印象挺深刻,主要是启发式面试,个人比较喜欢。一个是我司自己实现了一整套服务治理,可以实现优雅启停等等,面试官和我详细探讨了这么做的好处以及怎么做。另一个问题是mq的使用问题,一连串,比如使用mq的时候如何保证数据一致性,幂等性,消息积压,消息丢失等等,还聊了一些缓存相关的,比如热点商户缓存失效,穿透,雪崩等等吧,其他都是简单问题,就不赘述了(还是因为没记住)。 64 | 65 | 66 | 67 | ​ 好像没三面,hr那天又请假了,我就回去等了。后来等来了消息。 68 | 69 | 70 | 71 | 第三家:某东 72 | 73 | 74 | 75 | ​ 朋友推过去的,效率奇高,上午9点到,中午12点hr面都完事儿了。这个回来整理了,因此题目比较详细。 76 | 77 | 78 | 79 | ​ 一面: 80 | 81 | ​ 1、Object的方法 82 | 83 | ​ 2、jdk1.8比1.7做了哪些改变 84 | 85 | ​ 3、volatile原理 86 | 87 | ​ 4、工作中用到的redis数据类型及场景 88 | 89 | ​ 5、工作中用到的线程池及原理、每个参数是怎么设置的 90 | 91 | ​ 6、工作中用到的Redis锁及原理 92 | 93 | ​ 7、slect * from a left join b on 条件 和 select * from a left join b where 条件一样么,为什么 94 | 95 | ​ 8、热点商户的缓存穿透怎么解决,排队后面的请求等待时间过程怎么办 96 | 97 | ​ 9、hashmap的put过程和扩容过程 98 | 99 | ​ 10、用list users = new ArrayList<>()来说明类加载过程和整个过程中内存各区域的变化 100 | 101 | ​ 11、线上用的垃圾回收器是啥,分几个阶段,哪个阶段stop the world,eden里还有什么 102 | 103 | ​ 12、设计一个高可用、幂等、安全、高性能的接口需要分别考虑什么 104 | 105 | ​ 13、Spring IOC bean初始化过程 106 | 107 | ​ 14、mybatis的执行过程 108 | 109 | ​ 15、事务隔离级别和mvcc 110 | 111 | ​ 16、redis集群现在有10台机器,新加入5台,数据是怎么同步的 112 | 113 | ​ 17、redis的持久化方式、redis的过期策略 114 | 115 | ​ 18、redis和memcache的区别 116 | 117 | ​ 19、mysql有哪些索引类型 118 | 119 | ​ 20、lock和synchronized区别,生产还用过juc下的哪些类,场景 120 | 121 | ​ 21、AtomicInteger的原理 122 | 123 | 124 | 125 | ​ 二面: 126 | 127 | ​ 1、redis lru是怎么实现的,如何手写一个lru 128 | 129 | ​ 2、B树和B+树的区别,mysql为啥使用B+树 130 | 131 | ​ 3、红黑树的特性及变换 132 | 133 | ​ 4、生产上的分布式事务怎么做的 134 | 135 | ​ 5、分布式限流 136 | 137 | ​ 6、mq积压如何保证消费到最新的消息,mq如何保证消费顺序 138 | 139 | ​ 7、lambda写一个排序 140 | 141 | ​ 8、mysql能发生死锁么,为什么 142 | 143 | ​ 9、生产上的服务降级做了么,怎么做的 144 | 145 | ​ 10、缓存的双写一致性怎么保证,生产是怎么用的,有什么问题,怎么解决 146 | 147 | ​ 11、生产的不停机分表怎么做的,怎么支持跨时间查询,有无其他更好的分表方式 148 | 149 | ​ 12、说一下下单的整个流程 150 | 151 | ​ 13、如何解决超卖 152 | 153 | ​ 14、线上发生过jvm问题么,如何排查的,引起原因是什么 154 | 155 | ​ 15、线程池的核心参数及原理 156 | 157 | 158 | 159 | 同样没三面就hr了。 160 | 161 | 162 | 163 | 第四家:某手 164 | 165 | 166 | 167 | ​ hr还下楼来接,面试官的体验也很棒,整个一面就在白板上给他画,想到哪就画到哪,聊到哪,不像面试,倒像是探讨问题。二面就比较严肃了,问一个答一个,还问了一个比较低级的业务问题,我一股无名火,差点没急眼,幸亏忍住了。。。三面是个boss,体验也挺棒,还是以引导面试为主,不会的会引导你,总体觉得这家公司很注重人的感受,很喜欢。 168 | 169 | 170 | 171 | 一面 172 | 173 | 174 | 175 | 1、介绍一下项目架构:技术+业务 176 | 177 | 2、缓存双写一致性,先更新db再更新缓存有什么问题 178 | 179 | 3、系统内的一致性和通道方的一致性如何解决 180 | 181 | 4、volatile原理和应用 182 | 183 | 5、mysql索引分类,详细介绍一下聚簇索引和结构 184 | 185 | 6、数组交叉合并,例如 186 | 187 | ​ [[1,3],[2,4],[5,7],[8,9]]输出[[1,4],[5,9]] 188 | 189 | 7、两个事务 190 | 191 | ​ T1 T2 192 | 193 | begin: 194 | 195 | select * from t where ... 196 | 197 | 198 | 199 | ​ begin: 200 | 201 | ​ insert into t (id,name) values (5,"小明"); 202 | 203 | ​ commit; 204 | 205 | 206 | 207 | update t set ... where id = 5; -->(问这条是否可以执行成功,为什么?) 208 | 209 | commit; 210 | 211 | 8、redis使用了哪些数据类型,怎么用的,过期策略 212 | 213 | 9、redis如何实现分布式锁 214 | 215 | 10、限流和服务降级做了没,怎么做的;简述令牌桶原理 216 | 217 | 11、线上秒杀是怎么做的,超卖怎么解决 218 | 219 | 12、介绍一下mvcc和间隙锁 220 | 221 | 13、写一个单例 222 | 223 | 14、线上垃圾收集器,CMS几个阶段 224 | 225 | 15、redis和memcached区别 226 | 227 | 228 | 229 | 二面 230 | 231 | 232 | 233 | 1、ThreadLocal用过没,说一下原理 234 | 235 | 2、项目难点 236 | 237 | 3、表t(id(主键),sid(学生id),cid(课程id),score(乘积)) 求所有乘积都超过90的全部sid 238 | 239 | 4、将一个小于千亿的long类型的数字转成中文输出 240 | 241 | ​ 例如1234 输出:一千两百三十四 242 | 243 | 5、synchronized 和 Lock区别,建议使用哪个,为什么 244 | 245 | 6、tcp和http的区别,一个tcp连接可以发送多个http请求么,什么参数控制,浏览器请求连接数有限制么,是多少,是服务端限制的还是浏览器限制的 246 | 247 | 7、介绍一下saas平台的主业务流程 248 | 249 | 8、平时怎么带项目的,说一下具体流程 250 | 251 | 252 | 253 | 三面 254 | 255 | 256 | 257 | 1、过去项目中最大的成就是什么、业务、架构、管理都可 258 | 259 | 2、完成情况,指标 260 | 261 | 3、未来的职业规划 262 | 263 | 4、写个方法,要求考虑性能 264 | 265 | 输入:File file 266 | 267 | 文件5G,JVM 1G 268 | 269 | 文件格式:2020-01-08 10:07:23 123 http://www.baidu.com/index 270 | 271 | 123是用户ID,范围1到100亿 272 | 273 | 要去:解析文件,统计并打印每个用户的总访问次数,打印出用户ID和总次数即可 274 | 275 | 没有脏数据、可以写伪代码 276 | 277 | 278 | 279 | 第五家:某滴 280 | 281 | 282 | 283 | ​ 这个体验也有有点差,茶水间面试,等三面等了一个多小时,都想拍屁股走了,给hr打电话才来。 284 | 285 | 286 | 287 | 一面 288 | 289 | 1、支付三年,你认为支付系统比较重要的是什么 290 | 291 | 重复支付预防,分布式事务和降级,热点商户的处理 292 | 293 | 294 | 295 | 2、这三个都是怎么解决的 296 | 297 | 3、热点商户使用乐观锁+重试,如果重试也不行怎么处理,然后问了一些数据库的锁 298 | 299 | 4、分布式事务和降级怎么做的,定时用的什么组件,quartz单点怎么解决,广播的话怎么做,不用mq怎么做,自己实现一个分布式的delayqueue怎么实现 300 | 301 | 5、redis怎么用的,用了哪几种数据类型,底层数据结构是什么,string相比c的char数组做了哪些优化,list怎么用的 302 | 303 | 6、重复支付怎么搞定的 304 | 305 | 7、对账怎么搞,准实时对账怎么搞,如果只想从从库拉数据对账怎么解决延迟问题 306 | 307 | 308 | 309 | 二面 310 | 311 | 312 | 313 | ​ 二面基本上就没有基础问题了,都是一些业务场景怎么处理,线上出问题如何查询解决优化等等。 314 | 315 | 316 | 317 | \- 对账怎么做的 318 | 319 | \- 账户系统如何解决资金一致性问题 320 | 321 | \- redis锁怎么实现及用法 322 | 323 | \- AOP举个线上的例子 324 | 325 | \- 缓存一致性 326 | 327 | \- 服务降级和限流 328 | 329 | 330 | 331 | 三面 332 | 333 | 334 | 335 | ​ 三面跟二面差不多,基础问题不多,有一些管理相关的。 336 | 337 | 338 | 339 | \- 设计模式怎么用,用过哪些 340 | 341 | \- 团队怎么管理,日常比例 342 | 343 | \- 架构怎么设计,说一下具体流程 344 | 345 | \- 服务怎么拆分,原则 346 | 347 | \- 不停机分库分表怎么做 348 | 349 | \- JVM问题排查,栈溢出,OOM,CPU飙升 350 | 351 | \- 开发流程说一下过程 352 | 353 | \- 如何保证线上代码质量 354 | 355 | \- 除了内部灰度,还有哪些方法可以提高线上产品的质量以及减轻损失 356 | 357 | \- linux原理(完全不会) 358 | 359 | \- 其他我没记住 -------------------------------------------------------------------------------- /大厂面经/media/006tNbRwgy1g9ux8rjqfwj30g70fhdm4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/006tNbRwgy1g9ux8rjqfwj30g70fhdm4.jpg -------------------------------------------------------------------------------- /大厂面经/media/006tNbRwgy1g9ux8w8661j30hc08u403.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/006tNbRwgy1g9ux8w8661j30hc08u403.jpg -------------------------------------------------------------------------------- /大厂面经/media/006tNbRwgy1g9ux90cmw4j30h803iab4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/006tNbRwgy1g9ux90cmw4j30h803iab4.jpg -------------------------------------------------------------------------------- /大厂面经/media/006tNbRwgy1g9ux96vbg7j30i407sgmz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/006tNbRwgy1g9ux96vbg7j30i407sgmz.jpg -------------------------------------------------------------------------------- /大厂面经/media/006tNbRwgy1g9ux9a6cfxj308b049gm0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/006tNbRwgy1g9ux9a6cfxj308b049gm0.jpg -------------------------------------------------------------------------------- /大厂面经/media/006tNbRwgy1g9ux9dyrn5j30ax0a43zm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/006tNbRwgy1g9ux9dyrn5j30ax0a43zm.jpg -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213310547: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213310547 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213310630: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213310630 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213310681: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213310681 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213310684: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213310684 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213310692: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213310692 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213310736: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213310736 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213310747: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213310747 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213310749: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213310749 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213310764: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213310764 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213310784: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213310784 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213310802: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213310802 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213310803: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213310803 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213310828: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213310828 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213310899: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213310899 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213322270: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213322270 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213322273: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213322273 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213322276: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213322276 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213322278: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213322278 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213322285: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213322285 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213322329: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213322329 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213322353: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213322353 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213327997: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213327997 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213328002: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213328002 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213328002-6244008: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213328002-6244008 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213328002-6244008.: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213328002-6244008. -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213328004: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213328004 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213328010: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213328010 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213328034: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213328034 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213328040: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213328040 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213349268: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213349268 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213349274: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213349274 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213349278: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213349278 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213349286: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213349286 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213349309: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213349309 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213349324: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213349324 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213349350: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213349350 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213358869: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213358869 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213358870: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213358870 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213358873: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213358873 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213358875: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213358875 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213358889: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213358889 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213358898: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213358898 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213358910: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213358910 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213554931: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213554931 -------------------------------------------------------------------------------- /大厂面经/media/640-20191213213602270: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/640-20191213213602270 -------------------------------------------------------------------------------- /大厂面经/media/image-20191213092233778.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/image-20191213092233778.png -------------------------------------------------------------------------------- /大厂面经/media/image-20191213092446557.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/image-20191213092446557.png -------------------------------------------------------------------------------- /大厂面经/media/image-20191213093127572.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/image-20191213093127572.png -------------------------------------------------------------------------------- /大厂面经/media/image-20191213093225461.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/image-20191213093225461.png -------------------------------------------------------------------------------- /大厂面经/media/image-20191213093243414.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/image-20191213093243414.png -------------------------------------------------------------------------------- /大厂面经/media/image-20191213093257647.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/image-20191213093257647.png -------------------------------------------------------------------------------- /大厂面经/media/image-20191213213621574.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/image-20191213213621574.png -------------------------------------------------------------------------------- /大厂面经/media/image-20191213213740733.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/image-20191213213740733.png -------------------------------------------------------------------------------- /大厂面经/media/image-20191213213805148.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/image-20191213213805148.png -------------------------------------------------------------------------------- /大厂面经/media/image-20191213213928996.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/image-20191213213928996.png -------------------------------------------------------------------------------- /大厂面经/media/image-20191213214128396.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/image-20191213214128396.png -------------------------------------------------------------------------------- /大厂面经/media/image-20191213214535975.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/大厂面经/media/image-20191213214535975.png -------------------------------------------------------------------------------- /学习资料/Learning.md: -------------------------------------------------------------------------------- 1 | # 知识就摆在这里,就看你自己学不学 2 | 3 | ## 视频学习资料 4 | 5 | ### 面试题-视频版 6 | 7 | 链接: https://pan.baidu.com/s/1NQT7fzKU5hi7v1Y5Pu8V2g 提取码: f67h 8 | 9 | 10 | 11 | ### Java(架构师课程,动脑,咕泡) 12 | 13 | 链接:https://pan.baidu.com/s/1fevXlLxSidkQEhXu5OhvBg 提取码:qegc 14 | 15 | 链接: https://pan.baidu.com/s/1JzfqeQLNHVUw17NOu2vKQw 提取码: qjyd 16 | 17 | `还有一部分架构师课程网盘不让分享,但上面的视频也够你看了,咕泡的视频可以先看,讲的挺好的` 18 | 19 | 不能分享部分,[查看截图](#其他),若喜欢可以关注[【公众号】](#公众号),发送百度网盘账号,单独发你 20 | 21 | 22 | 23 | ### 算法(九章) 24 | 25 | 链接:https://pan.baidu.com/s/1WMlXxoY2Q9q404FZev5GVg 提取码:r1uq 26 | 27 | 28 | 29 | ### 大数据(Flink, Spark) 30 | 31 | 链接:https://pan.baidu.com/s/1G4k_1B6NO4yCoc211UXpDA 提取码:pkgr 32 | 33 | 34 | 35 | ### 机器学习 36 | 37 | 链接: https://pan.baidu.com/s/1rFA8EM7NXsJ2qL0tkxbDVg 提取码: 8n2g 38 | 39 | 40 | 41 | ### 其他参考资料 42 | 43 | Java知识库:https://www.yuque.com/lexiangqizhong/java 44 | 45 | ## 其他 46 | 47 | ![image-20200627142356190](https://tva1.sinaimg.cn/large/007S8ZIlly1gg6tugktvgj30as0cc0tf.jpg) 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /学习资料/media/006tNbRwly1ga6z6ig0vej30ck0ju75u.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/学习资料/media/006tNbRwly1ga6z6ig0vej30ck0ju75u.jpg -------------------------------------------------------------------------------- /学习资料/media/image-20191223212524703.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/学习资料/media/image-20191223212524703.png -------------------------------------------------------------------------------- /学习资料/media/image-20191223212734977.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/学习资料/media/image-20191223212734977.png -------------------------------------------------------------------------------- /学习资料/media/image-20191223212741417.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/学习资料/media/image-20191223212741417.png -------------------------------------------------------------------------------- /学习资料/media/image-20191223212859627.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/学习资料/media/image-20191223212859627.png -------------------------------------------------------------------------------- /学习资料/media/image-20191223212918623.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/学习资料/media/image-20191223212918623.png -------------------------------------------------------------------------------- /学习资料/media/image-20191223212936257.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/学习资料/media/image-20191223212936257.png -------------------------------------------------------------------------------- /学习资料/media/image-20191223212952306.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/学习资料/media/image-20191223212952306.png -------------------------------------------------------------------------------- /学习资料/media/image-20191223213011426.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/学习资料/media/image-20191223213011426.png -------------------------------------------------------------------------------- /学习资料/media/image-20191223213029704.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/学习资料/media/image-20191223213029704.png -------------------------------------------------------------------------------- /学习资料/media/image-20191223213731596.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/学习资料/media/image-20191223213731596.png -------------------------------------------------------------------------------- /源码分析/CompletableFuture.md: -------------------------------------------------------------------------------- 1 | # CompletableFuture 源码分析 2 | 3 | > 源码基于open jdk 11 4 | 5 | CompletableFuture 是 jdk8 引入的类,主要是对Future的补充。 6 | 7 | CompletableFuture类的官方API文档解释: 8 | 9 | 1. CompletableFuture是一个在完成时可以触发相关方法和操作的Future,并且它可以视作为CompletableStage。 10 | 2. 除了直接操作状态和结果的这些方法和相关方法外(CompletableFuture API提供的方法),CompletableFuture还实现了以下的CompletionStage的相关策略: 11 | - 非异步方法的完成,可以由当前CompletableFuture的线程提供,也可以由其他调用完方法的线程提供。 12 | - 所有没有显示使用Executor的异步方法,会使用ForkJoinPool.commonPool()(那些并行度小于2的任务会创建一个新线程来运行)。为了简化监视、调试和跟踪异步方法,所有异步任务都被标记为CompletableFuture.AsynchronouseCompletionTask。 13 | - 所有CompletionStage方法都是独立于其他公共方法实现的,因此一个方法的行为不受子类中其他方法的覆盖影响。 14 | 3. CompletableFuture还实现了Future的以下策略 15 | - 不像FutureTask,因CompletableFuture无法直接控制计算任务的完成,所以CompletableFuture的取消会被视为异常完成。调用cancel()方法会和调用completeExceptionally()方法一样,具有同样的效果。isCompletedEceptionally()方法可以判断CompletableFuture是否是异常完成。 16 | - 在调用get()和get(long, TimeUnit)方法时以异常的形式完成,则会抛出ExecutionException,大多数情况下都会使用join()和getNow(T),它们会抛出CompletionException。 17 | 18 | 待回答的几个问题: 19 | 20 | 1、如何实现并发执行任务? 21 | 22 | 2、并发执行如何获取任务结果? 23 | 24 | 25 | 26 | https://blog.csdn.net/CoderBruis/article/details/103181520?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.control 27 | 28 | -------------------------------------------------------------------------------- /源码分析/Helpers.md: -------------------------------------------------------------------------------- 1 | # Java 11中的Helpers 2 | 3 | ```java 4 | package java.util.concurrent; 5 | 6 | import java.util.Collection; 7 | 8 | /** 用于 java.util.concurrent 包中*/ 9 | class Helpers { 10 | //私有构造函数,不可实例化 11 | private Helpers() {} 12 | 13 | /** 14 | * Collection.toString() 的一种实现,适用于有锁的类。 15 | * 代替了以前在整个toString()过程中加锁,或者在每次调用Iterator.next()的时候加锁 16 | * 该方法只在调用toArray()期间加锁,以减少其他线程对访问集合时产生的影响 17 | * 并且遵循在加锁期间,不调用任何外部代码 18 | */ 19 | static String collectionToString(Collection c) { 20 | final Object[] a = c.toArray(); 21 | final int size = a.length; 22 | if (size == 0) 23 | return "[]"; 24 | int charLength = 0; 25 | 26 | // Replace every array element with its string representation 27 | for (int i = 0; i < size; i++) { 28 | Object e = a[i]; 29 | // Extreme compatibility with AbstractCollection.toString() 30 | String s = (e == c) ? "(this Collection)" : objectToString(e); 31 | a[i] = s; 32 | charLength += s.length(); 33 | } 34 | 35 | return toString(a, size, charLength); 36 | } 37 | 38 | /** 39 | * Like Arrays.toString(), but caller guarantees that size > 0, 40 | * each element with index 0 <= i < size is a non-null String, 41 | * and charLength is the sum of the lengths of the input Strings. 42 | */ 43 | static String toString(Object[] a, int size, int charLength) { 44 | // assert a != null; 45 | // assert size > 0; 46 | 47 | // Copy each string into a perfectly sized char[] 48 | // Length of [ , , , ] == 2 * size 49 | final char[] chars = new char[charLength + 2 * size]; 50 | chars[0] = '['; 51 | int j = 1; 52 | for (int i = 0; i < size; i++) { 53 | if (i > 0) { 54 | chars[j++] = ','; 55 | chars[j++] = ' '; 56 | } 57 | String s = (String) a[i]; 58 | int len = s.length(); 59 | s.getChars(0, len, chars, j); 60 | j += len; 61 | } 62 | chars[j] = ']'; 63 | // assert j == chars.length - 1; 64 | return new String(chars); 65 | } 66 | 67 | /** Optimized form of: key + "=" + val */ 68 | static String mapEntryToString(Object key, Object val) { 69 | final String k, v; 70 | final int klen, vlen; 71 | final char[] chars = 72 | new char[(klen = (k = objectToString(key)).length()) + 73 | (vlen = (v = objectToString(val)).length()) + 1]; 74 | k.getChars(0, klen, chars, 0); 75 | chars[klen] = '='; 76 | v.getChars(0, vlen, chars, klen + 1); 77 | return new String(chars); 78 | } 79 | 80 | private static String objectToString(Object x) { 81 | // Extreme compatibility with StringBuilder.append(null) 82 | String s; 83 | return (x == null || (s = x.toString()) == null) ? "null" : s; 84 | } 85 | } 86 | ``` -------------------------------------------------------------------------------- /源码分析/LinkedHashMap.md: -------------------------------------------------------------------------------- 1 | # LinkedHashMap源码分析 2 | 3 | > 以下源码基于Java8 4 | 5 | 众所周知 [HashMap]是一个无序的 `Map`,因为每次根据 `key` 的 `hashcode` 映射到 `Entry` 数组上,所以遍历出来的顺序并不是写入的顺序。 6 | 7 | 因此 JDK 推出一个基于 `HashMap` 但具有顺序的 `LinkedHashMap` 来解决有排序需求的场景。 8 | 9 | 它的底层是继承于 `HashMap` 实现的,由一个双向链表所构成。 10 | 11 | `LinkedHashMap` 的排序方式有两种: 12 | 13 | - 根据写入顺序排序。 14 | - 根据访问顺序排序。 15 | 16 | 其中根据访问顺序排序时,每次 `get` 都会将访问的值移动到链表末尾,这样重复操作就能的到一个按照访问顺序排序的链表。 17 | 18 | ## 数据结构 19 | 20 | ``` 21 | @Test 22 | public void test(){ 23 | Map map = new LinkedHashMap(); 24 | map.put("1",1) ; 25 | map.put("2",2) ; 26 | map.put("3",3) ; 27 | map.put("4",4) ; 28 | map.put("5",5) ; 29 | System.out.println(map.toString()); 30 | 31 | } 32 | ``` 33 | 34 | 调试可以看到 `map` 的组成: 35 | 36 | ![img](media/5cd1ba2adf7c0-20191214003715601.jpg) 37 | 38 | 打开源码可以看到: 39 | 40 | ``` 41 | /** 42 | * The head of the doubly linked list. 43 | */ 44 | private transient Entry header; 45 | 46 | /** 47 | * The iteration ordering method for this linked hash map: true 48 | * for access-order, false for insertion-order. 49 | * 50 | * @serial 51 | */ 52 | private final boolean accessOrder; 53 | 54 | private static class Entry extends HashMap.Entry { 55 | // These fields comprise the doubly linked list used for iteration. 56 | Entry before, after; 57 | 58 | Entry(int hash, K key, V value, HashMap.Entry next) { 59 | super(hash, key, value, next); 60 | } 61 | } 62 | ``` 63 | 64 | 其中 `Entry` 继承于 `HashMap` 的 `Entry`,并新增了上下节点的指针,也就形成了双向链表。 65 | 66 | 还有一个 `header` 的成员变量,是这个双向链表的头结点。 67 | 68 | 上边的 demo 总结成一张图如下: 69 | 70 | ![img](media/5cd1ba2d418b6-20191214003733877.jpg) 71 | 72 | 第一个类似于 `HashMap` 的结构,利用 `Entry` 中的 `next` 指针进行关联。 73 | 74 | 下边则是 `LinkedHashMap` 如何达到有序的关键。 75 | 76 | 就是利用了头节点和其余的各个节点之间通过 `Entry` 中的 `after` 和 `before` 指针进行关联。 77 | 78 | 其中还有一个 `accessOrder` 成员变量,默认是 `false`,默认按照插入顺序排序,为 `true` 时按照访问顺序排序,也可以调用: 79 | 80 | ``` 81 | public LinkedHashMap(int initialCapacity, 82 | float loadFactor, 83 | boolean accessOrder) { 84 | super(initialCapacity, loadFactor); 85 | this.accessOrder = accessOrder; 86 | } 87 | ``` 88 | 89 | 这个构造方法可以显示的传入 `accessOrder`。 90 | 91 | ## 构造方法 92 | 93 | `LinkedHashMap` 的构造方法: 94 | 95 | ``` 96 | public LinkedHashMap() { 97 | super(); 98 | accessOrder = false; 99 | } 100 | ``` 101 | 102 | 其实就是调用的 `HashMap` 的构造方法: 103 | 104 | `HashMap` 实现: 105 | 106 | ``` 107 | public HashMap(int initialCapacity, float loadFactor) { 108 | if (initialCapacity < 0) 109 | throw new IllegalArgumentException("Illegal initial capacity: " + 110 | initialCapacity); 111 | if (initialCapacity > MAXIMUM_CAPACITY) 112 | initialCapacity = MAXIMUM_CAPACITY; 113 | if (loadFactor <= 0 || Float.isNaN(loadFactor)) 114 | throw new IllegalArgumentException("Illegal load factor: " + 115 | loadFactor); 116 | 117 | this.loadFactor = loadFactor; 118 | threshold = initialCapacity; 119 | //HashMap 只是定义了改方法,具体实现交给了 LinkedHashMap 120 | init(); 121 | } 122 | ``` 123 | 124 | 可以看到里面有一个空的 `init()`,具体是由 `LinkedHashMap` 来实现的: 125 | 126 | ``` 127 | @Override 128 | void init() { 129 | header = new Entry<>(-1, null, null, null); 130 | header.before = header.after = header; 131 | } 132 | ``` 133 | 134 | 其实也就是对 `header` 进行了初始化。 135 | 136 | ## put 方法 137 | 138 | 看 `LinkedHashMap` 的 `put()` 方法之前先看看 `HashMap` 的 `put` 方法: 139 | 140 | ``` 141 | public V put(K key, V value) { 142 | if (table == EMPTY_TABLE) { 143 | inflateTable(threshold); 144 | } 145 | if (key == null) 146 | return putForNullKey(value); 147 | int hash = hash(key); 148 | int i = indexFor(hash, table.length); 149 | for (Entry e = table[i]; e != null; e = e.next) { 150 | Object k; 151 | if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 152 | V oldValue = e.value; 153 | e.value = value; 154 | //空实现,交给 LinkedHashMap 自己实现 155 | e.recordAccess(this); 156 | return oldValue; 157 | } 158 | } 159 | 160 | modCount++; 161 | // LinkedHashMap 对其重写 162 | addEntry(hash, key, value, i); 163 | return null; 164 | } 165 | 166 | // LinkedHashMap 对其重写 167 | void addEntry(int hash, K key, V value, int bucketIndex) { 168 | if ((size >= threshold) && (null != table[bucketIndex])) { 169 | resize(2 * table.length); 170 | hash = (null != key) ? hash(key) : 0; 171 | bucketIndex = indexFor(hash, table.length); 172 | } 173 | 174 | createEntry(hash, key, value, bucketIndex); 175 | } 176 | 177 | // LinkedHashMap 对其重写 178 | void createEntry(int hash, K key, V value, int bucketIndex) { 179 | Entry e = table[bucketIndex]; 180 | table[bucketIndex] = new Entry<>(hash, key, value, e); 181 | size++; 182 | } 183 | ``` 184 | 185 | 主体的实现都是借助于 `HashMap` 来完成的,只是对其中的 `recordAccess(), addEntry(), createEntry()` 进行了重写。 186 | 187 | `LinkedHashMap` 的实现: 188 | 189 | ``` 190 | //就是判断是否是根据访问顺序排序,如果是则需要将当前这个 Entry 移动到链表的末尾 191 | void recordAccess(HashMap m) { 192 | LinkedHashMap lm = (LinkedHashMap)m; 193 | if (lm.accessOrder) { 194 | lm.modCount++; 195 | remove(); 196 | addBefore(lm.header); 197 | } 198 | } 199 | 200 | 201 | //调用了 HashMap 的实现,并判断是否需要删除最少使用的 Entry(默认不删除) 202 | void addEntry(int hash, K key, V value, int bucketIndex) { 203 | super.addEntry(hash, key, value, bucketIndex); 204 | 205 | // Remove eldest entry if instructed 206 | Entry eldest = header.after; 207 | if (removeEldestEntry(eldest)) { 208 | removeEntryForKey(eldest.key); 209 | } 210 | } 211 | 212 | void createEntry(int hash, K key, V value, int bucketIndex) { 213 | HashMap.Entry old = table[bucketIndex]; 214 | Entry e = new Entry<>(hash, key, value, old); 215 | //就多了这一步,将新增的 Entry 加入到 header 双向链表中 216 | table[bucketIndex] = e; 217 | e.addBefore(header); 218 | size++; 219 | } 220 | 221 | //写入到双向链表中 222 | private void addBefore(Entry existingEntry) { 223 | after = existingEntry; 224 | before = existingEntry.before; 225 | before.after = this; 226 | after.before = this; 227 | } 228 | ``` 229 | 230 | ## get 方法 231 | 232 | LinkedHashMap 的 `get()` 方法也重写了: 233 | 234 | ``` 235 | public V get(Object key) { 236 | Entry e = (Entry)getEntry(key); 237 | if (e == null) 238 | return null; 239 | 240 | //多了一个判断是否是按照访问顺序排序,是则将当前的 Entry 移动到链表头部。 241 | e.recordAccess(this); 242 | return e.value; 243 | } 244 | 245 | void recordAccess(HashMap m) { 246 | LinkedHashMap lm = (LinkedHashMap)m; 247 | if (lm.accessOrder) { 248 | lm.modCount++; 249 | 250 | //删除 251 | remove(); 252 | //添加到头部 253 | addBefore(lm.header); 254 | } 255 | } 256 | ``` 257 | 258 | `clear()` 清空就要比较简单了: 259 | 260 | ``` 261 | //只需要把指针都指向自己即可,原本那些 Entry 没有引用之后就会被 JVM 自动回收。 262 | public void clear() { 263 | super.clear(); 264 | header.before = header.after = header; 265 | } 266 | ``` 267 | 268 | ## 总结 269 | 270 | 总的来说 `LinkedHashMap` 其实就是对 `HashMap` 进行了拓展,使用了双向链表来保证了顺序性。 271 | 272 | 因为是继承与 `HashMap` 的,所以一些 `HashMap` 存在的问题 `LinkedHashMap` 也会存在,比如不支持并发等。 273 | -------------------------------------------------------------------------------- /源码分析/Spring Boot/Spring Boot Reference 2.6.11 .pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/源码分析/Spring Boot/Spring Boot Reference 2.6.11 .pdf -------------------------------------------------------------------------------- /源码分析/media/5cd1ba2adf7c0-20191214003715601.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/源码分析/media/5cd1ba2adf7c0-20191214003715601.jpg -------------------------------------------------------------------------------- /源码分析/media/5cd1ba2adf7c0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/源码分析/media/5cd1ba2adf7c0.jpg -------------------------------------------------------------------------------- /源码分析/media/5cd1ba2d418b6-20191214003733877.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/源码分析/media/5cd1ba2d418b6-20191214003733877.jpg -------------------------------------------------------------------------------- /源码分析/media/5cd1ba2d418b6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jujunchen/Java-interview-question/46cc59de590e721c1beb77344c8ebb627b84f6b8/源码分析/media/5cd1ba2d418b6.jpg --------------------------------------------------------------------------------