Java
2020-11-11 15:04:43 88 举报
AI智能生成
Java复习指南
作者其他创作
大纲/内容
网络通讯
UDP
面向无连接,即不可靠传输
支持一对一,一对多,多对多,多对一
发送UDP报文,协议首部小
性格高但可靠性低
TCP
需要建立连接,可靠传输
三次握手和四次挥手
仅支持一对一
通道发送字节流,首部大
IO
BIO
传统阻塞式IO,有操作系统进程请求IO后阻塞等待操作系统调度,当IO发出中断请求后,操作系统再重新调度请求的进程。
NIO
select
原理
进程请求IO后可以与操作系统的建立一个等待IO的socket,同时将需要的文件描述符加入到fd_set(最大1024)中,当IO就绪后,操作系统通过select来通知进程IO状态,一个进程可以请求多个IO。当一个IO就绪时,操作系统需要遍历socket来通知请求这个IO的进程恢复状态,同时进程需要遍历整个fd_set来获取到需要的文件描述符
缺点
当请求IO时需要将文件描述符加入到fd_set,并且受限于最大1024个
IO就绪后操作系统需要遍历socket通知需要的进程
进程被操作系统调度唤醒后需要遍历fd_set来获得需要的IO文件描述符
poll
请求的最大文件描述符fd_set不再限制于1024
epoll
进程请求IO后不再放入到fd_set,取而存放到操作系统提供的一个列表中
当IO就绪后会将这个文件描述符加入到ready集合中,当进程被唤醒后仅需遍历ready集合即可
使用mmap()直接提供给用户态内存地址的引用,从而加速内存复制
这个适合于建立的socket连接少并且大部分请求IO都不活跃情况
Http/Https
基础,包括请求方法,状态码等
Http
通过TCP建立的无状态连接,明文传输
协议端口80
Https
Http+SSL建立的安全连接,加密传输
协议端口443
报文结构
设计模式
工厂
对于某些复杂的类,可以将其封装成工厂,对外隐藏复杂的创建逻辑
责任链
讲某些需要执行链式操作的组成一个责任链,使用时直接按顺序链式调用
装饰器
在保留原有类的基础上需要扩展类的功能,新建Decorator抽象类并将原有类作为入参传递,在装饰类中增加功能
建造者
当创建一个类时,某些配置项可能需要经常调整变动,使用建造者模式可以根据不同的配置进行build
观察者
当一个对象会因为另一个对象的行为而做出不同的行为,类似监听状态,则可以将监听者加入到被监听者维护的观察列表中,在需要的时候遍历观察者列表发送通知
策略
旨在解决多重if的业务逻辑,根据不同策略名选择不同的处理实现类
单例
当某一个类仅需要创建一个对象时可以使用单例模式,分为懒汉和饿汉,懒汉需要使用DLC确保唯一
pipeline
适用于一个复杂的业务,可以使用pipeline流式流程,各个Pipeline处理各个流程,Context作为状态承载者
代理
对某一类需要做增强(前置,后置)等可以采用代理实现
mysql
数据类型
int指定的长度仅仅是显示的参考长度,与数据实际存储占用的大小无关,实际存储都是4B
sql执行流程
常用引擎
innodb
myisam
高性能
表设计
表结构
索引设计
高性能sql
高可用
redis
数据类型
持久化策略
rdb
aof
混合策略
集群策略
主从
哨兵
第三方集群方式
客户端集群
代理集群
cluster集群
重要数据结构
重要算法
应用
分布式锁
布隆过滤器
简单限流
rabbitmq
zookeeper
mongo
算法
集合
ArrayList
线程不安全
扩容与缩容
查询时间复杂度O(1),遍历时间复杂度O(n)
LinkedList
折半查询
HashMap
线程不安全
jdk1.7
采用数组+链表实现,根据key的hash值决定存放的数组的index,
同一个index下存放hash冲突的key-value。
查询时时间复杂度:没有hash冲突O(1),存在hash冲突则会定位到具体的index,再遍历链表O(n)
同一个index下存放hash冲突的key-value。
查询时时间复杂度:没有hash冲突O(1),存在hash冲突则会定位到具体的index,再遍历链表O(n)
采用hashCode决定存放的index,当出现hash冲突时,根据equals()判断是否发生key重复,故单单重写equals()而不重写hashCode是没有意义的
当达到扩容因子(默认0.75)时会触发扩容机制。扩容采用头插法,多线程下头插法可能导致扩容死循环
jdk1.8
采用数组+链表+红黑树,当达到某一阈值(默认节点数>64&&数组length>8将链表转换成红黑树,节点<6转换成链表)
相比较于遍历链表,当出现hash冲突时,红黑树的查询复杂度为O(lgn)
相比较于遍历链表,当出现hash冲突时,红黑树的查询复杂度为O(lgn)
扩容采用尾插法,将原来的链表拆分成两个短链表
LinkedHashMap
一个继承haspMap的有序Map集合,采用数组+双向链表实现,各个entry采用pre,next连接。基于此可以实现简单的LRU
ConcurrentHashMap
线程安全
更新采用CAS操作
jdk1.7
采用数组Segement[]+链表<HashEntry>实现,包含了多个segement(HashTable对象),每个segement独立加锁,segement数量不能扩容
采用lock锁,等待锁时尝试自旋
jdk1.8
采用数组+链表+红黑树实现,每个数组的index独立加锁
采用synchronized锁
IO
字节流
InputStream
FileInputStream
ByteArrayInputStream
OutputStream
FileOutputStream
ByteArrayOutputStream
字符流
Reader
InputStreamReader
FileReader
BufferReader
Writer
OutStreamWriter
FileWriter
BufferWriter
多线程
线程
Java线程的生命周期:线程新建—>就绪—>运行—>阻塞休眠—>唤醒—>结束
Java线程的实现并不受《Java虚拟机规范》制约,因此如何实现Java线程各个JVM是不同的,主流的JVM线程与操作系统线程是一对一的关系,即线程完全交给操作系统去管理和调度
synchronized
jdk1.7
重量级moniter锁,性能不高
jdk1.8
逐渐升级的锁:偏向锁—>自旋锁—>轻量锁—>重量锁
使用对象头的MarkWord存储锁标志位
Lock
AQS
依托于AQS实现的各种锁
与synchronized的区别:1.Java层面的锁,利于控制锁粒度2.synchronized是非公平锁,而lock可以自定义
volatile
JMM模型
工作内存与主存的交互
可见性
MESI协议,总线风暴
有序性
指定重排
指定重排
Autmic类依托于此实现
ThreadLocal
以线程私有变量来保证线程安全
内存泄露问题
每个线程维护一份ThreadLocalMap threadLocals,其中存放了Entry<K,V>[],其key为ThreadLocal对象,值为value,key是对ThreadLocal对象的弱引用,因此当ThreadLocal对象为null时,key将被回收,但是value会被保留,只要Thread对象不被释放,这个Entry<K,V>就会无法被释放
线程池
初始化的主要参数
当任务到达时,执行顺序:使用空闲核心线程执行—>加入到等待队列—>创建新非核心线程执行—>拒绝策略
因此注意:当等待队列无界时,设置非核心线程大小并没有意义
如何解决线程安全问题
将共享变量转变为局部变量,不被其他线程共享
ThreadLocal,每个线程各操作各自的副本,互不干扰
变量搞成final,仅允许读取,拒绝写入
加锁控制访问
线程之间通讯
wait/notify机制
Object.wait()和Object.notify() 使线程释放锁并进入休眠状态
Condition
Condition.await()和Condition.signal() 使线程释放锁并进入休眠状态
管道
PipedInputStream和PipedOutStream可以通过管道使得线程之间通信
join
调用join对象的wait方法,加入抢占锁队列,线程执行完退出的时候调用nofifyAll()释放锁,返回调用join的线程
JVM
Java内存模型
堆
存放所有的Java对象,使用指针保留对该对象的引用,线程共享
栈
线程私有空间,保存线程运行期间的线程桢栈,包括:局部变量表,出口引用,异常表,操作数栈,动态链接
本地方法栈
类似于栈,但是是为native方法服务的
方法区
存放被虚拟机加载的类信息,静态,常量数据,线程共享
程序计数器
线程私有空间,用于指向CPU执行的代码位置,所有的程序跳转(switch,if等)都依托于此实现
类加载过程
加载过程
加载
根据类的全限定名词加载二进制字节流
加载二进制字节流中的静态数据结构为运行时常量池
在方法区生成class对象并将其作为访问入口
连接
验证
对二进制文件进行格式,语义,安全性校验
准备
在方法区分配内容并赋初值(如果不是static final则为零值)
解析
将常量池的符号引用转换为直接引用
初始化
初始化静态变量和静态代码块
使用
创建对象过程
卸载
类卸载是后来才引入的,JVM规范中甚至没有要求方法区需要进行GC。而类卸载本身要求就比较苛刻:类的所有对象已被回收,该类不再被引用且加载该类的类加载器已经被回收
双亲委派机制
用户自定义加载器:应用类加载器:扩展类加载器:启动类加载器
当一个加载器加载时,首先委托给父类加载,只有当父类反馈无法加载时,才会尝试自己去加载
用于防止同包同名类冲突
破坏双亲委派机制
继承ClassLoader重写 用户自定义加载器的loadClass(),直接跳过父类而自己加载
在父类加载时请求子类去加载
SPI机制
应用:加载JDBC驱动
自己实现类的加载而不去继承ClassLoader
OSGi
应用:OSGi Bundle类的热部署
GC
分代理论
当发生GC时,回收整个JVM效率是非常低的,因此有了分代收集,而分代收集是建立在分代理论基础上的。
存活多次GC而不被回收的对象很难被回收
绝大多数对象总是朝生夕灭的
跨代引用发生频率是很低的
对象已死?
可达性分析算法
GC Root:栈,本地方法栈,方法区常静量的指针等
由GCRoot出发,一旦某个对象不可达,即为需要回收的对象
引用计数算法
当一个对象被引用时计数+1,任何时刻被引用次数为0,则该对象可以被回收
无法解决循环引用的问题
GC策略
标记—清除
简单快速
GC后存在内存碎片
标记—复制
GC后空间连续
需要为GC预留可用空间,空间利用率低
复制比清除代价大
一旦预留空间无法存放GC后剩余对象,需要进行担保操作
复制操作更新引用实现复杂
标记—整理
GC后空间连续
不需要预留空间
移动比清除代价大
移动和更新引用实现复杂
主流GC算法
Serial
ParNew
CMS
G1
ZGC
Spring
Spring IOC
BeanDefinition接口
Bean封装的接口,主要实现类GenericBeanDefinition,RootBeanDefinition
AbstractRefreshableConfigApplicationContext上下文
使用AbstractBeanDefinitionReader来读取和解析beanDefition
三级缓存
一级用于存放初始化完成的bean
二级用于存放创建中的bean
三级用于存放获取增强后的bean的factory
bean的生命周期
实例化前postProcessBeforeInstantiation
实例化
实例化后postProcessAfterInstantiation
初始化前postProcessBeforeInitialization
init-method
初始化后postProcessAfterInitialization
使用
destory-method
Spring AOP
AOP实现方式
主要采用加载时织入,即在loadClass()时修改class文件,对其进行增强
在Java读取到class字节数组后,jvm加载class前对其增强
在jvm得到class的字节数组后,采用Instrumentation(字节码转换器)对其增强
还可以在编译时植入,在编译class时增强
Spring Aop
加载AOP配置后在bean的beanpostprocessor阶段做增强,此时需要aop的target对象被拦截,替换为proxy对象
Spring ORM
Mybatis
SpringBoot中使用MybatisAutoConfiguration注入SqlSessionFactory,其通过使用SqlSessionFactoryBean工厂来创建SqlSessionFactory实例
使用动态代理技术对mapper接口进行代理
JDK
需要实现接口
Cglib
通过创建子类实现
使用SqlSessionFactory来创建SqlSession连接对象,Mybatis中采用DefaultSqlSession实现类通过Exctor实现sql操作,springboot中采用SqlSessionTemplate调用代理对象实现sql操作
SqlSession线程不安全,故它是不能够线程共享的
Spring中的SqlSession需要多例,或者是实现线程隔离
默认情况下Exector为SimpleExecutor,最后用CachingExector封装,即使用mybatis的一级缓存的Exector
Mybatis一级缓存与二级缓存可以并存
一级缓存无法关闭,存在于每个SqlSession,执行CUD后会执行清空操作
二级缓存默认不开启,存在于SqlSessionFactory级别,可以创建并使用其他cache框架
SpringCloud
服务治理
主要是管理所有服务的IP,用于相互调用。服务提供者在注册到注册中心时会通知注册中心,同时会定时发送心跳。一旦注册中心长时间收不到心跳,则会将该服务移出服务列表。
Eureka AP
一旦某服务因网络原因被注册中心移除,重连后将不会再加入到注册中心的服务列表,故Eureka存在保护机制,只有当相当长时间无法获得心跳才会移出列表
多个Eureka集群通过相互注册的原理来实现注册中心的高可用
Zookeeper CP
客户端负载均衡
Feign主要依托于Ribbon实现,调用某个服务时,去注册中心fetch到所有的可用ip列表,然后在本地通过负载均衡选择一个去调用
注意与Nginx的服务端负载均衡区分
负载均衡采用的策略可以自由配置
服务调用
RestTemplate
基于Ribbon的服务调用
FeignClient
Ribbon+Hystrix的服务调用
服务保护
降级
为降低系统负荷而对于某些非核心服务采用降级,当请求超过一定时限后直接返回一个fallback
熔断
当请求因为某些原因出现错误或者超时,直接返回fallback,以降低对服务的压力
隔离
对于高并发的请求使用独立的线程池,以防止高并发请求占用线程池而导致调用其他接口的请求被阻塞甚至不可用(雪崩)
网关
Zuul
Java语言开发,很容易集成到项目中,对请求做处理等,适合近应用层网关
Nginx
性能高,适合最外层网关
分布式配置中心
Spring Config
没有界面,操作不够人性化
依托于git实现
配置更新的时候需要使用SpringBus更新
Apollo
界面化操作,使用方便
使用ApolloServer与ApolloClient实现
在配置更新的时候Client直接更新JVM变量值
消息总线
0 条评论
下一页