2022个人面试问题记录(三年)

180 阅读30分钟

一:数据库

  • 优化方式: ①使用索引。 ②减少查询字段,避免子查询全表查询,减少联表。 ③分库分表,减少数据量。 数据库配置方面读写分离 主库做修改 从库查询
  • 慢查询设置:show variable like '%qury%' 设值定义为慢查询的时间以及打开日志记录(终端中打开,可以看到是哪条慢)。 慢查询条数查询:show status like '%qury%'。 慢查询分析:explain sql语句 看type和extra(执行说明)。type为all或index需要优化(至少到range索引范围覆盖)。extra是useindex还是file,没有索引就走索引,或者不是最优索引。 可以成为索引的字段: ①主键和外键。 ②连接表与表的字段。 ③经常出现在条件中的字段。
  • 索引原理: 将无序数据进行有序排列,对索引列进行排序生成倒排表,对倒排表上的数据加上数据地址链,查询是先拿出倒排表再根据数据地址链获得数据。(终归来说就是减少了磁盘的io次数)。 索引失效: ①隐式转换(varchar转成了number)。 ②使用模糊查询。 ③参与计算。 ④or的字段不是索引。 ⑤不满足索引最左匹配原则。
  • 最左匹配原则:联合索引A和B,只用了右边的B作为查询条件则不走索引;多个时中途遇到了范围查询(大于小于)停止使用索引,可以调整索引顺序,将范围查找的条件放到最后。 B+树在查找时先用最左索引定位,再用第二个索引找到数据,光用第二个索引无法定位。 *索引在数据少,更新频繁,重复多时不建议使用,有外键时必须使用,索引越多占用空间越大,维护成本越高。
  • ACID: 原子性A:整个事务中的所有操作要么全部commit成功,要么全部失败rollback,一个事务不可能只执行其中的一部分SQL操作。 *实现:undolog,在sql执行前记录一条undolog,需要回滚时做逆处理(delete就做insert)。 一致性C:数据库总是从一个一致性的状态转换到另外一个一致性的状态,假如一个事务中第三步第四步失败了,最终事务没有commit,修改也不会保存到数据库中。 隔离性I:事务最终提交前对其他事务不可见。加锁管理多个事务的执行顺序,lock in share mode加的是读锁,for update 加的是写锁。 读未提交(RU):一个事务还没提交时,它做的变更就能被别的事务看到。(别的事务指同一时间进行的增删改查操作) 读提交(RC):一个事务提交(commit)之后,它做的变更才会被其他事务看到。 可重复读(RR):一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。 当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。 串行(xíng)化(S):在MySQL中同一时刻只允许单个事务执行,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。 持久性D:事务一旦提交,修改就会永久保存在数2022个人面试问题记录(三年)据库中。 *持久化到磁盘,如果并发量太大假如缓冲池(buffer pool),假如设备断电数据丢失,redo log + binlog。 *分页:通过设置limit的偏移量以及查询条数,偏移量=(当前页数-1)*显示条数。 *Mybatis原理:底层:动态代理,封装了结果集和pojo的映射。 读取Mybatis的配置文件,加载映射类,创建会话工厂以及会话对象,执行器通过会话对象里的传递参数动态生成sql操作数据库。 *#{}是预编译处理替换成?后在set赋值,${}是字符串替换。

二:Spring

  • IOC容器:避免频繁使用new,可以进行同意管理。实际上是一个key—value的map,存放通过反射创建的对象(@component@controller@service或者xml配置节点),使用时通过依赖注入。 控制反转:创建对象的控制权由自己转交给第三方,A和B共同完成一个事,以前由A去创建B,存在依赖关系,而现在由ioc创建,没有依赖关系,要什么就去ioc中获取。 依赖注入:注解注入;接口注入;setter注入;构造器注入。 工作流程:初始化后依赖注入。 如何控制加载顺序:@DependsOn,括号里内容在前加载。 *@autowired:spring自带,只能根据type注入,默认注入对象存在,想要根据name注入需要搭配@qualifier; @resource j2ee提供,根据type和name注入。 *spring bean作用域:单例(默认),session,request,application,websocket。 *beanFactory是spring的重要组件,创建和维护bean。而applicationtext是面向用户的。 BeanFactory:负责生产和管理Bean的一个接口。 FactoryBean: 一种Bean创建的一种方式,适用于创建复杂bean(默认创建是bean标签)。
  • AOP 将程序中的一些交叉业务逻辑提取出来作为一个切面,注入到目标对象,在这个方法前面前后去做一些事。 @aspect 表示这个类是一个切面。 @component 加入ioc管理。 *@scan... 扫描 component。 @cutpoint 定义切入点(文件位置)。 @before 切入时间。 代理模式:接口+真实实现类+代理类 用代理类来代替真实实现类来提供服务。 *静态代理:由程序员提供,编译时选择代理对象,需要实现接口中的所有方法,容易代码重复;动态代理:通过反射创建代理对象,灵活,可扩展可维护。 JDK代理使用的是反射机制实现aop的动态代理,CGLIB代理使用字节码。 JDK动态代理机制是委托机制,在动态生成的实现类里面委托hanlder去调用原始实现类方法,CGLIB则使用的继承机制,被代理类和代理类是继承关系。 *@Transactional 事务失效:数据库不支持,方法不是public修饰的(其余要加切面代理),异常被吃掉。原理:对加上注解的bean,spring会创建一个代理对象作为bean。
  • SringBatch jobLauncher根据定义jobid启动一个具体的任务(job),job中有好多具体执行步骤step。 在step中进行read(读),读文件时可以通过分隔符将每个字段映射到tokenizer自定义成一个lineMapper,process(业务逻辑),write(写入)。 异常:再parent配置中可使用skip方法定义需要跳过的异常类型。 优化:优化读sql;使用原生jdbc;多线程(task-executor);减少process中对数据库进行的操作。 *多线程:要求处理的对象和操作都是线程安全的。 要求对方法加上synchronized。 数据丢失:计数器,在最后的成功标志文件中看读写的数量,少了一般来说是等第二天重跑,数据量少可以实时。
  • ringBoot 启动流程:首先构造一个springApplication,在构造时将参数resource设置到application中,创建并初始化监听器以及初始值,对应值设置到对应属性中。 构造完成后执行run方法,run方法里包含记录启动时间,监听run方法执行,通过arguments获取args参数,创建并初始化环境配置,构造spring容器。 结束时发布finsh消息,停止计时,表示可以就收请求。config/application.properties(项目同级目录中config目录下)config/application.yml 再到同级再到resource。 xml starter:spring-boot-starter-parent : 用于依赖关系管理的父级POM。 spring-boot-starter-web: 构建Web、REST应用程序的启动器。它使用Tomcat服务器作为默认的嵌入式服务器。 spring-boot-devtools : 它提供了开发者工具。这些工具在应用开发模式中很有帮助。开发者工具的一个特点是在代码发生任何变化时自动重新启动服务器。 spring-boot-maven-plugin : 它用于创建应用程序的可执行 @SpringBootApplication包含的三个注解及其含义:@SpringBootConfiguration(源码中有一个Configuration的注解)声明当前类是SpringBoot应用的配置类,项目中只能有一个 @Configuration声明当前类是一个配置类,然后Spring会自动扫描到添加了@Configuration的类,读取其中的配置信息 @EnableAutoConfiguration开启自动配置,告诉SpringBoot基于所添加的依赖,去“猜测”你想要如何配置Spring。 比如我们引入了spring-boot-starter-web,而这个启动器中帮我们添加了tomcat、SpringMVC的依赖,此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置 第三个:@ComponentScan配置组件扫描的指令

微服务

  • PRC:服务调用方远程调用服务提供方。
  • dubbo:分布式rpc框架 *spring cloud:完整的项目框架,有其他组件,使用eruka或者nacos作为注册中心。
  • 服务提供方将将自己的服务注册到注册中心,消费方向注册中心发起订阅,注册中心返回服务列表给消费方,提供方与消费方将服务状态以及调用次数返回给监听器。注册中心通过心跳机制监控提供方。 暴露发现与调用:服务提供方做服务提交时将服务注册到注册中心,本地也暴露,消费方向注册中心拉去服务列表,并且在本地缓存。通过代理进行对应服务调用。 注册中心宕机:使用注册中心集群(没使用,降级就是关闭服务,通过心跳);都宕机只能通过本地缓存; 提供方宕机:不影响,会有其他的提供;都宕机无限次重连。
  • 异常处理: 网关时请求大于阈值:限流,redis获取令牌,setnx,控制访问量 A调用B,B调用C,C发生异常导致B得不到返回:熔断,关闭C的链接 关闭后恢复:全恢复不推荐,一般用B放出部分请求,只要有一个异常就继续关闭重试。 怎么注册到注册中心:以nacos为例,在微服务的pom.xml中添加nacos依赖,启动nacos,在8848/nacos确认是否启动完成,在application.yml中添加注册中心地址, 启动类上加上@EnableDiscoveryClient开启服务注册与发现功能;
  • SpringCloud 一致性C:系统中的所有数据备份,在同一时刻是否同样的值。 可用性A:部分节点故障后,集群整体还能响应客户端的读写请求。 分区容错性P:在遇到任何网络分区故障时,仍能够提供满足一致性和可用性的服务。 zk:cp高一致 eureka:ap高可用
  • Spring Cloud有哪些常用组件:
  1. Eureka:注册中心 9. Ribbon:负载均衡 和feign:启动类使用的注解不同,Ribbon用的是@RibbonClient;调用方式不同,步骤相当繁琐。
  2. Nacos:注册中心、配置中心 10. Spring CLoud Sleuth:链路追踪
  3. Spring Cloud Config:配置中心 11. Zipkin:链路追踪
  4. Feign/OpenFeign:RPC调用 ,Feign用的是@EnableFeignClients;Feign则是在Ribbon的基础上,采用接口的方式,将需要调用的其他服务的方法定义成抽象方法即可,不需要自己构建http请求。
  5. Spring Cloud Gateway:服务网关 14. Sentinel,Hystrix:服务熔断 12. Seata:分布式事务

reids 6379

  • 为什么快 客户端发出查询请求,先去redis中找,有就返回,没有在去数据库中找,有就回种到redis,下次可以直接从redis中获得。若数据库故障则熔断,无论有没有找到,redis都会有返回。 ①纯内存操作。 ②非阻塞性io多路复用机制。 ③主线程是单线程,避免了频繁的上下文切换。 ④数据结构简单,没有表,不强制有关联。 *非阻塞性:select系统调用时会监控多个文件的读写情况,其他线程就可以去做别的事。阻塞:文件不可读不可写时,redis不对其响应。 *上下文切换:暂停当前线程并保存,下次使用时调出来继续。
  • 使用 简单使用:string:get/set;hash:hmset/get(更符合面向对象);list: lpush/lrange; set(无序不可重复) sadd/smembers ;sortedset 按分数排序。 查找key: 少量key中查找:keys * ;大量key中查找:scan 0(游标,开始位置) match * count 10 不一定返回10条并且游标会变大变小。 实现分布式锁:给key加上过期时间 set key value ex(秒,px:毫秒) 时间 NX(存在时不可执行,XX:存在时可执行)。 异步队列:list:使用一个少一个,没有值也会消费,需要设置超时时间。pub/sub(主题订阅):创建topic,消费者订阅这个topic,不保证消息送达需要使用队列。 *主要使用在实现分布式锁以及热点数据存储。
  • RDB:在某一时段内对全量数据进行一次数据集快照,只有一个文件,容易持久化以及被封,但是会丢失数据,不安全。 手动:save: 阻塞进程知道持久化完成; bgsave:fork出一个子进程来完成持久化,不阻塞主进程,会在创建子进程前检查有没有正在进行的RDB/AOF,不浪费资源。 自动(关机且没有开启AOF):在redis.conf配置中save设置多少时间内多少数据插入进行一次持久化并且将bgsave-err改为yes(故障暂停写入)。
  • AOF:记录除查询外操作。数据不会丢失,文件大,不容易恢复。优先级高于RDB
  • 开启:在redis.conf配置找到append-only开启并设置同步策略(每秒同步、没修改同步、不同步)
  • 解决AOF文件过大:日志重写:fork出一个子进程将新AOF记录到临时文件,主进程同时记录到内存以及老AOF中,主进程等子进程完成后,往新AOF中做增量持久化,替换原文件。
  • 混合RDB-AOF: bgsave进行全量持久化,AOF记录操作指令达到增量持久化。
  • 缓存问题 ①缓存雪崩:挡在数据库外面的大量请求访问数据库,数据库受不了; 解决:redis集群,加锁排队。 *过期键删除策略:惰性过期:只有访问到才会去判断他有没有过期,节省cpu资源但是对内存不好 定期过期:设置过期时间。同时拥有两种过期策略。 *淘汰策略:缓存满了之后,不进行数据淘汰,也是Redis的默认配置。这时,当缓存被写满时,再有写请求进来,Redis不再提供服务,直接返回错误。 在设置了过期时间的键值对中进行随机删除;根据过期时间的先后顺序进行删除,越早过期的越先被删除。 从所有键值对中随机选择并删除数据。使用算法在所有的数据中进行筛选删除。 ②缓存穿透:缓存以及数据库中都没有;解决:存放空对象和布隆过滤器(他认为没有一定没有,认为有不一定有)。 ③缓存击穿:缓存中没有,数据库中有; 解决:加互斥锁,热点数据永不过期(不设置expire 过期)。 ④保证mysql与redis数据一致; 解决:延时双删,先删redis,再更新数据库,过几毫秒再删redis。
  • redis集群 主从模式:主库读写并同步从库,宕机需要改ip,难扩容,不支持大数据。 哨兵模式:在主从模式上加入哨兵节点,保证高可用,不好解决容量上限,单数3台以上,故障迁移,选出master。 cluster模式:多主多从,按key进行槽位分配,量大需要扩容使用。 *主从复制:主从库之间建立链接,主库将所有数据同步给从库,从库在本地加载(RDB),同时主库记录此期间操作记录到buffer,当主库完成RDB文件发送后,将buffer发送给从库,从库执行完成主从同步。

MQ

  • 工作流程:生产者想经纪人发送half消息,并创建订单,根据成功与否向经纪人发送commit或rollback(没有收到经纪人会掉生产者提供的回调接口检查是否创建成功),half消息得到commit后, 消费者拉取信息进行消费,消费成功信息销毁,失败重试策略进行重试,再次失败进入死信队列等待处理。
  • 原理:启动时经纪人向nameService(注册中心)发起注册并保持连接,每30s发送一次心跳;生产者向nameService获取经纪人服务地址,并选择一台服务器(根据负载均衡)发送消息; 消费者在消费消息时也想nameService获取经纪人服务地址,主动拉取信息进行消费。
  • 特点: ①异步:系统再给mq发完消息后就可以去处理别的事。 ②削峰:消息进入到队列中,由消费者自己控制消费速度。 ③解耦:两台服务器之间通过mq交流,不需要有依赖。
  • 为什么快:记录日志时是顺序写入到操作系统,再由操作系统异步将数据刷到磁盘。
  • 如何保证消息可靠:不重复生产;不重复消费;不多发。
  • 如何实现高可用:控制台添加镜像集群模式策略启动镜像集群,每台MQ上都有一样的queue(队列),一台MQ宕机,消费者还可以去别的MQ上拉消息。
  • 发送确认机制:ConfirmCallback接口确认是否正确到达 Exchange 中,成功到达则回调,失败回调ReturnCallback接口。
  • 接收确认机制:消费者在声明队列时,可以指定noAck参数,当noAck=false时,MQ会等待消费者发回ack信号后才从内存(或者磁盘,持久化消息)中移去消息。否则,消息被消费后会被删 除。 消费者接收每条消息后都必须进行确认(消息接收和消息确认是两个不同操作)。只有消费者确认了消息,MQ 才能安全地把消息从队列中删除。
  • 其他:消息丢失(生产者开启事务通过返回来判断,经纪人做持久化刷盘,同步刷慢异步刷会丢失);重复消费(使用redis实现分布式 setnx);消息积压(加机器);

VM/GC

  • jVM :执行java程序时将内存划分为多个区域(加载区,本地接口区,解析命令区,内存空间区(方法区(常量方法等),堆(对象),栈(线程创建)))。 java代码编译后的class文件被类加载器加载到内存空间区中进行使用。 方法区和堆是所有线程共享的内存区域;而java栈、本地方法栈和程序员计数器是运行是线程私有的内存区域。
  • 类加载器:将文件从硬盘中读取到内存中(显示:new();隐式:class.forname()/classLoader.loadClass);启动类加载器和自定义类加载器。 *class.forname():class初始化完成;classLoader.loadClass:还未链接。 *加载步骤:加载文件;链接(操作文件);初始化。 启动类加载器: ①AppClassLoader 加载应用 ②ExtClassLoader 加载扩展类 ③bootClassLoader 加载系统类
  • 双亲委派:当类加载器收到类加载请求时,首先会把请求委派给父类加载器。只有在父类加载器找不到指定类时,子类加载器才会尝试自己去加载。
  • 反射:获取类的信息,再创建对象时,jvm会在磁盘中找到这个类的class文件,并加载到内存中,创建一个class对象,创建完成后就可以反向获取这个类的信息。
  • JVM调优的步骤大致可以分为: 1.熟悉业务场景,了解当前业务系统的要求,是吞吐量优先还是响应时间优先; 2.选择合适的垃圾回收器组合,如果是吞吐量优先,则选择ps+po组合;如果是响应时间优先,在1.8以后选择G1,在1.8之前选择ParNew+CMS组合; 3.规划内存需求,只能进行大致的规划。 4.CPU选择,在预算之内性能越高越好; 5.根据实际情况设置升级年龄,最大年龄为15; 6.设定日志参数
  • 判断垃圾 引用计数法:当对象被使用时计数+1,被释放时-1,为0时可被回收;无法判断循环调用。 可达性分析法:从对象到gcroot(常量或活跃线程引用对象)之间没有一条完整的数据链,说明可回收。
  • 清理算法 标记-清理:可达性分析将存活对象标记,遍历清除无标记对象后,取消所有标记。造成碎片化(不连续,创建大对象时会触发清理)。 复制算法:将存活对象从对象面复制到空闲面,清除时清除对象面所有对象。适用与存活率低的新生代。 标记-整理:将存活对象整理到一段,清理时清除端外所有。移动成本高,适用与存活率高的老年代。 分代回收: minorGc:新生代(1/3)复制算法回收,对象创建再eden区(占新生代8/10),将存活对象复制到from(占新生代1/10)区并年龄+1,清除其他区, 再次创建后,将存活对象以及from区对象复制到新区中并年龄+1,清除其他区,这个区成为新的from区,原from称为to区。 fullGc:老年代(2/3)标记整理算法回收;速度慢,频率低;触发条件:老年代空间不足;系统调用System.gc() 希望虚拟机执行,但执不执行看虚拟机;成为老年代的对象数量大于老年代剩余空间数量。 *jdk8后无永久代。
  • 其他 *G1收集器:use G1GC *内存泄露:对象由于某种原因无法释放内存。原因:使用单例(生命周期长);资源未关闭。

线程与并发

  • 线程与进程:进程是资源分配的最小单位,一个系统最少一个进程;线程是系统分配的最小单位,一个进程最少一个线程。

  • 线程安全:内存安全,当多个线程访问一个对象时,不需要同步控制,也能返回正确的对象行为。

  • 保证线程安全:使用线程安全的类,拒绝多线程访问同一个变量。

  • 生命周期:线程对象创建后被其他线程调用start(),进入可运行线程池中(就绪状态)等待cpu资源,获取后执行,执行完成或因异常退出了run(),线程结束生命周期。

  • 阻塞:线程由于某种原因放弃cpu使用权暂停。 ①等待阻塞:执行了wait方法,线程释放所有资源进入等待池,可以用别的线程使用notify或notifyAll唤醒。 ②同步阻塞:线程获取对象同步时,同步锁被其他线程占用。进入锁池。 ③其他阻塞:使用了join方法或sleep方法。

  • ThreadLocal:线程本地存储机制,将数据存放在某一线程内部。 底层:通过threadlocalMap实现,每一个thread对象中都有一个threadlocalMap,key为threadlocal对象,值为缓存数据。 泄露:使用完后线程不被回收,对象不被回收; 解决:手动调用threadLocal的remove方法。 *实现处理线程返回值 ①使用while做判断。 ②使用join方法。 ③通过callable接口:futureTask的isdone方法或加入线程池。

  • 线程池:加入线程管理,提高响应速度,有则直接使用,降低资源消耗。 普通方法:反复创建线程开销大,过多的线程会占用太多的内存 好处:加快响应速度,理利用CPU和内存,统一管理 应用场景:服务器接受到大量的请求时,使用线程池技术是非常合适的,它可以大大减少线程的创建和销毁次数,提高服务器的工作效率。需要创建5个以上的线程,建议使用线程池来管理。 | corePoolSize | int | 核心线程数 | | maxPoolSize | int | 最大线程数 | | keepAliveTime | long | 保持存活时间 |unit 空闲线程存活时间单位 keepAliveTime的计量单位 | workQueue | BolckingQuere | 任务存储队列 | | threadFactory | ThreadFactory | 当线程池需要更新时,会使用threadFactory生成新的线程池 | | Handler | RejectedExecutionHandler | 线程池饱和策略,由于线程池无法接受所提交的任务的拒绝策略 | 拒绝时机: 1.当Executor关闭时,提交新任务会被拒绝 2.以及当Executor对最大线程和工作队列容量使用有限边界并且已饱和时 | 策略 | 描述 | | ------------------------ | ------------------------------------------------------------ | | AbortPolicy | 拒绝任务时,会直接抛出一个类型为RejectedExecutionException 的 RuntimeException,让你感知到任务被拒绝了,于是你便可以根据业务逻辑选择重试或者放弃提交等策略。 | | DiscardPolicy | 是当任务提交时直接将刚提交的任务丢弃,而且不会给与任何提示通知,所以这种策略使用要慎重,因为有一定的风险,对我们来说根本不知道提交的任务有没有被丢弃 | | DiscardOldestPolicy | 丢弃队列中最靠前的任务,也就是存活时间最久的,并执行当前任务 | | CallerRunsPolicy | 这种策略算是最完善的相对于其他三个,当线程池无能力处理当前任务时,会将这个任务的执行权交予提交任务的线程来执行,也就是谁提交谁负责,这样的话提交的任务就不会被丢弃而造成业务损失,同时这种谁提交谁负责的策略必须让提交线程来负责执行,如果任务比较耗时,那么这段时间内提交任务的线程也会处于忙碌状态而无法继续提交任务,这样也就减缓了任务的提交速度,这相当于一个负反馈。也有利于线程池中的线程来消化任务 | | RejectedExecutionHandler | 或实现RejectedExecutionHandler接口的自定义handler | *线程池状态:接收处理;不接受不处理排队任务;不接收处理排队任务; 所有任务都已终止进入tiding(taiding 整齐)状态,执行terminate(停止 钩子方法由抽象类声明并且实现,子类也可以选择加以扩展)方法;terminate执行完成;

  • 并发 原子性:一个操作中Cpu不能暂停,要么执行完要么不执行。 可见性:多个线程访问一个变量时,其中一个线程修改了变量,其他线程可见。 有序性:更改代码顺序对执行结果不影响。可能造成线程不安全。 锁原因:缺一不可 ①一个资源每次只能被一个线程使用。 ②阻塞时,不释放已占有资源。 ③已占有资源在完成前被抢。 造成死锁:几个线程头尾相接循环等待资源。 解决死锁:注意加锁顺序,设置锁超时时间。 悲观锁是将资源锁住,等一个之前获得锁的线程释放锁之后,下一个线程才可以访问。 乐观锁采取了一种宽泛的态度,通过某种方式不加锁来处理资源,可以使用版本号version和cas算法实现,性能较悲观锁有很大的提高。乐观锁适用于多读的应用类型,这样可以提高吞吐量。

  • CAS算法:比较交换的意思,它包含 3 个参数 CAS(V,E,N),V表示要更新变量的值,E表示预期值,N表示新值。仅当 V值等于E值时,才会将V的值设为N, 如果V值和E值不同,则说明已经有其他线程做两个更新,则当前线程则什么都不做。最后,CAS 返回当前V的真实值。

  • 同步器 使用: 获取对象锁:synchronized(this);同步非静态方法。 获取类锁:synchronized(类.class);同步静态方法。 原理: 同步方法:通过acc_synchronized关键字对对象加锁,当线程要执行的方法被标记上,需要先获得锁才能执行。 同步代码块:通过monitor enter以及monitor exit执行加锁;monitor enter 先获得锁在执行;monitor exit 先释放锁在执行。 每个对象都有被加锁技术器,不为0获得锁的线程才能重新获取。

  • 其他 sleep:Thread类,不需要synchronized关键字,不释放锁,适用于单线程休眠。 wait:Object类,yilai synchronized关键字,释放锁有进入等待队列,适用于多线程之间通信。 join:造成阻塞。 yeild:释放资源进入等待池,保留cpu使用权。 start:调用start方法会创建一个子线程并启动。 run:thread类的普通启动方法。 thread和runnable:thread是实现runnable接口的类。


基础

  • 数据类型 String:不可变类,引用类型,改变会指向一个新的字符串对象。 StringBuffer:线程安全,单线程效率低。 StringBuilder:线程不安全,效率高。 *线程安全:内存安全,当多个线程访问一个对象时,不需要同步控制,也能返回正确的对象行为。 *保证线程安全:使用线程安全的类,拒绝多线程访问同一个变量。 *不可变类:成员变量被private修饰,没有修改成员变量方法(set),类或方法被final修饰;基本数据类型的包装类都是不可变类。
  • 修饰词 static: ①修饰变量或方法:可以跨代码块访问。 ②修饰类:可以被外部类引用。 ③修饰代码块:只能定义在被定义的类中。 ④修饰包:导入指定包。 final: ①修饰类:不可被继承。 ②修饰方法:不可重写,可以重载。 ③修饰变量:值不可改。 ④修饰类变量:只能在静态代码块中初始化。 ⑤修饰成员变量:只能在非静态代码块中初始化。 ⑥修饰局部变量:由程序员初始化。 ⑦修饰引用数据类型:初始化后不能指向新的对象,值可以改。 ⑧修饰基本数据类型:初始化后值不可改。 *finally:try catch 后执行finally中代码;finalize():清除回收对象。 transient:不持久化某个对象属性。 volatile:修饰字段修改对所有线程可见,不满足原子性,线程不安全。 *原子性:一个操作中Cpu不能暂停,要么执行完要么不执行。
  • 面向对象 继承:从已有类中获得继承信息创建子类,子类有父类的属性以及方法。 封装:将数据以及操作数据的方法定义成接口,操作数据只能通过该定义的接口。(电脑开机键,一键包含了很多操作)。 多态:同一个行为拥有不同的表现形式的能力。(父类动物会叫,子类猫叫喵喵喵,子类狗叫汪汪汪)。 ①编译时多态:重载:发生在同一类中,方法名必须相同,其他不同。 ②运行时多态:重写:发6生在父子类中。方法名参数列表相同,返回值范围以及异常小于等于父类,父类final修饰不可以重写。(只供电,不关心电哪里来)。 抽象:将一类对象的共同特征总结出来,只关注对象的属性与方法。 *抽象类与接口:抽象类单继承,接口多实现,接口只能Public static final。
  • 集合类 List:有顺序,可以重复,可以为null,可以使用getindex或者迭代器获取元素。 Set:无序,不可重复,只能有一个null,只能使用迭代器遍历获取元素。 ArrayList:底层由数组实现,适用于随机查找。 LinkedList:底层由链表实现,适用于插入与删除,额外实现dueue接口(双向队列),可用作队列。 HashSet:计算对象的hashcode来判断对象加入的位置,位置上没有就加入,有则调用equals方法,相同则加入失败,不同加入其他位置。 HashMap:没有synchronized修饰,允许key-value为null,线程不安全。 HashTable:不允许key-value为null,线程安全。 ※HashMap※ ①1.7中hashMap底层为数组+链表,1.8中加入红黑树,提高插入效率。 ②1.7中链表插入使用头插法,1.8为尾插法,插入时需要获取元素个数。 ③1。8中优化哈希算法,节省Cpu资源。 底层实现:数组+链表,1.8后加入红黑树(数组长度达到64,链表高度达到8)。 计算key的哈希值,取模得到数组下标,未产生哈希冲突(下表位置没有元素),直接创建node(1.7entry)插入; 产生哈希冲突则调用equals方法比较,相同则替换,不同则判断是红黑树还是链表再插入。key为null,存在下表为0的位置。 put方法: 计算key的哈希值,取模得到数组下标,未产生哈希冲突(下表位置没有元素),直接创建node(1.7entry)插入; 产生哈希冲突,1.7先判断是否需要扩容,在将entry对象插入。1.8判断是红黑树节点还是链表节点,插入后判断是否需要扩容,不需要则结束put方法。 扩容: ①新建数组 ②遍历老数组每个位置上元素 ③根据元素的key计算出新数组下标 ④将元素放入新数组 ⑤将新数组赋值给HashMap的table属性(哈希表)。 *1.8不同:在遍历时是红黑树节点的还需要在获取红黑树的元素个数,来判断以链表节点扩容还是红黑树节点扩容。 ※※※※※※※ 1.5其他 object类中方法:equals(),wait(),clone(),notify(),notify()。 ==:比较变量的值是否相等 基本数据类型比较值是否相等,引用类型比较对象的地址是否相同。 equals():用于比较对象的内容是否相同。 hashcode():返回对象在内存中的地址值(int)。 for循环指定从哪里开始更快,foreach基于迭代器 更简洁

网络

  • OSI七层模型: 自上而下,应用层(文件传输)、表示层(文件加密)、会话层(管理会话)、传输层(提供端与端的接口)、网络层(选择路由包)、数据链路层、物理层(将数据通过电缆或以太网的方式转换成比特流在网络中), 到达指定位置后再自下而上解析。
  • 三次握手:服务器B创建TCB(控制域)表示可接受连接请求,客户A向服务器B发出连接请求报文(携带ack,req等信息),进入请求已发送状态(第一次);服务器B同意后发出确认报文进入已接收状态(第二次); 客户A在收到同意报文后还需要在发送一次确认,后进入已连接状态(第三次)。 首次握手隐患:发送连接请求后服务端掉线一直重试 解决:使用tcp—cookies。 建立连接后客户端故障: 解决:保活报文。
  • 四次挥手: 客户端发送finsh报文;服务端收到反馈;服务端将未传完数据给到客户;客户端收到反馈。