java
2019-08-01 14:24:07 11 举报
AI智能生成
java学习笔记
作者其他创作
大纲/内容
jvm
内存模型
公有部分
堆:对象的内存分配
年轻代
Eden 区域
from 区域
to 区域
老年代
对象创建:类加载检查>>分配内存>>初始化零值>>设置对象头>>执行 init 方法
对象内存布局
对象头
实例数据
对齐填充
对象的访问定位
直接指针
使用句柄
方法区:存储了每一个类的结构信息
直接内存
元空间:使用的是直接内存
常量池
线程私有
虚拟机栈:栈帧
局部变量表
操作数栈
动态链接
方法出口信息
本地方法栈
程序计数器
类加载机制
加载
验证
准备
解析
初始化
使用
卸载
命令
jstack:查看堆栈信息
gc
如果判断为垃圾
引用计数法
可达性
垃圾回收算法
标记清除算法
复制算法
标记压缩算法
分代收集
新生代:复制算法
老年代:标记-清除或标记-整理算法
垃圾回收器
串行回收器:单线程进行垃圾回收
新生代串行回收器
老年代串行回收器
并行回收器:多线程进行垃圾回收
新生代 ParNew 回收器
新生代 Parallel GC 回收器
老年代 ParallelOldGC 回收器
CMS 回收器
G1 回收器
垃圾回收类型
Minor GC,也称Young GC
Major G,也称Old GC
Full GC:清理整个堆空间
显示调用System.gc
老年代空间不足
Stop-The-World:全世界暂停,只进行垃圾回收
引用
强引用
软引用(SoftReference):内存不足回收
弱引用(WeakReference):下次垃圾回收时回收
虚引用:不能通过它访问对象,监控对象的创建和销毁。
编译器
前端编译器:源代码到字节码
JIT 编译器:编译技术,从字节码到机器码
AOT 编译器:源代码到机器码
JMM
概念
屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果,
定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节
final变量
一旦初始化完成后,就会立刻写入主内存,所有的线程不需要同步就能知道该变量的值
特性
可见性
原子性
有序性
内存屏障
用来禁止处理器指令发生重排序,保证底层操作的有序性和可见性
内存屏障是指插入两个cpu指令之间的一种指令
常见的屏障
LoadLoad屏障
后续的load以及读取操作要保证前一个load读取的数据读取完毕
StoreStore屏障
后面的store操作执行前,保证前一个store操作对其他处理器可见
LoadStore屏障
在后面的store以及后续的写入操作之前,保证之前的load操作要读取的数据被读取完毕
StoreLoad屏障(开销最大,万能屏障)
在后续的load以及后续的读取操作之前,保证前面的store的写入对所有处理器可见
happens-before
A操作 happens-beforeB操作:A操作的操作结果对B操作可见
mysql
索引
概念:索引是帮助高效获取数据的数据结构
前缀索引
哈希索引
单列索引/组合索引
bTree索引
聚簇索引:存储了整行数据
非聚簇索引(辅助索引):存储了主键的值
覆盖索引:直接取到了索引中的值,所以不需要回表
匹配原则
最左前缀原则
哈希索引和bTree索引区别
哈希索引不支持排序,范围查询
哈希索引不支持多列联合索引的最左匹配规则
哈希索引存在哈希碰撞问题
锁
行级锁:粒度最小,并发高
表锁
MVCC:多版本并发控制
只适用于Msyql隔离级别中的读已提交(Read committed)和可重复读(Repeatable Read)
悲观锁:适合多写场景
乐观锁:适合多读场景
版本号
CAS算法
读写锁
排他锁(X锁,写锁):如果事务T对数据A加上排他锁后,则其他事务不能再对A加任任何类型的封锁。获取排他锁的事务既能读数据,又能修改数据
共享锁(S锁,读锁):如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁。获取共享锁的事务只能读数据,不能修改数据
读读不阻塞,读写阻塞,写写阻塞
Next-key Lock: 锁定索引项本身和索引范围。可解决幻读问题
Record Lock:记录锁:对索引项加锁,锁定符合条件的行。其他事务不能修改和删除加锁项
Gap Lock: 间隙锁:对索引项之间的“间隙”加锁,锁定记录的范围(对第一条记录前的间隙或最后一条将记录后的间隙加锁)
,不包含索引项本身。其他事务不能在锁范围内插入数据,这样就防止了别的事务新增幻影行
,不包含索引项本身。其他事务不能在锁范围内插入数据,这样就防止了别的事务新增幻影行
读写分离
延时怎么办
sem-sync:半同步
并行复制
实时性要求高的强制走主库
写完加缓存
基础
事务
什么是事务?
一组原子性的sql操作,要么全部成功,全部失败。
四大特性(ACID)
atomicity,原子性:不可分割的最小工作单元,一个事务中的所有操作要么全部提交成功,要么全部失败回滚。
consistency,一致性:一次事务需要保证数据库在操作后依然处于数据一致性的状态。
isolation,隔离性:一个事务的提交之前,对于其他事务是不可见的。
durability,持久性:事务一旦提交,所做的修改就会永久的保存到数据库中(但是没有绝对的持久性,分很多的级别)
隔离级别
读未提交:READ-UNCOMMITTED
读提交:READ-COMMITTED
可重复读:REPEATABLE-READ(默认)
串行化:SERIALIZABLE
引擎
InnoDB
MyISAM
InnoDB和MyISAM区别
锁:InnoDB行锁和表锁都支持,默认行级锁,MyISAM只支持表锁
事务:InnoDB支持,MyISAM不支持
外键:InnoDB支持,MyISAM不支持
MVCC:仅InnoDB支持
mq
为什么使用
解耦
异步
削峰
有什么缺点
系统可用性降低,mq挂了,别的接口都挂了
复杂性增高,消息丢失?顺序乱了?重复发送?
一致性问题,异步执行失败了
消息传递路径更长,延时会增加
上游无法知道下游的执行结果
常见问题
可靠性
1. rebittmq:发送时:confirm 发送成功,回调
2. kafka follower 同步成功,才返回成功
2. kafka follower 同步成功,才返回成功
数据持久化
持久化到数据库
本地:如kahadb
接收方:关闭自动确认,手动确认
发送端
幂等性
保证接收端处理消息的业务逻辑具有幂等性
保证消息具有唯一编号,并使用一张日志表来记录已经消费的消息编号。
顺序性
rebitmq:每个 queue 一个 consumer
kafka:指定key写到一个partiton
多线程:对key,进行hash,放到内存队列,保证顺序
多线程:对key,进行hash,放到内存队列,保证顺序
rocketMq: 数据取模放到 messagequeue 里面,
消费者消费同一个 messagequeue
消费者消费同一个 messagequeue
消息挤压:消费后不落库,写到新的30个partition
消息过期丢失:手动写程序重新补消息
磁盘快满:快速消费写到其它mq
消息过期丢失:手动写程序重新补消息
磁盘快满:快速消费写到其它mq
延时消息:环形队列
概念
jms
模型
点对点:消息生产者向消息队列中发送了一个消息之后,只能被一个消费者消费一次。
发布/订阅
点对点:消息生产者向消息队列中发送了一个消息之后,只能被一个消费者消费一次。
发布/订阅
AMQP
activemq
持久化
kahadb(默认)
jdbc:createTablesOnStartup 设置false
AMQ方式:只适用于 5.3 版本之前,不推荐使用
死信队列:消息过期后,默认会将失效消息保存到“死信队列(ActiveMQ.DLQ)
Consumer
手动确认,保证消息一定被消费
主从:用zk做选举
shared nothing master-slave:每一个broker(包括master和slave)都有自己的消息存储区
shared storage master-slave:共用存储
rabbitmq
erlang语言 高并发 定制化开发比较困难
集群
普通集群
镜像集群
rocketmq
阿里出品 分布式结构
kafka
功能不是很丰富,主要使用在大数据领域 分布式架构
并发
锁基础
CAS
比较,交换,用unsafe类
缺点
只能保证一个共享变量的原子操作
循环时间长,开销大
ABA问题:用AtomicStampReference解决
AQS
锁
volatitle
禁止指令重排序:编译期生成字节码时,会在指令序列中增加内存屏障
线程立即可见
不保证原子性
常用的锁
synchronized:异常自动解锁,是非公平锁,可重入,不要锁字符串,字符串常量池公用,容易造成死锁
ReentranLock:重入锁(递归锁)
ReadWriteLock:读写锁:读锁可以重复获取,但读写锁之间互斥
synchronized和ReentranLock比较
实现:synchronized 是 JVM 实现的,而 ReentrantLock 是 JDK 实现的
性能:新版本 Java 对 synchronized 进行了很多优化,例如自旋锁等,synchronized 与 ReentrantLock 大致相同
等待可中断:ReentrantLock 可中断,而 synchronized 不行
公平锁:synchronized 中的锁是非公平的,ReentrantLock 默认情况下也是非公平的,但是也可以是公平的
锁绑定多个条件:一个 ReentrantLock 可以同时绑定多个 Condition 对象
异常:异常时synchronized会自动解锁,ReentrantLock不会
锁控制
CountDownLatch:闭锁:倒计数器,常用来判断线程池是否执行完毕
CyclicBarrier:循环屏障:只有当多个线程都到达时,这些线程才会继续执行
Semaphore:信号量,可以控制对互斥资源的访问线程数。
锁的类型
自旋锁:当一个线程在获取锁的时候,如果锁已经被其它线程获取,
那么该线程将循环方式去获取锁
那么该线程将循环方式去获取锁
缺点:循环消耗cpu
公平/非公平锁
公平锁:按等待顺序获取锁是公平锁
非公评锁:吞吐量高
可重入锁/不可重入锁
独占锁:锁只能被一个线程持有
共享锁:可以被多个线程持有
乐观/悲观
悲观锁
每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁
传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现
Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现
乐观锁
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,
但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现
但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现
乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,
其实都是提供的乐观锁。在Java中一种实现方式是CAS
其实都是提供的乐观锁。在Java中一种实现方式是CAS
锁优化
自旋锁:避免进入阻塞状态从而减少开销
锁消除:锁消除是指对于被检测出不可能存在竞争的共享数据的锁进行消除
锁粗化:如果一系列的连续操作都对同一个对象反复加锁和解锁
频繁的加锁操作就会导致性能损耗,只在最外面加一次就可以了
频繁的加锁操作就会导致性能损耗,只在最外面加一次就可以了
轻量级锁
偏向锁:偏向锁的思想是偏向于让第一个获取锁对象的线程,这个线程在之后获取该锁就不再需要进行同步操作,甚至连 CAS 操作也不再需要
锁的状态
无锁状态(unlocked)
偏向锁状态(biasble):只有一个线程进入临界区
轻量级锁状态(lightweight locked):多个线程交替进入临界区
重量级锁状态(inflated):多个线程同时进入临界区
并发容器
CopyOnWriteArrayList:写加锁,读不加锁
队列
操作
阻塞队列
ArrayBlockingQueue:数组,有界,加锁,默认非公平
LinkedBlockingQueue:单向链表,无界(可设置大小),加锁
PriorityBlockingQueue:优先队列,二叉堆,无界,加锁,
SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态
DelayQueue:延迟消费,无界,底层基于优先队列
非阻塞队列:ConcurrentLinkedQueue:链表,无界,cas
map
ConcurrentSkipListMap:跳表
ConcurrentHashMap:哈希表
原子类
线程
如何开一个线程
继承Thread类
实现Runnable接口
实现Callable接口,可以用返回值,用FutureTask封装,可以阻塞
线程池
newCachedThreadPool
缓存线程池:内部使用 SynchronousQueue
newFixedThreadPool:定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
newSingleThreadExecutor:单线程化的线程池
常用方法
shutdown:等待线程都执行完毕之后再关闭
shutdownNow:相当于调用每个线程的 interrupt() 方法
future.cancel(true):中断一个线程
参数
corePoolSize:核心线程数
maximumPoolSize:线程池中允许的最大线程数,也就是最大并发线程数
handler:饱和策略,当阻塞队列满了,且没有空闲的工作线程
守护线程
守护线程是程序运行时在后台提供服务的线程,不属于程序中不可或缺的部分。
当所有非守护线程结束时,程序也就终止,同时会杀死所有守护线程。
使用 setDaemon() 方法将一个线程设置为守护线程
当所有非守护线程结束时,程序也就终止,同时会杀死所有守护线程。
使用 setDaemon() 方法将一个线程设置为守护线程
常用方法
sleep休眠,不释放锁
sleep() 和 wait() 区别
yield:建议具有相同优先级的其它线程可以运行
interrupt:中断线程:不能中断 I/O 阻塞和 synchronized 锁阻塞
join:在线程中调用另一个线程的 join() 方法,会将当前线程挂起,而不是忙等待,直到目标线程结束。
wait() notify() notifyAll() :
wait:线程挂起,等待其它线程调用 notify() 或者 notifyAll()唤醒
它们都属于 Object 的一部分,而不属于 Thread
只能用在同步方法或者同步控制块中使用,否则会在运行时抛出 IllegalMonitorStateException。
使用 wait() 挂起期间,线程会释放锁。这是因为,如果没有释放锁,那么其它线程就无法进入对象的同步方法或者同步控制块中,
那么就无法执行 notify() 或者 notifyAll() 来唤醒挂起的线程,造成死锁
那么就无法执行 notify() 或者 notifyAll() 来唤醒挂起的线程,造成死锁
Condition:await() signal() signalAll()
FutureTask:用做任务执行,可以用返回值
线程中断
并不会使线程立刻退出,而是线程一个通知,具体如何处理,由需要被停止的线程自行决定
中段线程
Thread.interrupt()
线程是否被中断
Thread.isInterrupted()
线程是否被中断,并且清除当前中断状态
Thread.interruptted
sleep方法因为中断会抛出异常,并且会清除中断标记,所以需要在异常处理中再次进行中断
状态
新建:NEW ,刚new出来对象
可执行状态:RUNNABLE:调用 start 方法,等待cpu调度
运行:RUNNING
阻塞:BLOCKED
终止:TERMINATED
基础
NIO
特性
基于通道
非阻塞
channle:通道
DatagramChannel
SocketChannel
FileChannel
ServerSocketChannel
buffer:缓冲区
selector:选择器:单个线程处理多个通道
简介
spring
bean生命周期
实例化
设置对象属性
Aware接口
BeanPostProcessor前置处理-postProcessBeforeInitialization:在容器中的Bean初始化之前执行
@PostConstruct
初始化方法
实现InitializingBean接口:afterPropertiesSet方法
配置文件指定init-method
BeanPostProcessor后置处理-postProcessAfterInitialization:在容器中的Bean初始化之后
@PreDestroy
destroy-method
配置文件指定init-method
实现DisposableBean接口:destroy方法
分布式
服务治理
链路追踪
监控:访问压力,时长等
降级
分布式会话
tomcate+redis
spring session+redis
JWT
分布式事务
XA:两阶段提交:用事务管理,效率低,不适用互联网场景
TCC:补偿方案
try
confirm
cancel
要自己写补偿机制
本地消息表
可靠协议最终一致性方案
分库分表
数据库中间件
中间件代理:proxy:有:mycat,Atlas
client:Sharding-JDBC
数据迁移
停机迁移
原表和分表同时写,用迁移工具迁移
id生成
弄一张表专门生成id:并发量低
uuid:无序,当主键性能低
snowflake算法
基础
CAP
C:强一致性
A:可用性
P:分区容错性
CP:ZK
AP:eureka
BASE
一致性哈希算法
常见问题
接口幂等性
接口顺序性
分布式锁,每个接口有顺序号,可以用mq异步处理
hash到一台服务器,放到一个队列里
常用框架
dubbo
负载均衡
随机
轮训
最少活跃
一致性哈希
spi
服务降级
springcloud
eureka:注册中心
ribbon:负载均衡
feign:声明式服务调用
Hystrix:熔断器
熔断:服务端做
降级:客户端做
服务监控:hystrixDashboard
zuul:网关
zookeeper
注册中心
分布式锁
用临时节点做主从切换
分布式协调
分布式锁
zk
redis
redis
基础
为什么要用:高性能,高并发
为什么这么快
纯内存
非阻塞IO多路复用
单线程,避免多线程频繁上下文切换
redis和memcached区别
线程模型:文件事件处理器:io多路复用
这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路
I/O
I/O
数据类型
字符串
列表:跳跃表
集合
散列表:维护两个散列表,渐进扩容
有序集合
过期删除
定期删除:每一段时间,扫描删除
惰性删除:访问时发现过期,进行删除
快满了,走内存淘汰机制,有多种回收策略可选
持久化
RDB:快照存储
AOF:追加命令的方式
如何选择
架构
哨兵
读写分离:主从架构
master一定要持久化
不然重启丢失数据,主从复制后,slave数据全部清空
不然重启丢失数据,主从复制后,slave数据全部清空
slave过期key:master过期时模拟发过来一个del命令
无磁盘化复制
主从复制断点续传
常见问题
异步复制,宕机,数据丢失:设置参数,多少秒异步复制延迟,master不在接收写请求
并发竞争
分布式锁+时间戳
数据结构
数组
链表
栈
队列
哈希表
二叉树
二叉搜索树
跳表:建索引的方式,时间复杂度都是O(logN)
设计模式
单例模式
饿汉:静态常量,线程安全
饿汉:静态代码块,线程安全
懒汉:非空校验,线程不安全
懒汉:方法加同步锁,线程安全
懒汉:静态内部类,线程安全
双重检查锁,线程安全
枚举,线程安全
工厂模式
简单工厂模式:静态方法创建产品
工厂方法模式:一个工厂创建一个产品
抽象工厂模式:一个工厂创建一类产品
网络
应用层
传输层
TCP:传输控制协议 TCP(Transmission Control Protocol)
--提供面向连接的,可靠的数据传输服务。
--提供面向连接的,可靠的数据传输服务。
三次握手
四次挥手
UDP:用户数据协议 UDP(User Datagram Protocol)
--提供无连接的,尽最大努力的数据传输服务(不保证数据传输的可靠性)
--提供无连接的,尽最大努力的数据传输服务(不保证数据传输的可靠性)
网络层
数据链路层
物理层
linux
IO多路复用函数
select:无差别轮询复杂度,时间复杂度O(n)
poll:没最大连接数限制,时间复杂度O(n)
epoll:时间驱动,时间复杂度O(1)
子主题
0 条评论
下一页