java资料全套思维导图
2023-09-22 23:46:40 2 举报
AI智能生成
个人总结最全面的java资料全套
作者其他创作
大纲/内容
管理工具
git
snv
togit
maven
项目部署
tomcat
子主题 1
子主题 2
windos
linux
服务器查看日志
jenlins
通讯协议
rpc
子主题 1
http
数据库
mysql
重要sql
统计总数(不存在的统计为0)
SELECT A.`name`,COUNT(B.p_id) from A A LEFT JOIN B B on A.p_id=B.p_id GROUP BY A.`name`;
统计总数(求出大于2的总数)
SELECT A.`name`,COUNT(B.p_id) num from A A LEFT JOIN B B on A.p_id=B.p_id GROUP BY A.`name` HAVING num>2;
查询重复的数据
select * from A where `name` in (select A1.`name` from A A1 GROUP BY A1.`name` HAVING COUNT(A1.`name`)>1);
删除重复的数据
DELETE t1 FROM A t1, A t2 WHERE t1.name = t2.name AND t1.id > t2.id;
快速备份表
create table emp_copy like emp
inser into emp_copy select * from emp
根据条件更新新表数据
update a t1,b t2 set t1.`name` = t2.`name`,t1.p_id=t2.p_id where t1.id = t2.id;
删除重复数据只保留最小的一条
delete from user where id not in (select stu.minid from (select min(id) as minid from user group by name) stu)
and name in (select stu.minid from (select `name` as minid from `user` group by name having count(`name`)>1) stu);
and name in (select stu.minid from (select `name` as minid from `user` group by name having count(`name`)>1) stu);
数据库的搜索引擎
索引
子主题
子主题
cassandra
java
运行环境
jdk
java编程思想
对象导论
抽象过程
汇编语言
底层轻微抽象
命令式语言
C、Basic
对汇编的抽象
解决问题时
基于计算机的结构
不会基于需要解决问题的结构
只针对待解决问题建模
世界某些特定视图
list
所有问题最终都是列表
APL
所有问题都是算法形成的
不能解决所有问题
面向对象OOP
表示问题空间元素
不会受限于任何特定类型的问题
每个对象一个接口
类
问题空间元素
接口
确定某一特定元素。所能发出的请求
被隐蔽的具体实现
访问控制
让程序员无法触及他们不该触及的部分
允许类库设计者改变内部分工作方式
关键字
public
任何类
protected
仅继承的类
default
同包下的所有类
private
仅当前类
复用具体实现
组合
现有类 --->新类
极大的灵活性
继承
编译器
继承类
编译时的限制
继承
父类和子类的差异
直接在子类加方法
覆盖方法
是一个与像一个的关系
是一个
继承覆盖父类
纯粹替代
像一个
在子类中添加新的接口元素
伴随多态的和互换对象
特定类型 ---> 父类对象
不能依赖特定类型的代码
函数调用
前期绑定
非面向对象编程
运行代码的绝对地址
后期绑定
面向对象编程
编译器 ---> 确保调用方法的存在
运行时 ---> 计算代码的地址
java编译器
对象中存储信息 ---> 计算方法地址
动态绑定默认的
向上转型
单根继承结构
优点
保证所有对象具有某些功能
极大简化参数传递
容易实现垃圾回收
容器
集合
list
存储序列
map
关联数组
set
无重复组合
泛型
向下转型 ---> Object ---> 具体类型
参数化类型
对象对的创建和生命周期
C++
最求最大运行速度
编写时确定:存储空间和生命周期
存储
堆栈
静态方法区
Java
存储
堆的内存池
逻辑假设
异常处理
错误 ---> 基于编程语言中
java内置异常并强制使用
对象
用引用操控对象
遥控器 (应用) ---> 电视(对象)
创建对象
存储地点
寄存器
处理器的
速度最快
不能直接控制
堆栈
通用RAM中
java对象引用
堆
通用的内存池
java对象
常量存储
程序代码内部
ROM(只读存储器)
非RAM存储
流对象
持久化对象
特例
基本类型
boolean
char
byte
short
int
long
float
double
void
高精度数字
BigInteger
BigDecimal
java中的数组
自动初始化
范围检查
少量内存开销
运行时下标检查
创建新的类型
类成员的基本数据类型初始化
非类字段 --> 不初始化
永远不需要销毁对象
控制执行流程
恰好出现在迭代语句前
continue
继续下一次循环
break
中断循环
continue |abe|
继续循环 到|abe|处
break |abe|
中断循环到 |abe|处
初始化和清理
用构造器确保初始化
作用
确保每个对象初始化
调用构造器,编译器的责任
没有返回值
不是返回void
this
问题
a.peel() 和 b.peel()
怎么知道是a还是b调用的peelfangf
答案
作为第一个参数 --》 peel()
this 所操作对象的引用
类似于Banana.peel(a,1)
清理
特殊内存
Gc仅负责new 出来的对象
本地方法分配的内存,GC无法回收
finalize()
GC前,调用finalize()
GC,回收对象内存
说明
对象可能不被垃圾回收
对象回收只与内存有关
绝对不能直接调用finalize()
对象创建过程
首次创建Dog对象,访问Dog静态方法
java编译器定位Dog.class
java编译器定位Dog.class
载入Dog.class ,静态初始化
new Dog() 时,在堆上分配内存
存储空间清零
基本类型(默认值)
引用(null)
执行字段定义处的初始化条件
执行构造器
初始化
静态初始化
static{ }
首次加载类时执行(即使未生成类对象)
非静态初始化
{ }
生成类对象时执行,匿名内部类的初始化
构造器(最后执行)
枚举类型
enum
编译器行为
特性
toString()
ordinal
特定enum常量声明顺序
values
按顺序生成数组
访问控制权限
为什么控制访问权限
使用户不接触不该接触的部分
更改内部类实现,不影响客户端程序员
关键字
public
protected
继承的类+同包的类
default
同包的类
private
类的访问权限
可以
public
default
不可以
private
protcted
复用类
怎么复用
组合
新类中,产生现有类对象
继承
按照现有类型,进行复用
调用导出类,先加载基类
@Override
确保覆盖,而非重载
代理
继承和组合中庸之道
成员对象
构造的的类中(组合)
在新类中暴露成员对象的所有方法(继承)
在组合与继承之间选择
组合
显式,在新类中放置子对象
复用具体实现,而非接口
继承
隐式,在新类中放置对象
新类 -->基类,复用接口
向上转型
新类是现有类的一种类型
类接口可能丢失方法
final
数据
基本类型
引用
引用所指向对的对象恒定不变
指向对象的内容,可以更改
参数
无法改变参数所指向的对象
方法
防止继承类覆盖
private方法隐式的为final
无法获取,无法覆盖
类
无法被继承
java的final类
基本类型包装类
字符串
String
StringBuffer
StringBuild
数字
Math
StrictMath
系统
System
Calss
多态
对比
多态
分离:消除类型之间的耦合关系
封装
合并:创建新的数据类型
实现隐藏
分离:接口实现 ,将细节私有化
问题
基类的应用,如何找到继承类的方法
答案
编译器不知道对象类型
运行时判断对象类型,找到正确的方法体
准则
继承:表达行为(方法)间对的差异
组合:状态(对象)上的变化
接口
关系
普通类--> 抽象类 ---> 接口
抽象类和普通方法
抽象方法
仅有声明,没有方法体
abstract void f()
抽象类
包含抽象方法的类
编译器阻止实例化
可以不包含抽象方法
阻止创建实例
重构工具
公共方法---> 集成层次向上转移
接口
含义
完全抽象的类
没有任何方法体
域
隐式:static,final
java5之前,创建常量组的工具
不能是空的final
可以被非常量表达式初始化
所有实现特定接口的类,看起来都像这样
类与类之间的协议
作用
完全解耦
忽略继承层次
实现多重继承
接口的组合
为什么使用接口
能向上转型为多个基类型
防止创建该类的对象
接口与工厂
工厂方法
工厂对象
创建方法
生成接口某个实现的对象
好处
代码完全与接口的实现分离
透明的将某个实现,替换成另一个实现
内部类
private内部类
完全阻止依赖于类型的编码
完全隐藏了实现细节
无法访问不属于公共接口的方法
在方法和作用域内对的内部类
为什么需要
实现接口,创建并返回引用
创建类,不希望类公共可用
作用域和普通变量一样
匿名内部类
说明
返回值得生成,表示返回值的类的定义结合在一起
通过new 表达式,自动向上转型为接口的引用
类是匿名的,没有名字
构造器
有参
无参
特点
扩展类or实现接口,不能两者兼备
只能实现一个接口
工厂方法
使用匿名内部类
嵌套类
说明
static内部类对象x外围类对象
不能从嵌套类的对象,访问非静态的外围类对象
接口内部的类
嵌套类 ---> 接口的一部分
接口中的任何东西,都是public和static的
好处
创建公共代码,被所有不同实现共用
为什么需要内部类
入口
内部类对象 --> 访问外围类对象的所有成员
内部类 --->进入外围类的窗口
多重继承
每个内部类,独立继承一个接口的实现
外围类继承层次,对内部类无影响
内部类允许继承多个非接口类型
闭包和回调
回调
对象携带信息,在某一时刻调用初始对象
控制框架
图形用户接口GUI
事件驱动系统
持有对象
容器
用途
编译器X错误---> 容器
Collection
说明
独立元素的序列
槽内只有一个元素
分类
list
ArrayList
按照插入顺序
***便于随机访问
中间插入和移除元素
LinkedList
按照插入顺序
**中间插入和移除元素
便于随机访问
Stack
后进先出
LIFO
set
元素无重复
HashSet
散列函数
查询速度快
TreeSet
红黑树
排序
Queue
先进先出FIFO
并发编程
PriorityQueue
Map
映射表:键值对对象
槽内有两个对象,键和值
迭代器
统一了对容器的访问方式
只能单向移动
foreach隐形包括迭代器
异常
发现错误
编译阶段
运行时
好处
提供一致的错误报告模型
节省代码
正常逻辑---错误逻辑
Throwable
Error
JVM报告系统错误
Exception
编译期检查
RuntimeException
运行时异常
可忽略,防止代码臃肿
try-catch-finally
catch
仅处理匹配的catch子句
派生类对象,可以匹配基类
finally
子句总会执行即使try中有return
基本异常
构造器
默认
字符串参数
用名称代表发生的问题
根类
Throwable
PrintStackTrace()
从方法调用处---> 异常抛出处的方法调用系列
标准错误流
栈低:第一个方法调用
字符串
字符串
String
对象不可变
StringBuffer
非线程安全,可变
StringBuild
线程安全
格式化输出
Format
正则表达式
java
\\d
\\\\
一个\
其他语言
\d
类型信息
类型信息
类型判断
x instanceof Integer
泛化的Class引用
Class
初始化
对静态方法或非常数静态域的首次引用
static final 不初始化
构造器隐式为静态的
常用方法
printInfo()
全限定类型
getInterface()
包含的接口
getSuperClass()
直接基类
newInstance()
创建类
必须有默认构造器
类型信息
Class对象
JVM加载器
RTTI
含义
RunTime Type info
运行时,识别对象类型(多态)
编译时打开和检查class文件
好处
代码只操纵基类的引用
方便扩展程序
反射
运行时加载类
磁盘中文件
网络中一串字节
java.lang.reflect
Field
Method
invoke
Constructor
动态代理
中间人---> 额外的操作
java动态代理
动态代理创建
动态代理方法的调用
所有的调用---》 单一的调用处理器
代码耦合度,超过期望
泛型
引入原因
多态
方法的参数是接口
但是满足特定的接口
泛型
更通用---> 某种不确定的类型
参数化类型(容器类)
泛型
简单泛型
指定容器要持有什么类型
编译器保证类型的正确性
元组类库
一次方法调用,返回多个对象
一个对象 ---> 持有多个对象
泛型接口
生成器,创建对象的类
泛型方法
泛型参数列表
返回值前
尽量使用泛型方法
擦除
在泛型代码内部,无法获取有关泛型参数类型的信息
泛型
具体的类型信息被擦除
边界
泛型的参数类型
设置限制条件
< T extends HasF>
限制为hasF的子类类型
<? extends T >
超类型通配符(参数值下界)
某个特定类的任何基类
<?>
无界通配符
数组
为什么特殊
效率
简单的线性序列
存储和随机访问引用序列
效率最高
类型
保存基本类型
泛型之前的容器不能
优先使用容器
更多的功能
编译器类型检查
效率已经不是问题
Arrays
fill()
填充各个位置
System.arrayCopy()
复制数组
比for循环快很多
equals()
比较整个数组
元素个数
对应位置元素
sort()
排序算法
基本类型
快速排序
引用类型
稳定并排序
对象比较的方式
java.lang.Comparable接口
编写自己的Comparable
比较
当前对象<参数
负数
当前对象=参数
0
当前对象>参数
正数
binarySearch()
排序数组---> 快速查找
容器深入
填充容器
Collections.nCopies()
Collections.addAll()
set和存储顺序
Set
每个元素唯一
元素必须定义eqquals()
HashSet
元素必须定义hashCode()
TreeSet
保证次序的Set,底层为树形结构
元素必须实现Comparable接口
方法
first()
返回容器的第一个元素
last()
返回容器的最末一个元素
返回容器的最末一个元素
subSet(from,to)
Set的子集
headSet(to)
<to的set子集
tailSet(from)
>=from的set子集
LinkedHashSet
内部使用链表维护插入的次序
元素必须定义hashCode()
理解map
实现
HashMap
构造器(调整容器性能)
容量
负载因子
TreeMap
基于红黑树实现
方法
firstKey()
lastKey()
sunMap()
fromKey()
headMap()
tailMap()
LinkedhashMap
取的顺序是插入顺序
WeakHashMap
弱键,允许释放映射所指向的对象
如果映射外没有引用指向键,则键可以被Gc
ConcurrentHashMap
线程安全
不涉及同步加锁
IdentityHashMap
性能
散列码
相对唯一,代表对象的int值
将对象的某些信息转换而成
散列Map,必须实现
equals和hashCode
覆盖equals(),总是同时覆盖hashCode()
hashCode()不需要返回唯一的标识码
equals()方法必须严格判断两个对象是否相同
散列与散列码
Object
hashCode()
使用对象的地址计算散列码
equals()
比较对象的地址
equals()
自反性
对称性
传递性
一致性
理解hashCode()
目的
一个对象查找另一个对象
键对象---》 生成数字(散列码)---》数组下标
bucket:实际散列列表的数组命名
冲突
equals()方法
线性查询
put()
针对键的hashCode(),转换取模
数组的对应位置
null
创建新的LinkedList
非null
list是否有相同元素
有,替换value
没有,添加到list末尾
get()
同put()
覆盖hashCode()
why?
同一对象调用hashCode()--->相同值
hashCode(),处理的是桶位下标
how
不能依赖异变的数据
数据变化---> 不同的散列码
不能具有唯一的对象信息(this)
Apache库自动生成
HashMap性能因子
容量
桶位数
初始容量
创建时拥有的桶位数
尺寸
当前存储的项数
负载因子
尺寸/容量
空表
0
半满表
0.5
>负载因子,容器自动增加容量,再散列
构造器可以指定,默认是0.75
同步控制
自动同步整个容器
synchronizedList()
快速报错
防止多进程同时修改同一容器
持有引用
引用
SoftReference
内存敏感的高速缓存
WeakReference
规范映射,不影响GC
对象的实例可以在程序多处使用,节省空间
PhantomReference
调度回收前的清理工作
WeakHashMap
保存WeakReference
value只保存一份实例,节省存储空间
java 1.0/1.1的容器
Vector
HashTable
Stack
BitSet
IO系统
概述
源端-接收端
文件
控制台
网络连接
通信方式
顺序
随机存取
缓冲
二进制
按字符
换行
按字
File类
表示
特定文件的名称
一个目录下的一组文件的名称
输入和输出
流
有能力产出数据的数据源对象
有能力接收数据的接收端对象
java
输入
InputStream或Reader派生
read()
输出
0utput Stream或Writer派生
write()
叠合多个对象→期望功能
InputStream
作用
表示从不同数据源产生输入的类
途径
字节数组
String对象
文件
管道
Internet连接
类型
ByteArrayInputStream
缓冲区
StringBufferInputStream
String
FilelnputStream
文件读取信息
PipedInputStream
SequenceInputStream
两个或多个InputStream合并为单一
FilterInputStream
抽象类
OutputStream
作用
输出所要去往的目标
目标
字节数组
文件
管道
类型
ByteArrayOutputStream
内存创建缓冲区
所有送往“流”的数据,都放于此
FileOutputStream
信息写至文件
PipedOutputStream
FilterOutputStream
抽象类
添加属性和接口
FilterInputStream从InputStream读取数据
DatalnputStream
BufferedInputStream
LineNumberInputStream
PushbackInputStream
Filter OutputStream向OutputStream写入
DataOutputStream
PrintStream
格式化输出
BufferedOutputStream
Reader和Writer
InputStream和OutputStream
面向字节
8位, byte
Reader和Writer
面向字符
兼容Unicode
信息的来源和去处
InputStream
Reader
适配器
InputStreamReader
OutputStream
Writer
适配器
OutputStreamWriter
FileInputStream
FileReader
FileOutputStream
FileWiter
ByteArrayInputStream
CharArrayReader
ByteArrayOutputStream
CharArrayWriter
PipedInputStream
PipedReader
PipedOutputStream
PipedWriter
I/O的典型使用
缓冲输入文件
基本的文件输出
标准的I/O
标准输入
System.in
未加工的InputStream
标准输出
System.out
PrintStream对象
标准错误
System.in
PrintStream对象
进程控制
java内部--->其他操作系统程序
OsExcuter.command()
传递command字符串
新I/O
jdk1.4
速度提高
通道,缓冲区
修改类
FileInputStream
FileOutputStream
RandomAccessFile
压缩
属于InputStream和OutputStream继承层次
压缩类库按字节方式,不是字符方式
Java档案文件
JAR
Java ARchive
一组文件→单个压缩文件
压缩,传输时间短
向服务器发一次请求
对象序列化
意义
创建对象,程序终止时,保持状态
自动弥补操作系统的差异
方法
实现Serializable接口
对象-->字节序列化
字节序列化-->原来的对象
轻量级持久化
对象必须显示序列化
显示反序列化
支持特性
远程方法调用RMI
存活于其他计算机的对象
像存活于本机一样
java Beans
配置状态信息
方法
序列化
创建OutputStream对象
封装在ObjectOutputStream对象
调用WriterObject() 即可对象序列化
反序列化
在InputStream封装在ObjectInputStream内
调用readerObject()
transient关键字
特定子对象,不想java序列化保存
逐个字段关闭序列化
只能和Serializable配合使用
xml
对象序列化限制
仅是java的解决方案
只有java程序能反序列化这种对象
优点
跨平台
跨语言
Preferences
key -value数据集合
基本类型
字符串
单个字符串长度8k
应用
存储和读取用户的偏好
程序设置项的设置
数据存储位置
不是本地文件
使用合适的系统资源
Windows的注册表
枚举类型
简介
具体值得有限集合
新的类型
作为常规的程序组件使用
基本enum特性
values()
enum实例数组
ordinal()
enum实例在声明时的次序
从0开始
name()
实例声明的名字
像enum添加新方法
定义方法时,enum实例实例序列最后加分号
enum不能被继承,剩下就是普通类
使用接口组织枚举
在接口内部,创建实现该接口的枚举-----枚举分组
常量相关的方法
为enum实例编写方法---不同的行为
注解
并发
并发的多面性
并发方式
进程
操作系统级别
进程相互隔离
线程
java支持
抢占式
更快的执行
多处理器,多个任务---提高吞吐量
运行在单处理器上的程序性能更好
基本线程机制
定义任务
实现Runnable接口,编写run()方法
Thread类
Runnable对象-- Thread构造器
线程调度是非 确定性的
早期JDK不会频繁对时间切片
使用Exector
客户端和任务执行间的间接层
允许管理异步执行的任务,无需显示管理线程的声明周期
shutdown()
防止新任务提交给Exector
当前线程继续允许之前提交的所有任务
newFixedThreadPool
预先执行高昂的线程分配
newCacahedThreadPool
为每一个任务创建一个线程
newSingleThreadPool
多个任务将排队
任务会顺序执行
所有任务使用相同的线程
序列化任务,不需要同步共享资源
从任务中产生返回值
Runnable不返回任何值
实现Callable接口
call()
ExecutorService.submit()调用
Future对象
休眠
sleep
InterruptedException
优先级
线程的重要性---调度器
JDK10个优先级
windows 7个且不固定
礼让
yield()
守护线程
在后台提供通用服务
不是程序中不可或缺的部分
所有非后台线程结束后,会杀死进程的所有后台线程
线程等待当前线程执行
join()
共享受限资源
不正确的访问资源
解决共享资源竞争
why?
不清楚线程何时运行
对资源加锁
序列化访问共享资源
互斥量--mutex
synchronizeed
流程
检查锁是否可用
获取锁
执行代码
释放锁
特定对象
所有方法共享一个锁
每个类
static方法共享
一个任务可以多次或得对象的锁
显式的Lock对象
代码缺乏优雅性
更加灵活
更细粒度的控制
原子性与易变性
原子性
原子操作不能被线程调度机制中断
应用中的可视性
对volatile域修改
所有读操作立刻看到修改
long和duble
两个分离的32位操作
自撕裂
volatile
告诉编译器,不要执行任何读取和写入操作的优化
读取和写入直接针对内存,不被缓存
原子类
AtomicInteger
AtomicReference
compareAndSet(exp,update)
临界区
同步代码内部的部分代码,不是整个方法
synchronized指定某个对象,锁用来对花括号内的代码同步
(互斥量是同步整个方法)
ThreadLocal
根除对变量的共享
为相同变量的不同线程,创建不同存储
终结任务
在阻塞时终结
线程状态
new 新建
Runable 就绪
Blocked 阻塞
有某个条件阻止线程运行
调度器忽略线程
Dead 死亡
进入阻塞状态
调用sleep()
调用wait()线程挂起
等待某个输入/输出流完成
试图在某个对象调用同步方法,但对象锁不可用
中断
interrupt()
Excutor --shutdownNow()
Excutor.submit()返回Future,可调用cancel ()
线程间协作
概述
护持--解决资源共享问题
多个任务一起工作,解决某个问题
任务之间握手
wait()和notifyAll()
wait()
等待某个条件发生变化,这个变化又另一个任务实现
挂起线程,对象上锁释放
sleep()和yield()没有释放锁
将任务挂起,只有在notify()和notifyAll()才被唤醒
notify()
通知对象x
众多等待同一个锁的任务,只有一个被唤醒
错失的信号
死锁
生产者和消费者
Chif
生产者
WaitPerson
消费者
生产者消费者和队列
任务间使用管道输入输出
死锁
死锁的条件
互斥条件
任务的资源只有有一个是不能共享的(筷子)
持有资源
一个任务持有一个资源,等待另一个资源
资源不能被任务抢占
循环等待
新类库中的构件
CountDownLatch
同一个或多个线程,强制他们等待由其他任务执行的一组操作
CycLicBarrier
一组任务并行执行,在进行下一个步骤前等待,直至所有的任务完成
所有的并行任务在栅栏处列队,一致向前移动
DelayQueue
无界的BlockingQueue,放置实现了Delayed的接口对象
对象只有在到期时才能从队列取走
PriorityBlockingQueue
优先级队列,具有阻塞的读取操作
Exchanger
两个对象交换的栅拦
性能调优
免锁容器
原理
对容器的修改可以与读操作同时发生,只要读取者只能看到完成修改的结果
修改在容器数据结果的副本执行,在修改过程不可视
ConcurrentLinkedQueue
ConcurrentHashMap
乐观加锁
保持数据为锁定状态
ReadWriteLock
优化不频繁写入,但多个任务经常读取的数据结构
如果写锁被持有,任何读取者都不能访问
总结
线程的好处
轻量级的执行上下文切换(大约100条指令)
进程需要上千条指令,并改变所有内存空间
而线程只改变程序的执行序列和局部变量
多线程的缺点
等待资源时,想能降低
处理线程,额外的cpu
糟糕的程序设计,导致不必要的复杂度
病态行为:竞争,死锁
不同平台导致的不一致性
多线程与并发编程
多线程
概念
进程
是操作系统进行资源分配和调度的基本单位
线程
是进程中的一个执行单元,负责当前进程中的程序执行
创建方式
继承
Thread
实现
实现Runnable
实现Callable
线程池创建
Executors
ThreadPoolExecutor
生命周期
新建
就绪
运行
阻塞
死亡
调度策略
抢占式调度,优先级高的任务一直执行
协作
sleep
当前线程睡眠一段时间,不会释放锁
yield
放弃当前线程获取的cpu时间片,给其他线程
join
暂停当前线程,等待调用线程执行结束在继续执行,不会释放锁
通讯
使用Object类的wait() 和 notify() 方法
wait和 notify必须配合synchronized使用,wait方法释放锁,notify方法不释放锁
使用 volatile 关键字
使用JUC工具类 CountDownLatch
使用 ReentrantLock 结合 Condition
基本LockSupport实现线程间的阻塞和唤醒
并发编程
线程池
设计理念
创建好的线程在指定时间内有系统统一管理
避免频繁的创建和销毁线程带来的系统开销
处理流程
使用(构造参数含义)
corePoolSize:线程池的大小。线程池创建之后不会立即去创建线程,而是等待线程的到来。当当前执行的线程数大于改值是,线程会加入到缓冲队列;
maximumPoolSize:线程池中创建的最大线程数;
keepAliveTime:空闲的线程多久时间后被销毁。默认情况下,改值在线程数大于corePoolSize时,对超出corePoolSize值得这些线程起作用。
unit:TimeUnit枚举类型的值代表keepAliveTime时间单位,可以取下列值:
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //纳秒
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //纳秒
workQueue:阻塞队列,用来存储等待执行的任务,决定了线程池的排队策略,有以下取值:
ArrayBlockingQueue
基于数组的有界队列
LinkedBlockingQueue
链表结构的阻塞队列,吞吐量高于ArrayBlockingQueue
SynchronousQueue
不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则阻塞。吞吐量高于LinkedBlockingQueue
消费一个,才去生产一个
PriorityBlockingQueue
优先级的无限阻塞队列
threadFactory:线程工厂,是用来创建线程的。默认new Executors.DefaultThreadFactory();
handler:线程拒绝策略。当创建的线程超出maximumPoolSize,且缓冲队列已满时,新任务会拒绝,有以下取值:
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
四种线程池创建
newSingleThreadExecutor
组成
核心线程数=最大线程数=1
LinkedBlockingQueue
keepAliveTime=0
特征
线程池中最多执行1个线程,之后提交的线程活动将会排在队列中以此执行
作用
可保证顺序地执行各个任务,以无界队列方式来运行该线程。
场景
一个任务一个执行的场景
newFixedThreadPool
组成
核心线程数=最大线程数
LinkedBlockingQueue
keepAliveTime=0
特征
线程池中的线程处于一定的量,可以很好的控制线程的并发量
线程可以重复被使用,在显示关闭之前,都将一直存在
超出一定量的线程被提交时候需在队列中等待
作用
创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在某个线程被显式地关闭之前,池中的线程将一直存在。
场景
执行长期的任务,性能好很多
newCachedThreadPool
组成
核心线程数=0
最大线程数为int 最大值
keepAliveTime=60
SynchronousQueue
特征
线程池中数量没有固定,可达到最大值(Interger. MAX_VALUE)
线程池中的线程可进行缓存重复利用和回收(回收默认时间为1分钟)
当线程池中,没有可用线程,会重新创建一个线程
作用
可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们,并在需要时使用提供的 ThreadFactory 创建新线程。
场景
执行很多短期异步的小程序或者负载较轻的服务
newScheduleThreadPool
特征
线程池中具有指定数量的线程,即便是空线程也将保留
可定时或者延迟执行线程活动
作用
创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
newSingleThreadScheduledExecutor
特征
线程池中最多执行1个线程,之后提交的线程活动将会排在队列中以此执行
可定时或者延迟执行线程活动
作用
创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。
注意事项
建议使用 new ThreadPoolExecutor(...) 创建线程
合理设置线程数
CPU密集任务,参考值为NCPU+1
IO密集任务,参考值为2*CPU
Synchronized
使用方法
代码块
指定加锁对象,给指定对象加锁
静态方法
当前类对象加锁
实例方法
当前实例对象加锁
底层实现
对象头
JVM虚拟机中存储布局
三个区域
对象头(Header)
类型指针(Klass Pointer)
对象指向它的类元素指针,确定对象那个实例
标记字段(Mark word)
存储对象运行数据
实例数据(Instance data)
对齐填充(Padding)
锁对象存储位置
标记字段
Monitor
锁
乐观锁和悲观锁
乐观锁
认为取数据不会被修改,所以不加锁,但是在更新会判断是否被修改
实现:CAS算法
悲观锁
假设取数据不会被修改,所以要加锁,其他线程就会等待直到拿到锁
实现
java 实现:Synchronized
Mysql: 行锁、表锁、读锁、写锁
总结
悲观锁适合写操作多的场景
乐观锁适合读操作多的场景
公平锁和非公平锁
公平锁
每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程时等待的第一个,
就占有锁,否则加入等待队列,按照FIFO的原则取到自己
就占有锁,否则加入等待队列,按照FIFO的原则取到自己
优点
等待锁的线程不会一直等待
缺点
等待线程的每个线程(出第一个以外)都会阻塞,cpu唤醒阻塞线程的开销比非公平锁大
非公平锁
线程直接尝试占有锁,如果失败,再采用类似公平锁的方式
优点
减少线程唤起的开销,整体吞吐量高
缺点
处于等待队列中的线程可能很久才会获取锁
new ReentrantLock(...)
true
公平锁
false
非公平锁
独享锁和共享锁
独享锁
该锁一次只能被一个线程持有
共享锁
该锁可能被多个线程锁持有
比较
new ReentrantLock(...)是独享锁
ReadWriteLock,其读锁是共享锁,写锁是独享锁
读锁的共享锁可保证并发读是非常高效
独享锁和共享锁是通过AQS实现
分段锁
一种锁设计,不是一种具体的锁
java常见的锁
Synchronized
ReentrantLock
Samphore
AtmoicInteger
concurrent(并发包)
内存模型
共享变量
被多个线程共同使用的变量
三个概念
可见性
原子性
有序性
volatile
特点
从主存中获取数据,而不是缓存中
可见性
有序性
使用条件
对变量的鞋操作不依赖于当前值
该变量没有包含在其他变量的不变式中
原理
数据总线加锁
缓存一致性原理
三级缓存
使用场景
状态标记量
double check
Cas
Compare and Swap,即比较再交换
锁特征
独占锁
悲观锁
AQS
AbstractQueuedSynchronizer
数据模型
核心功能
锁同步(synchronized)
锁等待(wait,notify)
三个核心成员
共享变量:volatile int state
对头节点:head
队尾节点:tail
state状态变更是基于cas实现
三个方法
cas保证可见性,aqs保证原子性
CLH队列
FIFO
资源共享方式
可重入锁ReentrantLock
独占式
信号量Semaphore
共享式
获取锁和释放锁的原理
获取锁
线程a获取锁,state状态将0变成1,线程a占用
若a没有释放,b线程来获取锁,此时state为1,表示被占用,线程b创建一个node节点放到队尾,阻塞b
释放锁
线程a执行完,将state从1设置为0
唤醒下一个node b线程节点,然后删除a线程节点
线程b占用,获取state状态,执行完唤醒下一个nodde
常用类
面试题
sleep和wait的区别
sleep是Thread的方法,wait是Object的方法;
sleep不会释放锁,wait会释放锁,并加入到对象的monitor 的queue中;
sleep不需要synchronized,但是wait是需要synchronized;
sleep不需要唤醒,但是wait需要唤醒; 除过wait(10)
请描述synchrno丨zed和reentrant丨ock的底层实现及重入的底层原理-百度阿里
请描述锁的四种状态和升级过程-百度阿里
https://www.cnblogs.com/mingyueyy/p/13054296.html
CAS的ABA问题如何解决-百度
请谈一下AQS.为什么 AQS的底层是CAS + volatile -百度
请谈一下你对volatile的理解-美团阿里
volatile的可见性和禁止指令重排序是如何实现的-美团
CAS是什么-美团
请描述一下对象的创建过程-美团颗丰
对象在内存中的内存布局-美团顺丰
DCL单例为什么要加volatile -美团
写一个案例
解释一下锁的四种状态-顾丰
Object。= new〇bject()在内存中占了多少字节?-顺丰
请描述synchron丨zed和ReentrantLock的异同
聊聊你^fas-if-seria丨和happens-before语义的理解-京东
如了l^ThreadLocal吗?你4道ThreadLoca丨中如何解决禹奋泄漏问题吗? •京东阿里
请描述一下锁的分类以及JDK中的应用-阿里
IO
同步
正常调用
异步
基于回调
阻塞
没开线程
非阻塞
开了线程
设计模式
jvm
jvm基础
jvm的及基本结构
类加载子系统
运行时数据区(内存结构)
执行引擎
栈帧结构
局部变量表
是一组变量值的存储空间,存储方法参数和方法内部定义的局部变量
操作数栈
是一个先进后出的栈,用于在方法运行时各种字节码指令往操作数栈中写入和提取内容
动态链接
每个栈帧中都包含一个指向运行时常量池中该栈帧所属方法的引用.符号引用在运行时转换为直接引用的过程就被称为动态链接
方法返回地址
类加载器
作用
实现通过类的权限定名加载描述该类的二进制流信息
分类
启动类
Bootstrap Class Loader
扩展类
Extension Class Loader
应用程序类
Application Class Loader
自定义类
双亲委托机制
如果一个类记载器收到类加载的请求,他首先不会自己去加载这个类,而是把请求委托给加载器去完成,每一个层次
都是如此,因此所有;类记载请求都会被传到父类加载器的启动类记载器中,只有当父类加载器反馈自己无法完成加载后,
子类加载器才会尝试进行类加载
都是如此,因此所有;类记载请求都会被传到父类加载器的启动类记载器中,只有当父类加载器反馈自己无法完成加载后,
子类加载器才会尝试进行类加载
确保了沙箱安全
破坏双亲委托机制
在ClassLoader抽象类中添加findClass
引入线程上下文加载器
为了实现模块热部署机制
类加载过程
加载
通过一个类的全限定名来获取定义此类的二进制字节流
将这个字节流所代表的静态存储结构转化为方法区的运行是数据结构
在内存中生成一个代表这个类的class对象
验证
验证字节流是否符合class文件的规范
对字节流描述的信息进行语义分析
验证程序语义是否合法,是否符合逻辑
准备
为类中定义(静态变量)的变量分配内存并设置类的初始值
解析
Java虚拟机将常量池内符号应用替换为直接引用
初始化
执行<Clinit>方法,完成变量的初始化
方法调用
解析调用
解析调用是指编译期就可以完成符号引用到直接引用的转换,就可以确定调用方法的版本,就可以完成方法的调用
分派
静态分派(与重载相关)
依赖静态类型来决定方法执行的版本,发生在编译阶段
动态分派(与重写相关)
如果实现方法是为每个类在方法区建立虚方法表,需方法表中存放着各个方法的实际入口地址。
如果某个方法在子类中没有被重写,那么子类的虚方法表中的地址入口与父类相同的方法一致,
都指向父类的实现接口。如果子类重写了这个方法,子类虚方法表中的地址也会被替换为
指向子类实现版本的入口地址
如果某个方法在子类中没有被重写,那么子类的虚方法表中的地址入口与父类相同的方法一致,
都指向父类的实现接口。如果子类重写了这个方法,子类虚方法表中的地址也会被替换为
指向子类实现版本的入口地址
泛型
原理
java的泛型采用的是类型擦除式泛型,也就是说代码在编译之后就不存在泛型信息了
泛型最终都会被转换为Object的
缺点
涉及到频繁的拆箱装箱过程,效率很低
不支持运行是获取泛型的数据类型
对重载有一定的影响(java的泛型是全面落后在其他语言的)
JMM
主内存与工作内存
volatile
可见性
对volatile变量的写操作会强制刷新到主存,并使其他处理器核心的缓存失效,保证可见性
有序性
volatile修饰的变量不会参与指令重排
先行发生原则
内存屏障
Load Barrier
在读指令插入读屏障,可以试缓存失效。迫使从主存中读取数据
Store Barrier
在写入指令插入写屏障,可以保证写入到缓存的数据刷新到主存
实际应用
LoadLoad
StoreStore
LoadStore
StoreLoad
volatile变量的写操作涉及该屏障
对象的创建
类加载
空间分配
对对象进行必要的设置
执行<init>,构造函数
对象的访问定位
通过句柄访问
堆中将划分一部分空间作为句柄池,refrence存放的是句柄地址,而句柄中存放了直接地址
句柄定位方式有助于对象移动过程的处理
通过直接地址访问定位
refrence存放的是对象的直接地址,使用直接指针的方式来定位对象,效率更高,.因为少了一次指针定位的时间开销
对象存活判断
引用计数法
原理
为每个对象添加一个引用计数,每当有一个地方引用了,计数器值加一,当引用失效时,计数器减一,当计数器的值为0时,认为对象可以被回收
缺陷
无法解决对象之间的循环引用问题
可达性分析法
原理
从GCRoot开始向下搜索,如果对象不可达,那么对象可以被回收
GCRoot
虚拟机栈中引用的对象
本地方法栈中引用的对象
方法区中静态属性引用的对象
方法区常量引用的对象
虚拟机内部的引用
所用被同步锁持有的对象
反映java虚拟机内部情况的JMXBean等对象
内存分配和回收策略
对象优先在Eden区分配
大对象直接进入老年代
长期存活的对象进入老年代
空间分配担保
当回收Eden区时候, 需要确保Serv ivor区能够有足够的空间存放存活的对象,为了避
免YGC后Servivor空间不足, 因此需要老年代进行空间分配担保,当Serv ivor区空间
不足以容纳存活的对象时,将利用老年代的空间。这就是空间分配担保机制。根据统
计信息,当老年代的空间也不足以多于的对象时,那么就会空间分配担保失败,这个
时候就会触发FullGC。
免YGC后Servivor空间不足, 因此需要老年代进行空间分配担保,当Serv ivor区空间
不足以容纳存活的对象时,将利用老年代的空间。这就是空间分配担保机制。根据统
计信息,当老年代的空间也不足以多于的对象时,那么就会空间分配担保失败,这个
时候就会触发FullGC。
经典垃圾收集器
Serial
单线程新生代收集器。采用复制算法, 会有STW.
ParNew
是Serial的多线程版本同样也是新生代收集器, 采用复制算法会有STW.
Parallel Scavenge
基于标记复制算法的新生代收集器
Serial Old
Serial的老年代版本, 采用的标记整理算法, 同样也是单线程的。
Parallel Old
Parallel Scavenge的老年代多线程收集器, 采用的是标记整理算法。
CMS
Serial的老年代版本, 采用的标记整理算法, 同样也是单线程的。
基于标记清除算法的收集器,一般用作老年代收集器。它的垃圾收集过程经历初始标
记,并发标记,重新标记,并发清除的过程。其优点停顿时间短,缺点是无法清除浮
动垃圾。
基于标记清除算法的收集器,一般用作老年代收集器。它的垃圾收集过程经历初始标
记,并发标记,重新标记,并发清除的过程。其优点停顿时间短,缺点是无法清除浮
动垃圾。
G1
G1收集器将整个堆空间划分为许多个Region, 它不再重物理上区分新生代和老年
代, 而是根据每个分区的回收价值来进行回收。G 1还提供了Humongous区域来专门
用来存储大对象。
代, 而是根据每个分区的回收价值来进行回收。G 1还提供了Humongous区域来专门
用来存储大对象。
垃圾收集算法
引用计数法
一般不采用
标记清除算法
首先标记需要被回收的对象,标记完成后统一回收掉标记的对象。它的缺点时执行效
率不问题,效率随着对象的增长而降低。并且该算法会产生大量的内存碎片。
率不问题,效率随着对象的增长而降低。并且该算法会产生大量的内存碎片。
标记整理算法
标记所有需要回收的对象,然后将存活的对象移动到一端,然后清除边界之外的内存。
复制算法
将内存按容量分为两个部分,每次只使用其中一部分。垃圾回收时,将存活的对象复制到另一部分,然后清除使用过的一半内存。
分代收集理论
弱分代学说
绝大多数对象都是朝生夕灭的弱分代学说
强分代学说
熬过越多次垃圾收集的对象就越难灭亡
跨代引用假说
跨代引用相对于同代引用是少数
引用
强引用
软引用
当内存不足时被回收, 可以使用SoftReference来实现
弱引用
下一次GC时会被回收, 可以使用WeakRefrence来实现
虚引用
在回收时可以收到一个通知, 用PhantomReference实现
对象的内存布局
对象头
哈希码
GC分代年龄
锁状态标记
线程持有的锁
偏向时间戳
实例数据
存储我们在程序代码中定义的各种字段,包括从父类继承的
对齐填充
没有特别的的要求, 但是hotspot虚拟机要求对象的起始地址必须为8字节的整数倍。
锁优化
自旋锁与自适应循环
锁消除
虚拟机即时编译器在运行是,对一些代码要求同步,但是对检查到不可能存在共享数
据竞争的锁进行消除
据竞争的锁进行消除
锁粗化
锁的粒度比较小的时候可能会出现频繁的加锁和解锁。这个时候就可以对锁的作用访
问进行拓展合并几个同步区域,以提高效率。
问进行拓展合并几个同步区域,以提高效率。
偏向锁
偏向锁的核心就是正在无竞争的情况夏将这个同步取消掉。当锁被第一次获取时,会
记录偏向线程ID和锁状态,持有偏向锁的线程下次进入无需加锁。当另一个线程尝试
区获取这个锁的时候,偏向锁将会升级为轻量级锁。
记录偏向线程ID和锁状态,持有偏向锁的线程下次进入无需加锁。当另一个线程尝试
区获取这个锁的时候,偏向锁将会升级为轻量级锁。
轻量级锁
轻量级锁是在无竞争的时候使用CAS来替换互斥量来提高效率。
运行时数据区
线程私有
程序计数器
虚拟机栈
本地方法栈
线程间共享
堆区
线程共享的堆中依然可以划分出线程私有的空间, 比如TLAB(线程分配缓存区) 以提
高对象分配时的效率。
高对象分配时的效率。
方法区
方法区目前已经采用本地内存来实现了
JAVA线程
HotSpot虚拟机线程的实现
每个Java线程直接映射到一个操作系统原生线程来实现, 中间没有任何间接结构。且
HotSpot虚拟机不会干涉线程调度。
HotSpot虚拟机不会干涉线程调度。
状态
新建
无限制等待
没有设置时间的wait, join, park等
期限等待
设置了时间的sleep, wait, join, park等
阻塞
等待锁
结束
线程的实现
使用内核线程实现
使用用户线程实现
使用用户线程加轻量级进程混合实现
线程安全
定义
当多个线程同时访问一个对象时,如果不用考虑这些线程运行时环境下的调度和交替
执行,也不需要进行额外的同步,或者在调用时方法进行任何的协调,调用这个对象
的行为都可以得到正确的结果,那就称这个对象是线程安全的。
执行,也不需要进行额外的同步,或者在调用时方法进行任何的协调,调用这个对象
的行为都可以得到正确的结果,那就称这个对象是线程安全的。
实现途径
不可变
相对线程安全
绝对线程安全
线程独立
线程兼容
JDK8新特性
接口默认方法
Lamdar表达式
函数式接口
Stream流
全新的Date Api
子主题
常用工具
jps:虚拟机进程状态工具
jstat:虚拟机统计信息监视工具
jst at-gc util 2764; 可查看各分代大小, GC次数, GC总时间等信息, 可用来排除频
繁GC导致的卡顿。
繁GC导致的卡顿。
jinfo:Java配置信息工具
jmap:Java内存映像工具
jhat:虚拟机堆转储快照分析
jstack:Java堆栈跟踪工具
jvm调优
jvm内存结构
why理解JVM
写出更优雅的代码
排查问题-性能调优
面试必问
历史
HotSpot-sun-oracle
JRockit-bea
J9-IBM
Dalvik-google
未来的java-11
模块化混合语言多核并行丰富语法64位更强的GC
JavaSE体系
JDK-JRE-JVM
标准版;JavaEE、JavaME
C++语言实现
运行时数据区
线程私有:程序计数器、虚拟机栈、本地方法栈线程共享:堆、方法区
线程私有
程序计数器
唯一一个不会出现OutOfMemoryError情况的区域
多线程,需要恢复现场
Java方法,则指明当前线程执行的代字节码行数
Natvie方法,这个计数器值则为空(Undefined)
虚拟机栈
栈的大小缺省为1M,最小165K可用参数-Xss调整大小,例如-Xss256k
局部变量表
操作数栈
动态链接
返回地址
三部曲:恢复上层方法的局部变量表和操作数栈、把返回值
(如果有的话)压入调用者栈帧的操作数栈中、调整PC计数器
的值以指向方法调用指令后面的一条指令
(如果有的话)压入调用者栈帧的操作数栈中、调整PC计数器
的值以指向方法调用指令后面的一条指令
本地方法栈
native方法调用JNI到了底层的C/C++
对应操作系统内存!
三者:生命周期和线程相同
线程共享
方法区-永久代
jdk 1.7及以前:-XX:PermSize;-XX:MaxPermSize;jdk1.8以后:-
XX:MetaspaceSize;-XX:MaxMetaspaceSizejdk1.8以后大小就只
受本机总内存的限制
XX:MetaspaceSize;-XX:MaxMetaspaceSizejdk1.8以后大小就只
受本机总内存的限制
1.8:元空间
堆
-Xms:堆的最小值; -X mx:堆的最大值; -X mn:新生代的大小;
-XX:NewSize;新生代最小值;-XX:MaxNewSize:新生代最大值;
-XX:NewSize;新生代最小值;-XX:MaxNewSize:新生代最大值;
运行时常量池
符号引用
在编译时用符号引用来代替引用类,在加载时再通过虚拟机获取该引用类的实际地址
符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可
字面量
文本字符串:String a=”abc”, 这个abc就是字面量
八种基本类型
int a=1; 这个1就是字面量
short\int\long\float\double\char\byte\boolean\
声明为final的常量
常量池的变化
三者:涉及到生命周期管理和垃圾回收等概念
直接内存
使用Native函数库直接分配堆外内存(NIO)
通过-XX:MaxDirectMemorySize来设置
栈溢出
参数:-Xss256k
无限递归-java.lang.Stack Overflow Error
不断建立线程-OutOfMemoryError
一般演示不出,演示出来机器也死了
jvm中对对象
JVM中的对象
根据new的参数是否能在常量池中定位到一个类的符号引用
1.检查加载
执行相应的类加载过程
2.分配内存
根据方法区的信息确定为该类分配的内存空间大小
a.指针碰撞
java堆内存空间规整的情况下
把那个指针向空闲空间那边挪动一段与对象大小相等的距离
b.空闲列表
java堆空间不规整的情况下
并发安全
解决:CAS机制
分配缓冲
每个线程在Java堆中预先分配一小块私有内存
如果设置了虚拟机参数-XX:+Use TLAB本地线程分配缓冲(Thread Local Allocation Buffer, TLAB)
3.内存空间初始化
将分配到的内存空间都初始化为零
对象的实例字段在Java代码中可以不赋初始值就直接使用
4.设置
对象头设置
这个对象是哪个类的实例、如何才能找到类的元数据信息对象的哈希码、对象的GC分代年龄等信息
5.对象初始化
从Java程序的视角来看, 对象创建才刚刚开始
构造函数和变量赋值
对象的内存布局
对象头(Header)
存储对象自身的运行时数据:8Byte
哈希码(HashCode) 、GC标志、
对象分代年龄、锁状态标志、线程
持有的锁、偏向线程ID、偏向时间
对象分代年龄、锁状态标志、线程
持有的锁、偏向线程ID、偏向时间
类型指针-8Byte
指针压缩!--4Byte
确定这个对象是哪个类的实例
数组长度-4Byte-非必须
对齐填充
说明:当包含数组类型-且开启指针压缩, 会有两个padding的情况
实例数据(Instance Data)
对齐填充(Padding)
对象的访问定位
直接指针
reference中存储的直接就是对象地址
优势:速度更快,它节省了一次指针定位的时间开销
Sun HotSpot-默认使用!!
句柄
Java堆中将会划分出一块内存来作为句柄池
句柄中包含了对象实例数据与类型数据各自的具体地址
优势:在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄
中的实例数据指针, 而reference本身不需要修改
中的实例数据指针, 而reference本身不需要修改
堆内存分配策略
优先在Eden区分配
新生代:Eden区Survivor(from) 区:设置Survivor是为了减少送到老年代的对象Survivor(to) 区:设置两个Survivor区是为了
解决碎片化的问题(复制回收算法)
解决碎片化的问题(复制回收算法)
-XX:+Print GC Details打印垃圾回收日志
-Xmn10m新生代空间10m
大对象直接进入老年代
-XX:PretenureSizeThreshold=4m超过多少大小的对象直接进入老年代
-XX:+Use Serial GC
Pretenure SizeThreshold参数只对Serial和ParNew两款收集器有效
最典型的大对象是那种很长的字符串以及数组
1.避免大量内存复制,2.避免提前进行垃圾回收
原理:大对象一般生存时间较长
长期存活的对象进入老年代
年龄增加到一定程度(默认为15)_时,就会被晋升到老年代
根据年龄动态判定
如果在Survivor空间中相同年龄所有对象大小的综合大于Survivor空间的一半,
年龄大于或等于该年龄的对象就可以直接进入老年代
年龄大于或等于该年龄的对象就可以直接进入老年代
空间分配担保
Minor GC之前, 虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间
成立, 那么Minor GC可以确保是安全的
不成立, 则虚拟机会查看Handle Promotion Failure设置值是否允许担保失败
如果允许,那么会继续检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小
如果大于, 将尝试着进行一次Minor Gc
否则:进行一次Full GC
HotSpot默认是开启空间分配担保的
java中的泛型
什么是泛型
即“参数化类型”
本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)
引入一个类型变量T(其他大写字母都可以,不过常用的就是T,E,K,V等等),并且用◇括起来,并放在类名的后面
泛型类、泛型接口、泛型方法
why-need
适用于多种数据类型执行相同的代码
泛型中的类型在使用时指定,不需要强制类型转换
jvm-how-实现
只在程序源码中存在, 在编译后的字节码文件中, 就已经替换为原来的原生类型(Raw Type, 也称为裸类型) 了, 并且在相
应的地方插入了强制转型代码
应的地方插入了强制转型代码
对于运行期的Java语言来说, ArrayList<int>与ArrayList<String>就是同一个类
实际上是Java语言的一颗语法糖
泛型实现方法称为类型擦除,基于这种方法实现的泛型称为伪泛型
擦除法所谓的擦除, 仅仅是对方法的Code属性中的字节码进行擦除, 实际上元数据中还是保留了泛型信息, 这也是我们能通
过反射手段取得参数化类型的根本依据
过反射手段取得参数化类型的根本依据
垃圾回收算法和收集器
why-learn
1、面试需要2、GC对应用的性能是有影响的;3、写代码有好处
判断对象存活
引用计数法
优点:快,方便,实现简单。缺陷:对象相互引用时
(A.instance=B同时B.instance=A),很难判断对象是否该回收
(A.instance=B同时B.instance=A),很难判断对象是否该回收
可达性分析
“GCRoots“的对象作为起始点,从这些节点开始向下搜索,搜索所
走过的路径称为引用链(ReferenceChain)
走过的路径称为引用链(ReferenceChain)
当一个对象到GCRoots没有任何引用链相连时则证明此对象是不可用的
GC-Roots-Set集合
1.当前虚拟机栈中局部变量表中的引用的对象
2.当前本地方法栈中局部变量表中的引用的对象
3.方法区中类静态属性引用的对象
4.方法区中的常量引用的对象
2.当前本地方法栈中局部变量表中的引用的对象
3.方法区中类静态属性引用的对象
4.方法区中的常量引用的对象
finalize
第二次标记
finalize可以完成对象的拯救,但是JVM不保证一定能执行,所以请忘记这个“坑”
用在直接内存分配的回收
四种引用
强引用:一般的Objectobj=newObject(),就属于强引用
软引用SoftReference
内存充足的时候不会回收它,而在内存不足时会回收它
非常适合于创建缓存
弱引用WeakReference
无论内存充足与否,都会回收该对象的内存
实际运用(WeakHashMap、ThreadLocal)
虚引用PhantomReference
幽灵引用,最弱,被垃圾回收的时候收到一个通知
两种GC
Garbage-Collection
打印GC详情-XX:+HeapDumpOnOutOfMemoryError
oMinorGC
特点:发生在新生代上,发生的较频繁,执行速度较快触发条件:
Eden区空间不足\空间分配担保
Eden区空间不足\空间分配担保
FullGC
特点:主要发生在老年代上(新生代也会回收),较少发生,执行速
度较慢
度较慢
子主题
垃圾回收器
并行:垃圾收集的多线程的同时进行。
并发:垃圾收集的多线程和应用的多线程同时进行。
并发:垃圾收集的多线程和应用的多线程同时进行。
Serial/SerialOld
最古老的,单线程,独占式,成熟,适合单CPU
-XX:+UseSerialGC新生代和老年代都用串行收集器-
XX:+UseParNewGC新生代使用ParNew,老年代使用SerialOld-
XX:+UseParallelGC新生代使用ParallerGC,老年代使用Serialold
XX:+UseParNewGC新生代使用ParNew,老年代使用SerialOld-
XX:+UseParallelGC新生代使用ParallerGC,老年代使用Serialold
ParNew
Serial基本没区别,唯一的区别:多线程,多CPU的,停顿时间比Serial少
(ParallerGC)/ParallelOld
关注吞吐量的垃圾收集器,高吞吐量则可以高效率地利用CPU时间
适合在后台运算而不需要太多交互的任务
吞吐量:CPU用于运行用户代码的时间与CPU总消耗时间的比值
ConcurrentMarkSweep(CMS)
获取最短回收停顿时间为目标的收集器
-XX:+UseConcMarkSweepGC,一般新生代使用ParNew,老年代的用CMS
CMS收集器是基于”标记一清除”算法实现的
1.初始标记
STW-只是标记一下GCRoots能直接关联到的对象
2.并发标记
对象进行可达性分析,找到存活对象
3.重新标记
SYW-修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录
4.并发清除
优点:耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作
CPU资源敏感:因为并发阶段多线程占据CPU资源
缺点:
浮动垃圾:由于CMS并发清理阶段用户线程还在运行着,伴随
程序运行自然就还会有新的垃圾不断产生
程序运行自然就还会有新的垃圾不断产生
老年代空间使用率阈值(92%)
会产生空间碎片:标记-清除算法会导致产生不连续的空间碎片
G1垃圾回收器
-XX:+UseG1GC使用G1垃圾回收器
划分成多个大小相等的独立区域(Region)新生代和老年代不再物理隔离
算法:标记一整理(old,humongous)和复制回收算法(survivor)。
1.YoungGC-复制算法选定所有新生代里的Region。通过控制新生
代的region个数来控制youngGC的时间开销
代的region个数来控制youngGC的时间开销
2.MixedGC选定所有新生代里的Region,外加根据global
concurrentmarking统计得出收集收益高的若干老年代Region
MixedGC不是fullGC,它只能回收部分老年代的Region
concurrentmarking统计得出收集收益高的若干老年代Region
MixedGC不是fullGC,它只能回收部分老年代的Region
Mixed GC不是fullGC, 它只能回收部分老年代的Region
如果mixedGC实在无法跟上程序分配内存的速度,导致老年代
填满无法继续进行MixedGC,就会使用serialoldGC(fullGC
填满无法继续进行MixedGC,就会使用serialoldGC(fullGC
G1是不提供fullGC的
全局并发标记(globalconcurrentmarking)
基本和CMS一样
特点
空间整合:不会产生内存碎片
可预测的停顿:
适合于大内存!
StopTheWorld现象GC收集器和我们GC调优的目标就是尽可能的减少STW的时间和次数。
jvm执行子系统
Class文件结构
jvm无关性
一次编写,到处运行
字节码(ByteCode) 是构成平台无关性的基石
Class类文件
Class文件是一组以8位字节为基础单位的二进制流
8字节,对齐-压缩!
Class文件都对应着唯一一个类或接口的定义信息
不一定以磁盘文件的形式存在
动态代理
javassist-运行时编译
文件格式
各个数据项目严格按照顺序紧凑地排列
中间没有添加任何分隔符
两种数据类型:无符号数和表
无符号数属于基本的数据类型,u1、u2、u4、u8
表是由多个无符号数或者其他表作为数据项构成的复合数据类型
表用于描述有层次关系的复合结构的数据, 整个Class文件本质上就是一张表
文件格式详解
魔数与Class文件的版本
头4个字节-
CA FE BA BE
确定这个文件是否为一个能被虚拟机接受的Class文件
后4个字节存储的是Class文件的版本号
第5和第6个字节是次版本号(Minor Version)
第7和第8个字节是主版本号(Major Version)
JDK 1.8-p
00 00 00 34
常量池
放置一项u 2类型的数据, 代表常量池容量计数值(constant_pool_count)
容量计数是从1而不是0开始
两大类常量:字面量(Literal) 和符号引用(Symbolic References)
字面量比较接近于Java语言层面的常量概念, 如文本字符串、声明为final的常量值等
符号引用则属于编译原理方面的概念
类和接口的全限定名(Fully QualifiedName) 、字段的名称和描述符(Descriptor) 、方法的名称和描述符
访问标志
这个Class是类还是接口; 是否定义为public类型; 是否定义为abstract类型; 如果是类的话, 是否被声明为final
(父)类索引-接口索引集合
目标:确定这个类的继承关系
类索引用于确定这个类的全限定名
父类索引只有一个
除了java.lang.Object之外, 所有的Java类都有父类
接口索引集合就用来描述这个类实现了哪些接口
字段表集合
描述接口或者类中声明的变量
字段(field) 包括类级变量以及实例级变量
方法表集合
描述了方法的定义
编译器添加; 最典型的便是类构造器”<clin it>”方法和实例构造器“<init>
属性表集合
存储Class文件、字段表、方法表等自己的属性表集合
用于描述某些场景专有的信息。如方法的代码就存储在Code属性表中
字节码指令
由一个字节长度的、代表着某种特定操作含义的数字(称为操作码, Opcode) 以及跟随其后的零至多个代表此操作所需参数(称为
操作数, Operands) 而构成
操作数, Operands) 而构成
操作码的长度为一个字节
so:操作码总数不可能超过256条
大多数的指令都包含了其操作所对应的数据类型信息
大多数对于boolean、byte、short和char类型数据的操作, 实际上都是使用相应的int类型作为运算类型
1.加载和存储指令
将一个局部变量加载到操作栈
将一个数值从操作数栈存储到局部变量表
将一个常量加载到操作数栈:
扩充局部变量表的访问索引的指令:wide
2.运算或算术指令
用于对两个操作数栈上的值进行某种特定运算,并把结果重新存入到操作栈顶
加法指令:i add、ladd、f add、d add。减法指令:i sub、I sub、f sub、dsub。乘法指令:imul、Imul、f mul、dmu
3.类型转换指令
宽化类型转换
int类型到long、float或者double类型。long类型到float、double类型。float类型到double类型
窄化类型转换
i2b、i2c、i2s、I2i、f2i、f2l、d2i、d2l和d2f
4.创建类实例的指令
new!!!
5.创建数组的指令
new array、a new array、multi a new array
6.访问字段指令
get field、put field、get static、put static。
7.数组存取相关指令
ba load、ca load、sa load、i a load、la load、fa load、da load、a a load。
ba store、ca store、sa store、i a store、fa store、da store、a a store。
取数组长度的指令:array length。
8.检查类实例类型的指令
instance of、check cast。
9.操作数栈管理指令
将操作数栈的栈顶一个或两个元素出栈:pop、pop2
复制并将复制值重新压入栈顶:dup、dup2、dup_x1、dup2_x1、dup_x2、dup2_x2
将栈最顶端的两个数值互换:swap
10.控制转移指令
有条件或无条件地修改PC寄存器的值
条件分支:
ifeq、iflt、ifle、ifne、ifgt、ifge、ifnull、ifnonnull、if_icmpeq、if_icmpne、if_icmplt、if_icmpgt、if_icmple、
if_icmpge、if_acmpeq和if_acmpne。
if_icmpge、if_acmpeq和if_acmpne。
复合条件分支:tableswitch、lookupswitch
无条件分支:goto、goto_w、jsr、jsr_w、ret
11.方法调用指令
invokevirtual指令用于调用对象的实例方法
invokeinterface指令用于调用接口方法
invokespecial指令用于调用一些需要特殊处理的实例方法
invokestatic指令用于调用类方法(static方法)
invokedynamic指令用于在运行时动态解析出调用点限定符所引用的方法并执行该方法
12.方法返回指令
ireturn(当返回值是boolean、byte、char、short和int类型时使用)
Ireturn、freturn、dreturn和areturn
另外还有一条return指令供声明为void的方法、实例初始化方法以及类和接口的类初始化方法使用
13.异常处理指令
athrow指令
14.同步指令
有monitorenter和monitorexit两条指令来支持synchronized关键字的语义
栈帧详解
栈顶-栈帧称为“当前栈帧”,与这个栈帧相关联的方法称为”当前方法”
1.局部变量表
局部变量表的容量以变量槽(VariableSlot,下称Slot)为最小单位
boolean、byte、char、short、int、float、double、long8种数据类型和引用reference
64位的数据类型只有long和double两种
reference类型则可能是32位也可能是64位
2.操作数栈
先进后出(FirstInLastOut,FILO)栈
解释执行引擎称为“基于栈的执行引擎”
3.动态链接
符号引用是一个地址位置的代号
用代号com/enjoy/pojo/User.Say:0V指代某个类的方法
静态解析:符号引用在类加载阶段或者第一次使用的时候就直接转换成直接引用
动态连接:符号引用在每次运行期间转换为直接引用,即每次运行都重新转换
4.返回地址
正常退出与异常退出
恢复现场
恢复上次方法的局部变量表、操作数栈
把当前方法的返回值,压入调用者栈帧的操作数栈中
用当前栈帧保存的返回地址调整PC计数器的值
5.附加信息
调试相关的信息
数据重叠优化
下面栈帧的一部分操作数栈与上面栈帧的部分局部变量表重叠在一起
基于栈的字节码解释执行引擎
区别于:基于寄存器的指令集
moveax,1addeax,1
计算“1+1”的结果
iconst_1iconst_1iaddistore_O
优点就是可移植
缺点是执行速度相对来说会稍慢一些
方法调用详解
编译时就必须确定下来。这类方法的调用称为解析
编译期可知,运行期不可变
括静态方法
与类型直接关联
私有方法
外部不可被访问
适合在类加载阶段进行解析
静态分派
多见于方法的重载
静态分派发生在编译阶段,因此确定静态分派的动作实际上不是由虚拟机来执行的。
动态分派
静态类型同样都是Human的两个变量man和woman在调用sayHello()方法时执行了不同的行为
因为:这两个变量的实际类型不同
实现上,最常用的手段就是为类在方法区中建立一个虚方法表。虚方法表中存放着各个方法的实际入口地址
类加载机制
类的生命周期-7个阶段
加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用
(Using)和卸载(Unloading)
(Using)和卸载(Unloading)
其中验证、准备、解析3个部分统称为连接(Linking)
1.加载
1)通过一个类的全限定名来获取定义此类的二进制字节流。
2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
用户应用程序可以通过自定义类加载器参与
2.验证
文件格式验证、元数据验证、字节码验证、符号引用验证
3.准备
类变量分配内存并设置类变量初始值的阶段
进行内存分配的仅包括类变量(被static修饰的变量),而不包括实例变量
4.解析
将常量池内的符号引用替换为直接引用的过程
5.初始化
有且只有5种情况必须立即对类进行”初始化”
1)遇到new、getstatic、putstatic或invokestatic这4条字节码指令时
2)使用java.lang.reflect包的方法对类进行反射调用的时候
3)当初始化一个类的时候,如果发现其父类还没有进行过初始化
4)当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类)
5)当使用JDK1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化
初始化阶段是执行类构造器<clinit>(方法的过程
初始化的单例模式(线程安全)
6.使用
7.卸载
类加载器
由加载它的类加载器和这个类本身一同确立一个类在Java虚拟机中的唯一性
加解密案例(de enc rpt代码)
通过位的二进制异或运算进行加解密(一次就是加密,再运算一次就是解密)
双亲委派模型
启动类加载器(Bootstrap ClassLoader)
使用C++语言实现,是虚拟机自身的一部分
扩展类加载器(Extension ClassLoader
应用程序类加载器
自定义类加载器
ClassLoader中的loadClass方法中的代码逻辑就是双亲委派模型
重写loadClass方法
另一种是重写find Class方法
Tomcat类加载机制
2.System系统类加载器加载tomcat启动的类
3 Common通用类加载器加载tomcat使用以及应用通用的一些类
4webapp应用类加载器
Webapp ClassLoader中loadClass方法
打破双亲委派!
但其父类仍然符合双亲委派,所以没问题!
JVM调优
调优的本质
并不是显著的提高系统性能
主要调的是稳定
减少GC调用次数和耗时
调优原则
1、大多数的java应用不需要GC调优
2、大部分需要GC调优的的,不是参数问题,是代码问题
3、在实际使用中,分析GC情况优化代码比优化GC参数要多得多;
4、GC调优是最后的手段
2、大部分需要GC调优的的,不是参数问题,是代码问题
3、在实际使用中,分析GC情况优化代码比优化GC参数要多得多;
4、GC调优是最后的手段
目的
GC的时间够小GC的次数够少
MinorGC执行时间不到50ms;MinorGC执行不频繁,约10秒一次;
FullGC执行时间不到1s;FullGC执行频率不算频繁,不低于10分钟1次
GC调优
调优步骤
日志分析
1,监控GC的状态
2,分析结果,判断是否需要优化
3,调整GC类型和内存分配
4,不断的分析和调整
5,全面应用参数
阅读GC日志
主要关注MinorGC和FullGC的回收效率(回收前大小和回收比较)、回收的时间
调优实战
项目启动GC优化
1、开启日志分析-XX:+PrintGCDetails发现有多次GC包括FullGC
2、调整Metadata空间-XX:MetaspaceSize=64m减少FullGC
3、减少Minorgc次数,增加参数-Xms500mGC减少至4次
4、减少Minorgc次数,调整参数-Xms1000mGC减少至2次
5、增加新生代比重,增加参数-Xmn900mGC减少至1次
6、加大新生代,调整参数-Xms2000m-Xmn1800m
还是避免不了GC,没有必要调整这么大,资源浪费
2、调整Metadata空间-XX:MetaspaceSize=64m减少FullGC
3、减少Minorgc次数,增加参数-Xms500mGC减少至4次
4、减少Minorgc次数,调整参数-Xms1000mGC减少至2次
5、增加新生代比重,增加参数-Xmn900mGC减少至1次
6、加大新生代,调整参数-Xms2000m-Xmn1800m
还是避免不了GC,没有必要调整这么大,资源浪费
项目运行GC优化
使用jmeter同时访问三个接口,index、time、noblemetal使用40个线程,循环2500次进行压力测试,观察并发的变化
jmeter的聚合报告的参数解释:
jmeter的聚合报告的参数解释:
推荐策略
1.新生代大小选择
响应时间优先的应用:尽可能设大
吞吐量优先的应用:尽可能的设置大
避免设置过小
2.老年代大小选择
响应时间优先的应用:老年代使用并发收集器
吞吐量优先的应用:一般吞吐量优先的应用都有一个很大的新生代和一个较小的老年代
GC调优是个很复杂、很细致的过程,要根据实际情况调整,不同的机器、不同的应用、不同的性能要求调优的手段都是不同
逃逸分析
JVM最激进的优化,最好不要调整相关的参数
-XX:+DoEscapeAnalysis:启用逃逸分析(默认打开)-XX:+EliminateAllocations:标量替换(默认打开)-XX:+UseTLAB本地线程分配缓冲(默认打开)
如果是逃逸分析出来的对象可以在栈上分配的话,那么该对象的生命周期就跟随线程了,就不需要垃圾回收
常用性能-测试指标
响应时间
并发数
吞吐量
性能优化手段
避免过早优化
进行系统性能测试
寻找系统瓶颈,分而治之,逐步优化
前端优化常用手段
浏览器/APP
减少请求数
合并文件
使用客户端缓存
启用压缩
浏览器(zip) , 压缩率80%以上
资源文件加载顺序
css放在页面最上面, js放在最下面。
减少Cookie传输
友好的提示
毕竟用户需要的是不要不理他
CDN加速
内容分发网络,本质是一个缓存
反向代理缓存
将静态资源文件缓存在反向代理服务器上, 一般是Ng in x
Web组件分离
将js, css和图片文件放在不同的域名下。可以提高浏览器在下载web组件的并发数
应用服务器性能优化
缓存
第一定律:优先考虑使用缓存优化性能
缓存是将数据存在访问速度较高的介质中
合理使用-准则
频繁修改的数据,尽量不要缓存,读写比2:1以上才有缓存的价值。缓存一定是热点数据。应用需要容忍一定时间的数据
不一致。缓存可用性问题,一般通过热备或者集群来解决
不一致。缓存可用性问题,一般通过热备或者集群来解决
分布式缓存与一致性哈希
集群
将用户的请求分配到多个机器处理,对总体性能有很大的提升
异步
同步和异步,阻塞和非阻塞
Servlet异步
多线程
消息队列
程序
代码级别
一个应用的性能归根结底取决于代码是如何编写的。
选择合适的数据结构
选择更优的算法
编写更少的代码
并发编程
资源的复用
单例模式Spring中的bean
池化技术
存储性能优化
尽量使用SSD
定时清理数据或者按数据的性质分开存放
结果集处理-分页返回
性能优化
内存溢出
栈溢出
方法死循环递归调用(Stack Overflow Error) 、不断建立线程(OutOfMemoryError)
堆溢出
不断创建对象, 分配对象大于最大堆的大小(OutOfMemoryError)
直接内存
方法区溢出
在经常动态生产大量Class的应用中, CGLIb字节码增强, 动态语言, 大量JSP
内存泄漏
定义:程序在申请内存后,无法释放已申请的内存空间
长生命周期的对象持有短生命周期对象的引用
连接未关闭
数据库连接、网络连接和IO连接等
变量作用域不合理
1.一个变量的定义的作用范围大于其使用范围,
2.如果没有及时地把对象设置为null
2.如果没有及时地把对象设置为null
内部类持有外部类
Hash值改变
对比
内存溢出:实实在在的内存空间不足导致;
内存泄漏:该释放的对象没有释放,常见于使用容器保存元素的情况下
内存泄漏:该释放的对象没有释放,常见于使用容器保存元素的情况下
避免
内存溢出:检查代码以及设置足够的空间内存泄漏:一定是代码有问题
往往很多情况下,内存溢出往往是内存泄漏造成的
了解MAT
浅堆
指一个对象所消耗的内存
深堆
这个对象被GC回收后,可以真实释放的内存大小,也就是只能通过对象被直接或间接访问到的所有对象的集合
incoming和outgoing
它引用了谁?谁引用了它?
命令工具
命令行工具
jps
列出当前机器上正在运行的虚拟机进程
-q:仅仅显示进程, -m:输出主函数传入的参数.-I:输出应用程序主类完整package名称或jar完整名称.-v:列出jvm参数, -
Xms20m-Xmx50m是启动程序指定的jvm参数
Xms20m-Xmx50m是启动程序指定的jvm参数
jstat
监视虚拟机各种运行状态信息
显示:进程中的类装载、内存、垃圾收集、JIT编译等运行数据
jst at-gc 1361625010
-class(类加载器) -compiler(JIT) -gc(GC堆状态) -gc capacity(各区大小) -gc cause(最近一次GC统计和原因)
jinfo
查看和修改虚拟机的参数
jinfo-sysprops可以查看由System.getProperties()取得的参数
jinfo-flag未被显式指定的参数的系统默认值
jinfo-flags(注意s)显示虚拟机的参数
jinfo-flag+[参数]可以增加参数
jinfo-flag未被显式指定的参数的系统默认值
jinfo-flags(注意s)显示虚拟机的参数
jinfo-flag+[参数]可以增加参数
jmap
用于生成堆转储快照(一般称为heapdump或dump文件)
jmap-dump:live,format=b,file=heap.bin<pid>
jhat(VMHeapAnalysisTool)命令与jmap搭配使用,来分
析jmap生成的堆转储快照
析jmap生成的堆转储快照
jhat
jhatdump文件名后屏幕显示”Serverisready.”的提示后,用
户在浏览器中键入http://localhost:7000/就可以访问详情
户在浏览器中键入http://localhost:7000/就可以访问详情
使用jhat可以在服务器上生成堆转储文件分析
jstack
用于生成虚拟机当前时刻的线程快照
可视化工具
Jconsole
visualvm
GC重要参数
生产服务器推荐开启
-XX:-HeapDumpOnOutOfMemoryError默认关闭,建议开启
-XX:HeapDumpPath=./java_pid<pid>.hprof用来设置堆内存快照的存储文件路径
调优之前开启、调优之后关闭
-XX:+PrintGC调试跟踪之打印简单的GC信息参数
-XX:+PrintGCDetails,+XX:+PrintGCTimeStamps打印详细的GC信息
-Xlogger:logpath设置gc的日志路,如:-Xlogger:log/gc.log
考虑使用
-XX:+PrintHeapAtGC,打印堆信息
-XX:+TraceClassLoading参数方法:-XX:+TraceClassLoading
-XX:+DisableExplicitGC禁止在运行期显式地调用System.gc()
编写高效优雅的java程序
新一代ZGC
可以保证在TB级堆上的暂停时间非常短(TB级堆<10毫秒),对整个应用程序性能的影响非常小(<15%的吞吐量)
指针着色
指针表示虚拟内存中字节的位置。
ZGC仅适用于64位平台
ZGC指针使用42位来表示地址本身。因此, 可以处理4TB的内存空间(2的42次方)
4位来存储指针状态
多重映射
将多个虚拟内存范围映射到物理内存
负载屏障
负载屏障是一个代码片段,它在线程从堆加载引用时运行
负载障碍检查引用的元数据位
标记
确定我们可以到达哪些对象的过程。我们无法达到的被认为是垃圾
1.Stop The World阶段, 寻找根引用并标记它们
2.并发-从根引用开始遍历对象图
3.Stop The World阶段, 用来处理一些边缘情况, 比如弱引用
ZGC使用marked 0和marked 1元数据位进行标记
重定位
重新映射
如何启用
-XX:+Unlock Experimental VM Options-XX:+Use ZGC
目前ZGC是一个实验性GC, 在生产平台上使用, 还需要再考察
结论
ZGC打算以较低的应用程序暂停时间支持大堆。为了实现这一目标, 它使用了包括有色64位指针, 负载屏障, 重定位和重新映射在
内的技术
内的技术
框架
Spring
事物
概念
事务逻辑上的一组对数据的操作,组成这些操作的各个逻辑单元,要么一起成功,要么一起失败。
加载过程
本质
spring事务本质上使用数据库锁
spring事务只有在方法执行过程中出现异常才会回滚,并且只回滚数据库相关的操作
特性
原子性(atomicity)
强调事务的不可分割
一致性(consistency)
事务的执行前后数据的完整性保持一致
隔离性(isolation)
一个事务的执行的过程中,不应该受到其他事务的干扰
安全问题
脏读
一个事务读到了另一个事务未提交的数据
不可重复读
一个事务督导另一个事务已经提交的update的数据导致多次查询结果不一致
虚幻读
一个事务读到了另一个事务已经提交的insert的数据导致多次查询结果不一致。
持久性(durability)
事务一旦结束,数据就持久到数据库
过程
spring事物
Aop拦截注解或方法
动态代理处理事物方法
spring处理捕获到的事物异常
回滚
事物不回滚
垮库,违背原子性
不能使用事物,手动捕获然后回滚
抛出非运行时异常
代码控制的方式
编程式事物
代码中开启事物,手动提交
声明式事物
Spring Aop事物配置---rollback-for="java.lang.Exception"
注解事物
@Transactional(rollbackFor=Exception.class)
事物传播行为
TransactionDefinition接口中规定
同一事物
PROPAGATION_REQUIRED
如果存在一个事务,则支持当前事务。如果没有事务则开启一个新的事务。
PROPAGATION_SUPPORTS
支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY
如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常
不同事物
PROPAGATION_REQUIRES_NEW
总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
PROPAGATION_NOT_SUPPORTED
总是非事务地执行,并挂起任何存在的事务。
PROPAGATION_NEVER
总是非事务地执行,如果存在一个活动事务,则抛出异常
PROPAGATION_NESTED
如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行
架构设计
流程
Xml
Anonation
配置类
流程图
设计模式
1.工厂设计模式:Spring使用工厂模式通过BeanFactory和ApplicationContext创建bean对象。
2.代理设计模式:Spring AOP功能的实现。
3.单例设计模式:Spring中的bean默认都是单例的。
4.模板方法模式:Spring中的jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,它们就使用到了模板模式。
5.包装器设计模式:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
6.观察者模式:Spring事件驱动模型就是观察者模式很经典的一个应用。
7.适配器模式:Spring AOP的增强或通知(Advice)使用到了适配器模式、Spring MVC中也是用到了适配器模式适配Controller。
控制反转(IOC)依赖注入(DI)
概念
将设计好的对象交给容器控制
负责控制对象的生命周期和对象间的关系
在系统运行期间,动态向某个对象提供它所需要的其他对象
实现
反射
方式
set/get
接口
构造器
生命周期/加载过程
https://www.processon.com/diagraming/5f470dede401fd5f248ab2bc
面向切面编程(AOP)
概念
扩展功能不修改源代码,将功能代码从业务逻辑代码中分离出来
主要意图:通过对这些行为的分离,独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
AOP特点
采用横向抽取机制,取代了传统纵向继承体系重复性代码。
术语
(JoinPoint)连接点
(Pointcut)切入点
(Advice)通知/增强
前置通知
后置通知
异常通知
最终通知
环绕通知
(Aspect)切面
AOP实现原理
动态代理
cglib实现
JDk动态代理
静态代理
AOP操作案例
日志记录
性能统计
拦截器
事物处理
异常处理
面试题
Spring生命周期
IOC/AOP
循环依赖
构造器参数
只能抛出异常
setter方式单例,默认方式
Bean对象实例化之后再设置对象属性
setter方式原型,prototype
不进行缓存,不会提前暴露
JDK/Cglib区别
原理
JDK
拦截器(需实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类
调用InvokeHandler来处理
cglib
ASM开源包,通过修改字节码成子类
使用
实现接口
默认JDK
可强制使用cglib
CGLIB库
<aop:aspectj-autoproxy proxy-target-class="true"/>
没有实现
CGLIB库
性能
jdk1.6
cglib高
1.6之后
jdk
spring提供了什么扩展性
BeanFactory 和FactoryBean的区别
BeanFactory
IOC容器的最基本形式,并提供了IOC容器应遵守的的最基本的接口
FactoryBean
工厂类接口,用户可以通过实现该接口定制实例化Bean的逻辑
getObject()
返回由FactoryBean创建的Bean实例
booleanisSingleton()
返回作用域
Class<T>getObjectType()
返回创建的Bean类型
2.DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler。
BeanFactory和ApplicationContext的区别
相同点
是Spring的两大核心接口,都可以当做Spring的容器
不同点
描述
BeanFactory
只提供了实例化对象和拿对象的功能
ApplicationContext
应用上下文,提供5种的功能
装载bean
BeanFactory
延迟实例化
从容器中拿Bean的时候才会去实例化
ApplicationContext
不延迟实例化
容器启动时Bean全部实例化,缺点是耗内存
联系
ApplicationContext是BeanFactory的子接口
ApplicationContext
1) 国际化(MessageSource)
2) 访问资源,如URL和文件(ResourceLoader)
3) 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
4) 消息发送、响应机制(ApplicationEventPublisher)
ApplicationEvent:容器事件,必须由ApplicationContext发布;
ApplicationListener:监听器,可由容器中的任何监听器Bean担任。
5) AOP(拦截器)
1. preHandle:执行controller之前执行
2. postHandle:执行完controller,return modelAndView之前执行,主要操作modelAndView的值
3. afterCompletion:controller返回后执行
Spring框架中用到了哪些设计模式
7种
Spring MVC的工作原理
1.客户端(浏览器)发送请求,直接请求到DispatcherServlet。
3.解析到对应的Handler(也就是我们平常说的Controller控制器)。
4.HandlerAdapter会根据Handler来调用真正的处理器来处理请求和执行相对应的业务逻辑。
5.处理器处理完业务后,会返回一个ModelAndView对象,Model是返回的数据对象,View是逻辑上的View。
6.ViewResolver会根据逻辑View去查找实际的View。
7.DispatcherServlet把返回的Model传给View(视图渲染)。
8.把View返回给请求者(浏览器)。
@Component和@Bean的区别
1.作用对象不同。@Component注解作用于类,而@Bean注解作用于方法。
2.@Component注解通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中
3.@Bean注解比@Component注解的自定义性更强。
Spring框架中的单例bean是线程安全
不安全
Spring支持的事务管理类型
编程式事务管理
声明式事务管理
常用注解
@Controller
@Service
springBoot
优点
独立运行
简化配置
核心配置文件
bootstrap配置文件
application配置文件
自动配置
@EnableAutoConfiguration
应用监控
版本控制
RestFul
@PathVariable
核心注解
@SpingBootApplication
@SpringBootConfiguration
@Configuration
@EnableAutoConfiguration
@ComponentScan
单元测试
junit
常用注解
@Test
@Ignore
@Before
@After
@BeforeClass
@AfterClass
常用断言
SSM框架上使用
创建一个类
@RunWith
热部署
spring Loaded
pom.xml中的build添加spring-loaded依赖
spring-boot-devtools
pom.xml中的build添加spring-boot-devtools依赖
配置文件中添加
jRebel
springCloud
微服务之间通讯
Http通讯
消息通讯
事件驱动的通讯
消息中间件
java消息服务( Java Message Service,JMS)
面向消息中间件(MOM)的API
用于两个应用程序之间,或分布式系统中发送消息,进行异步通讯
常用协议
AMQP协议
MQTT协议
STOMP协议
XMPP协议
组成
Broker
消息服务器,作为server提供消息服务
Producer
消息生产者,业务发起方,负责生产消息传输给broker
Consumer
消息消费者,业务处理方,负责从broker获取消息并进行业务逻辑处理
Topic
主题,发布订阅模式下的消息统一汇集地,不同生产着向topic发送消息
由MQ服务器分发到不同不同订阅者,实现消息的广播
Queue
队列,PTP模式下,特定生产者向特定queue发送消息
消费者订阅特定的queue完成指定消息的接收
Message
消息体,根据不同通讯协议定义的固定格式进行编码的数据包
模式分类
PTP点对点
使用queue作为通信载体
pub/Sub发布订阅(广播)
使用topic做为通信载体
消息生产者(发布)将消息发布到topic,同时有多个消息消费者(订阅)消费该消息
从1到N个订阅者都能得到一个消息的拷贝
常见的消息中间件
RabbitMQ
使用Erlang编写的一个开源的消息队列, 支持很多协议
多用于进行企业级的ESB整合
ActiveMQ
Apache下使用Java完全支持JMS 1.1和J2EE 1.4规范的JMS
支持常用的多种语言客户端
kafka
Apache下使用scala实现的一个高性能分布式Publish/Subscribe消息队列系统
RocketMQ
阿里系下开源的一款分布式、队列模型的消息中间件
多用于订单交易系统
Redis
使用C语言开发的一个Key-Value的No SQL数据库
可以当做一个轻量级的队列服务来使用
ZeroMQ
号称最快的消息队列系统,专门为高吞吐量/低延迟的场景开发
在金融界的应用中经常使用,偏重于实时数据通信场景
优势
系统解耦
交互系统之间没有直接的调用关系,只是通过消息传输,故系统侵入性不强,耦合度低
提高响应时间
为大数据处理架构提供服务
应用场景
异步通信
解耦
冗余
扩展性
过载保护
可恢复
顺序保证
缓冲
数据流处理
RPC
Dubbo
CAP原理
c强一直性,A可用性,P分区容错
任何分布式系统只能保证满足其二,而分区容错是必须保证的
断路器
服务熔断
熔断机制是应对雪崩效应的一种微服务链路保护机制
当扇出链路的某个微服务不可用或者响应时间太长时,会进行降级
进而熔断该节点微服务的调用,快速返回“错误”的响应信息
服务降级
当某个服务熔断之后,服务器将不再被调用
客户端可以自己准备一个本地的fallback回调, 返回一个缺省值
@Hystrix Command
Spring Cloud框架里熔断机制通过Hystrix实现
5秒内调用20次,如果失败,就会启动熔断机制
核心组件
Eureka
各个服务启动时, Eureka Client都会将服务注册到Eureka Server
Eureka Client还可以反过来从Eureka Server拉取注册表, 从而知道
其他服务在哪里
其他服务在哪里
Ribbon
服务间发起请求的时候, 基于Ribbon做负载均衡, 从一个服务的多
台机器中选择一台
台机器中选择一台
Feign
基于Feign的动态代理机制, 根据注解和选择的机器, 拼接请求URL
地址,发起请求
地址,发起请求
Hystrix
通过Hystrix的线程池发起请求
避免了服务雪崩的问题
Zuul
如果前端、移动端要调用后端系统, 统一从Zu ul网关进入, 再转发请
不同的服务对应不同的线程池,实现了不同服务调用的隔离,
求给对应的服务
不同的服务对应不同的线程池,实现了不同服务调用的隔离,
求给对应的服务
案例
java基础
泛型和通配符
基本理解
自定义注解
持久层
mybatis
herbatis
ibatis
工具
Elasticsearch
前端
html
jsp
jquery
VUE
中间件
kafka
roketmq
redis
容器化技术
docker与微服务
基础篇(零基小白)
Docker简介
前提知识+课程定位+开场闲聊
是什么
问题:为什么会有docker出现
docker理念
一句话
解决了运行环境和配置问题的软件容器,
方便做持续集成并有助于整体发布的容器虚拟化技术。
容器与虚拟机比较
容器发展简史
传统虚拟机技术
容器虚拟化技术
对比
能干嘛
技术职级变化
coder
programmer
software engineer
DevOps engineer
开发/运维(DevOps)新一代开发工程师
一次构建、随处运行
更快速的应用交付和部署
更便捷的升级和扩缩容
更简单的系统运维
更高效的计算资源利用
· Docker应用场景
哪些企业在使用
新浪
美团
蘑菇街
......
去哪下
官网
docker官网:http://www.docker.com
仓库
Docker Hub官网: https://hub.docker.com/
Docker安装
前提说明
Docker的基本组成
镜像(image)
容器(container)
仓库(repository)
小总结
Docker平台架构图解(架构版)
首次懵逼正常,后续深入,先有大概轮廓,混个眼熟
整体架构及底层通信原理简述
安装步骤
CentOS7安装Docker
https://docs.docker.com/engine/install/centos/
安装步骤
确定你是CentOS7及以上版本
cat /etc/redhat-release
卸载旧版本
yum安装gcc相关
CentOS7能上外网
Subtopic
yum -y install gcc
yum -y install gcc-c++
安装需要的软件包
官网要求
执行命令
yum install -y yum-utils
设置stable镜像仓库
大坑
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
官网要求
推荐
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
我们自己
更新yum软件包索引
yum makecache fast
安装DOCKER CE
yum -y install docker-ce docker-ce-cli containerd.io
官网要求
执行结果
启动docker
systemctl start docker
测试
docker version
本次安装时间2021.11
docker run hello-world
卸载
systemctl stop docker
yum remove docker-ce docker-ce-cli containerd.io
rm -rf /var/lib/docker
rm -rf /var/lib/containerd
阿里云镜像加速
是什么
https://promotion.aliyun.com/ntms/act/kubernetes.html
注册一个属于自己的阿里云账户(可复用淘宝账号)
获得加速器地址连接
登陆阿里云开发者平台
点击控制台
选择容器镜像服务
获取加速器地址
粘贴脚本直接执行
直接粘
或者分步骤都行
mkdir -p /etc/docker
vim /etc/docker/daemon.json
重启服务器
systemctl daemon-reload
systemctl restart docker
永远的HelloWorld
启动Docker后台容器(测试运行 hello-world)
docker run hello-world
run干了什么
底层原理
为什么Docker会比VM虚拟机快
Docker常用命令
帮助启动类命令
启动docker: systemctl start docker
停止docker: systemctl stop docker
重启docker: systemctl restart docker
查看docker状态: systemctl status docker
开机启动: systemctl enable docker
查看docker概要信息: docker info
查看docker总体帮助文档: docker --help
查看docker命令帮助文档: docker 具体命令 --help
镜像命令
docker images
列出本地主机上的镜像
OPTIONS说明:
-a :列出本地所有的镜像(含历史映像层)
-q :只显示镜像ID。
docker search 某个XXX镜像名字
网站
https://hub.docker.com
命令
docker search [OPTIONS] 镜像名字
案例
OPTIONS说明:
--limit : 只列出N个镜像,默认25个
docker search --limit 5 redis
docker pull 某个XXX镜像名字
下载镜像
docker pull 镜像名字[:TAG]
docker pull 镜像名字
没有TAG就是最新版
等价于
docker pull 镜像名字:latest
docker pull ubuntu
docker system df 查看镜像/容器/数据卷所占的空间
docker rmi 某个XXX镜像名字ID
删除镜像
删除单个
docker rmi -f 镜像ID
删除多个
docker rmi -f 镜像名1:TAG 镜像名2:TAG
删除全部
docker rmi -f $(docker images -qa)
面试题:谈谈docker虚悬镜像是什么?
是什么
仓库名、标签都是<none>的镜像,俗称虚悬镜像dangling image
长什么样
后续Dockerfile章节再介绍
思考
结合我们Git的学习心得,大家猜猜是否会有
docker commit /docker push??
容器命令
有镜像才能创建容器,
这是根本前提(下载一个CentOS或者ubuntu镜像演示)
说明
docker pull centos
docker pull ubuntu
本次演示用ubuntu演示
新建+启动容器
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
OPTIONS说明
启动交互式容器(前台命令行)
列出当前所有正在运行的容器
docker ps [OPTIONS]
OPTIONS说明
退出容器
两种退出方式
exit
run进去容器,exit退出,容器停止
ctrl+p+q
run进去容器,ctrl+p+q退出,容器不停止
启动已停止运行的容器
docker start 容器ID或者容器名
重启容器
docker restart 容器ID或者容器名
停止容器
docker stop 容器ID或者容器名
强制停止容器
docker kill 容器ID或容器名
删除已停止的容器
docker rm 容器ID
一次性删除多个容器实例
docker rm -f $(docker ps -a -q)
docker ps -a -q | xargs docker rm
重要
有镜像才能创建容器,这是根本前提(下载一个Redis6.0.8镜像演示)
启动守护式容器(后台服务器)
在大部分的场景下,我们希望 docker 的服务是在后台运行的,
我们可以过 -d 指定容器的后台运行模式。
docker run -d 容器名
redis 前后台启动演示case
前台交互式启动
docker run -it redis:6.0.8
后台守护式启动
docker run -d redis:6.0.8
查看容器日志
docker logs 容器ID
查看容器内运行的进程
docker top 容器ID
查看容器内部细节
docker inspect 容器ID
进入正在运行的容器并以命令行交互
docker exec -it 容器ID bashShell
重新进入docker attach 容器ID
案例演示,用centos或者unbuntu都可以
上述两个区别
attach 直接进入容器启动命令的终端,不会启动新的进程
用exit退出,会导致容器的停止。
exec 是在容器中打开新的终端,并且可以启动新的进程
用exit退出,不会导致容器的停止。
推荐大家使用 docker exec 命令,因为退出容器终端,不会导致容器的停止。
用之前的redis容器实例进入试试
进入redis服务
docker exec -it 容器ID /bin/bash
docker exec -it 容器ID redis-cli
一般用-d后台启动的程序,再用exec进入对应容器实例
从容器内拷贝文件到主机上
容器→主机
docker cp 容器ID:容器内路径 目的主机路径
导入和导出容器
export 导出容器的内容留作为一个tar归档文件[对应import命令]
import 从tar包中的内容创建一个新的文件系统再导入为镜像[对应export]
案例
docker export 容器ID > 文件名.tar
cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
小总结
常用命令
Docker镜像
是什么
是什么
分层的镜像
UnionFS(联合文件系统)
Docker镜像加载原理
为什么 Docker 镜像要采用这种分层结构呢
重点理解
Docker镜像层都是只读的,容器层是可写的
当容器启动时,一个新的可写层被加载到镜像的顶部。
这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
Docker镜像commit操作案例
docker commit提交容器副本使之成为一个新的镜像
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
案例演示ubuntu安装vim
从Hub上下载ubuntu镜像到本地并成功运行
原始的默认Ubuntu镜像是不带着vim命令的
外网连通的情况下,安装vim
安装完成后,commit我们自己的新镜像
启动我们的新镜像并和原来的对比
小总结
本地镜像发布到阿里云
本地镜像发布到阿里云流程
镜像的生成方法
上一讲已经介绍过
基于当前容器创建一个新的镜像,新功能增强
docker commit [OPTIONS] 容器ID [REPOSITORY[:TAG]]
后面的DockerFile章节,第2种方法
将本地镜像推送到阿里云
本地镜像素材原型
阿里云开发者平台
https://promotion.aliyun.com/ntms/act/kubernetes.html
创建仓库镜像
选择控制台,进入容器镜像服务
选择个人实例
命名空间
继续
仓库名称
继续
进入管理界面获得脚本
将镜像推送到阿里云
将镜像推送到阿里云registry
管理界面脚本
脚本实例
将阿里云上的镜像下载到本地
下载到本地
本地镜像发布到私有库
本地镜像发布到私有库流程
是什么
Docker Registry
将本地镜像推送到私有库
下载镜像Docker Registry
运行私有库Registry,相当于本地有个私有Docker hub
案例演示创建一个新镜像,ubuntu安装ifconfig命令
从Hub上下载ubuntu镜像到本地并成功运行
原始的Ubuntu镜像是不带着ifconfig命令的
外网连通的情况下,安装ifconfig命令并测试通过
安装完成后,commit我们自己的新镜像
启动我们的新镜像并和原来的对比
curl验证私服库上有什么镜像
将新镜像zzyyubuntu:1.2修改符合私服规范的Tag
修改配置文件使之支持http
push推送到私服库
curl验证私服库上有什么镜像2
pull到本地并运行
Docker容器数据卷
坑:容器卷记得加入
--privileged=true
why
回顾下上一讲的知识点,参数V
是什么
一句话:有点类似我们Redis里面的rdb和aof文件
将docker容器内的数据保存进宿主机的磁盘中
运行一个带有容器卷存储功能的容器实例
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
能干嘛
数据卷案例
宿主vs容器之间映射添加容器卷
直接命令添加
命令
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
查看数据卷是否挂载成功
容器和宿主机之间数据共享
读写规则映射添加说明
读写(默认)
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名
默认同上案例,默认就是rw
只读
容器实例内部被限制,只能读取不能写
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
卷的继承和共享
容器1完成和宿主机的映射
容器2继承容器1的卷规则
docker run -it --privileged=true --volumes-from 父类 --name u2 ubuntu
Docker常规安装简介
总体步骤
搜索镜像
拉取镜像
查看镜像
启动镜像
服务端口映射
停止容器
移除容器
安装tomcat
docker hub上面查找tomcat镜像
docker search tomcat
从docker hub上拉取tomcat镜像到本地
docker pull tomcat
docker images查看是否有拉取到的tomcat
使用tomcat镜像创建容器实例(也叫运行镜像)
docker run -it -p 8080:8080 tomcat
-p 小写,主机端口:docker容器端口
-P 大写,随机分配端口
i:交互
t:终端
d:后台
访问猫首页
问题
解决
可能没有映射端口或者没有关闭防火墙
把webapps.dist目录换成webapps
先成功启动tomcat
查看webapps 文件夹查看为空
免修改版说明
docker pull billygoo/tomcat8-jdk8
docker run -d -p 8080:8080 --name mytomcat8 billygoo/tomcat8-jdk8
安装mysql
docker hub上面查找mysql镜像
从docker hub上(阿里云加速器)拉取mysql镜像到本地标签为5.7
使用mysql5.7镜像创建容器(也叫运行镜像)
命令出处,哪里来的?
简单版
使用mysql镜像
建库建表插入数据
外部Win10也来连接运行在dokcer上的mysql容器实例服务
问题
插入中文数据试试
为什么报错?
docker上默认字符集编码隐患
删除容器后,里面的mysql数据如何办
容器实例一删除,你还有什么?
删容器到跑路。。。。。?
实战版
新建mysql容器实例
新建my.cnf
通过容器卷同步给mysql容器实例
重新启动mysql容器实例再重新进入并查看字符编码
再新建库新建表再插入中文测试
结论
假如将当前容器实例删除,再重新来一次,之前建的db01实例还有吗?trytry
安装redis
从docker hub上(阿里云加速器)拉取redis镜像到本地标签为6.0.8
入门命令
命令提醒:容器卷记得加入--privileged=true
在CentOS宿主机下新建目录/app/redis
mkdir -p /app/redis
将一个redis.conf文件模板拷贝进/app/redis目录下
/app/redis目录下修改redis.conf文件
默认出厂的原始redis.conf
使用redis6.0.8镜像创建容器(也叫运行镜像)
测试redis-cli连接上来
请证明docker启动使用了我们自己指定的配置文件
修改前
修改后
记得重启服务
测试redis-cli连接上来第2次
安装Nginx
见高级篇Portainer
高级篇(大厂进阶)
Docker复杂安装详说
安装mysql主从复制
主从复制原理
默认你懂
主从搭建步骤
新建主服务器容器实例3307
进入/mydata/mysql-master/conf目录下新建my.cnf
vim my.cnf
修改完配置后重启master实例
docker restart mysql-master
进入mysql-master容器
docker exec -it mysql-master /bin/bash
mysql -uroot -proot
master容器实例内创建数据同步用户
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
新建从服务器容器实例3308
进入/mydata/mysql-slave/conf目录下新建my.cnf
vim my.cnf
修改完配置后重启slave实例
docker restart mysql-slave
在主数据库中查看主从同步状态
show master status;
进入mysql-slave容器
docker exec -it mysql-slave /bin/bash
mysql -uroot -proot
在从数据库中配置主从复制
主从复制命令参数说明
在从数据库中查看主从同步状态
show slave status \G;
在从数据库中开启主从同步
分支主题
查看从数据库状态发现已经同步
主从复制测试
主机新建库-使用库-新建表-插入数据,ok
从机使用库-查看记录,ok
安装redis集群(大厂面试题第4季-分布式存储案例真题)
cluster(集群)模式-docker版
哈希槽分区进行亿级数据存储
面试题
1~2亿条数据需要缓存,请问如何设计这个存储案例
回答
单机单台100%不可能,肯定是分布式存储,用redis如何落地?
上述问题阿里P6~P7工程案例和场景设计类必考题目,
一般业界有3种解决方案
哈希取余分区
缺点那???
一致性哈希算法分区
是什么
能干嘛
提出一致性Hash解决方案。
目的是当服务器个数发生变动时,
尽量减少影响客户端到服务器的映射关系
3大步骤
算法构建一致性哈希环
服务器IP节点映射
key落到服务器的落键规则
优点
一致性哈希算法的容错性
一致性哈希算法的扩展性
缺点
一致性哈希算法的数据倾斜问题
小总结
哈希槽分区
是什么
哈希槽计算
3主3从redis集群扩缩容配置案例架构说明
见自己的processon笔记
开打步骤
3主3从redis集群配置
关闭防火墙+启动docker后台服务
systemctl start docker
新建6个docker容器redis实例
命令分步解释
docker run
创建并运行docker容器实例
--name redis-node-6
容器名字
--net host
使用宿主机的IP和端口,默认
--privileged=true
获取宿主机root用户权限
-v /data/redis/share/redis-node-6:/data
容器卷,宿主机地址:docker内部地址
redis:6.0.8
redis镜像和版本号
--cluster-enabled yes
开启redis集群
--appendonly yes
开启持久化
--port 6386
redis端口号
进入容器redis-node-1并为6台机器构建集群关系
进入容器
docker exec -it redis-node-1 /bin/bash
构建主从关系
一切OK的话,3主3从搞定
链接进入6381作为切入点,查看集群状态
链接进入6381作为切入点,查看节点状态
cluster info
cluster nodes
主从容错切换迁移案例
数据读写存储
启动6机构成的集群并通过exec进入
对6381新增两个key
防止路由失效加参数-c并新增两个key
查看集群信息
容错切换迁移
主6381和从机切换,先停止主机6381
6381主机停了,对应的真实从机上位
6381作为1号主机分配的从机以实际情况为准,具体是几号机器就是几号
再次查看集群信息
先还原之前的3主3从
先启6381
docker start redis-node-1
再停6385
docker stop redis-node-5
再启6385
docker start redis-node-5
主从机器分配情况以实际情况为准
查看集群状态
redis-cli --cluster check 自己IP:6381
主从扩容案例
新建6387、6388两个节点+新建后启动+查看是否8节点
进入6387容器实例内部
docker exec -it redis-node-7 /bin/bash
将新增的6387节点(空槽号)作为master节点加入原集群
检查集群情况第1次
重新分派槽号
检查集群情况第2次
槽号分派说明
为主节点6387分配从节点6388
检查集群情况第3次
主从缩容案例
目的:6387和6388下线
检查集群情况1获得6388的节点ID
将6388删除
从集群中将4号从节点6388删除
将6387的槽号清空,重新分配,本例将清出来的槽号都给6381
检查集群情况第二次
将6387删除
检查集群情况第三次
DockerFile解析
是什么
Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
概述
官网
https://docs.docker.com/engine/reference/builder/
构建三步骤
编写Dockerfile文件
docker build命令构建镜像
docker run依镜像运行容器实例
DockerFile构建过程解析
Dockerfile内容基础知识
1:每条保留字指令都必须为大写字母且后面要跟随至少一个参数
2:指令按照从上到下,顺序执行
3:#表示注释
4:每条指令都会创建一个新的镜像层并对镜像进行提交
Docker执行Dockerfile的大致流程
(1)docker从基础镜像运行一个容器
(2)执行一条指令并对容器作出修改
(3)执行类似docker commit的操作提交一个新的镜像层
(4)docker再基于刚提交的镜像运行一个新容器
(5)执行dockerfile中的下一条指令直到所有指令都执行完成
小总结
DockerFile常用保留字指令
参考tomcat8的dockerfile入门
https://github.com/docker-library/tomcat
FROM
基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from
MAINTAINER
镜像维护者的姓名和邮箱地址
RUN
容器构建时需要运行的命令
两种格式
shell格式
exec格式
RUN是在 docker build时运行
EXPOSE
当前容器对外暴露出的端口
WORKDIR
指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
USER
指定该镜像以什么样的用户去执行,如果都不指定,默认是root
ENV
用来在构建镜像过程中设置环境变量
ADD
将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
COPY
类似ADD,拷贝文件和目录到镜像中。
将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置 :源文件或者源目录 :容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
COPY src dest
COPY ["src", "dest"]
VOLUME
容器数据卷,用于数据保存和持久化工作
CMD
指定容器启动后的要干的事情
注意
Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
参考官网Tomcat的dockerfile演示讲解
官网最后一行命令
分支主题
我们演示自己的覆盖操作
分支主题
它和前面RUN命令的区别
CMD是在docker run 时运行。
RUN是在 docker build时运行。
ENTRYPOINT
也是用来指定一个容器启动时要运行的命令
类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,
而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序
命令格式和案例说明
优点
在执行docker run的时候可以指定 ENTRYPOINT 运行所需的参数。
注意
如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
小总结
案例
自定义镜像mycentosjava8
要求
Centos7镜像具备vim+ifconfig+jdk8
JDK的下载镜像地址
官网
https://mirrors.yangxingzhen.com/jdk/
编写
准备编写Dockerfile文件
大写字母D
构建
docker build -t 新镜像名字:TAG .
注意,上面TAG后面有个空格,有个点
运行
docker run -it 新镜像名字:TAG
再体会下UnionFS(联合文件系统)
虚悬镜像
是什么
仓库名、标签都是的镜像,俗称dangling image
Dockerfile写一个
查看
docker image ls -f dangling=true
命令结果
删除
家庭作业-自定义镜像myubuntu
编写
准备编写DockerFile文件
构建
docker build -t 新镜像名字:TAG .
运行
docker run -it 新镜像名字:TAG
小总结
Docker微服务实战
通过IDEA新建一个普通微服务模块
建Module
docker_boot
改POM
写YML
主启动
业务类
通过dockerfile发布微服务部署到docker容器
IDEA工具里面搞定微服务jar包
编写Dockerfile
Dockerfile内容
将微服务jar包和Dockerfile文件上传到同一个目录下/mydocker
构建镜像
docker build -t zzyy_docker:1.6 .
打包成镜像文件
运行容器
访问测试
Docker网络
是什么
docker不启动,默认网络情况
ens33
lo
virbr0
docker启动后,网络情况
查看docker网络模式命令
常用基本命令
All命令
查看网络
docker network ls
查看网络源数据
docker network inspect XXX网络名字
删除网络
docker network rm XXX网络名字
案例
能干嘛
容器间的互联和通信以及端口映射
容器IP变动时候可以通过服务名直接网络通信而不受到影响
网络模式
总体介绍
bridge模式:使用--network bridge指定,默认使用docker0
host模式:使用--network host指定
none模式:使用--network none指定
container模式:使用--network container:NAME或者容器ID指定
容器实例内默认网络IP生产规则
说明
结论
docker容器内部的ip是有可能会发生改变的
案例说明
bridge
是什么
案例
说明
代码
docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8
两两匹配验证
host
是什么
案例
说明
代码
警告
docker run -d -p 8083:8080 --network host --name tomcat83 billygoo/tomcat8-jdk8
正确
docker run -d --network host --name tomcat83 billygoo/tomcat8-jdk8
无之前的配对显示了,看容器实例内部
没有设置-p的端口映射了,如何访问启动的tomcat83??
none
是什么
禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)
案例
docker run -d -p 8084:8080 --network none --name tomcat84 billygoo/tomcat8-jdk8
container
是什么
案例
docker run -d -p 8085:8080 --name tomcat85 billygoo/tomcat8-jdk8
docker run -d -p 8086:8080 --network container:tomcat85 --name tomcat86 billygoo/tomcat8-jdk8
运行结果
案例2
Alpine操作系统是一个面向安全的轻型 Linux发行版
docker run -it --name alpine1 alpine /bin/sh
docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh
运行结果,验证共用搭桥
假如此时关闭alpine1,再看看alpine2
自定义网络
过时的link
是什么
案例
before
案例
docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8
上述成功启动并用docker exec进入各自容器实例内部
问题
按照IP地址ping是OK的
按照服务名ping结果???
after
案例
自定义桥接网络,自定义网络默认使用的是桥接网络bridge
新建自定义网络
新建容器加入上一步新建的自定义网络
docker run -d -p 8081:8080 --network zzyy_network --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --network zzyy_network --name tomcat82 billygoo/tomcat8-jdk8
互相ping测试
问题结论
自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)
自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)
自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)
Docker平台架构图解
整体说明
整体架构
Docker-compose容器编排
是什么
Docker-Compose是Docker官方的开源项目,
负责实现对Docker容器集群的快速编排。
能干嘛
去哪下
官网
https://docs.docker.com/compose/compose-file/compose-file-v3/
官网下载
https://docs.docker.com/compose/install/
安装步骤
卸载步骤
Compose核心概念
一文件
docker-compose.yml
两要素
服务(service)
一个个应用容器实例,比如订单微服务、库存微服务、mysql容器、nginx容器或者redis容器
工程(project)
由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。
Compose使用的三个步骤
编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中的各个容器服务。
最后,执行docker-compose up命令 来启动并运行整个应用程序,完成一键部署上线
Compose常用命令
Compose编排微服务
改造升级微服务工程docker_boot
以前的基础版
SQL建表建库
一键生成说明
改POM
写YML
主启动
业务类
config配置类
RedisConfig
SwaggerConfig
新建entity
User
UserDTO
新建mapper
新建接口UserMapper
src\main\resources路径下新建mapper文件夹并新增UserMapper.xml
新建service
新建controller
mvn package命令将微服务形成新的jar包
并上传到Linux服务器/mydocker目录下
编写Dockerfile
构建镜像
docker build -t zzyy_docker:1.6 .
不用Compose
单独的mysql容器实例
新建mysql容器实例
进入mysql容器实例并新建库db2021+新建表t_user
单独的redis容器实例
微服务工程
上面三个容器实例依次顺序启动成功
swagger测试
http://localhost:你的微服务端口/swagger-ui.html#/
上面成功了,有哪些问题?
先后顺序要求固定,先mysql+redis才能微服务访问成功
多个run命令......
容器间的启停或宕机,有可能导致IP地址对应的容器实例变化,映射出错,
要么生产IP写死(可以但是不推荐),要么通过服务调用
使用Compose
服务编排,一套带走,安排
编写docker-compose.yml文件
第二次修改微服务工程docker_boot
写YML
通过服务名访问,IP无关
mvn package命令将微服务形成新的jar包
并上传到Linux服务器/mydocker目录下
编写Dockerfile
构建镜像
docker build -t zzyy_docker:1.6 .
执行 docker-compose up
或者
执行 docker-compose up -d
进入mysql容器实例并新建库db2021+新建表t_user
测试通过
Compose常用命令
关停
Docker轻量级可视化工具Portainer
是什么
安装
官网
https://www.portainer.io/
https://docs.portainer.io/v/ce-2.9/start/install/server/docker/linux
步骤
docker命令安装
第一次登录需创建admin,访问地址:xxx.xxx.xxx.xxx:9000
设置admin用户和密码后首次登陆
选择local选项卡后本地docker详细信息展示
上一步的图形展示,能想得起对应命令吗?
登陆并演示介绍常用操作case
Docker容器监控之
CAdvisor+InfluxDB+Granfana
原生命令
操作
问题
是什么
容器监控3剑客
一句话
CAdvisor监控收集+InfluxDB存储数据+Granfana展示图表
CAdvisor
InfluxDB
Granfana
总结
compose容器编排,一套带走
新建目录
新建3件套组合的
docker-compose.yml
启动docker-compose文件
docker-compose up
查看三个服务容器是否启动
测试
浏览cAdvisor收集服务,http://ip:8080/
第一次访问慢,请稍等
cadvisor也有基础的图形展现功能,这里主要用它来作数据采集
浏览influxdb存储服务,http://ip:8083/
浏览grafana展现服务,http://ip:3000
ip+3000端口的方式访问,默认帐户密码(admin/admin)
配置步骤
配置数据源
选择influxdb数据源
配置细节
1
2
配置面板panel
1
2
3
4
5
6
到这里cAdvisor+InfluxDB+Grafana容器监控系统就部署完成了
终章の总结
知识回顾简单串讲和总结
进阶篇:雷丰阳老师的K8S
面试总结
面试汇总
第1章1.try catch打印日志的级别类型,怎么打印异常堆栈信息?2. 集合类型及底层原理,举例。重点list,hashMap.3.JVM原理及性能调优,GC原理4.JVM,JRE,JDK三者关系?https://blog.csdn.net/Leo_01169/article/details/884149685.Spring特性,常见注解,SpringMVC流程图6.多线程7.Sychronized lock差别8.锁的类型,级别9.线程池优缺点,类型,常见参数10.sql调优,执行计划关注列11.存储过程,函数12.索引类型,及其数据结构(B+树,hash),原则使用13.拦截器,过滤器14.数据库引擎,差异。事务的三种提交类型及其常见关键字15.事务特性,常见隔离级别16.redis原理,数据类型,持久化类型,与其他缓存差异(mencashed)17.Kafka、ActiveMQ、RabbitMQ、RocketMQ 区别以及高可用原理https://www.cnblogs.com/jay-wu/p/10287636.html18.dubbo,zookeeper19.session cookie20.js jQuery,Vue,AngularJS21.分布式,集群,docker部署22.linux常见命令
1.try catch打印日志的级别类型,怎么打印异常堆栈信息?
debug, info, warn, error, fatal。
log.error("ERROR", "Error found: ", e);
2.分布式事务
分布式系统中一次操作由多个系统协同完成,这种一次事务操作涉及多个系统通过网络协同完成的过程称为分布式事务。
3.分布式事务的应用场景
电商系统中的下单扣库存
金融系统中的银行卡充值
教育系统中下单选课业务
sNS系统的消息发送
4.CAP理论
在进行分布式系统设计时,同时满足“一致性”、“可用性”和“分区容忍性”三者是几乎不可能的
组合
CA:放弃分区容忍性,加强一致性和可用性,关系数据库按照CA进行设计
AP:放弃一致性,加强可用性和分区容忍性,追求最终一致性,很多NoSQL数据库按照AP进行设计。
CP:放弃可用性,加强一致性和分区容忍性,一些强一致性要求的系统按CP进行设计,比如跨行转账,一次转账请求要等待双方银行系统都完成整个事务才算完成。
总结
在分布式系统设计中AP的应用较多,即保证分区容忍性和可用性,牺牲数据的强一致性(写操作后立刻读取到最新数据),保证数据最终一致性。
5.什么是幂等性?
幂等性是指同一个操作无论请求多少次,其结果都相同。
实现
1、操作之前在业务方法进行判断如果执行过了就不再执行。
2、缓存所有请求和处理的结果,已经处理的请求则直接返回结果。
3、在数据库表中加一个状态字段(未处理,已处理),数据操作时判断未处理时再处理。
6.分布式事务的解决方案
两阶段提交协议(2PC)
两个阶段
第一阶段:准备阶段(prepare)
协调者通知参与者准备提交订单,参与者开始投票。协调者完成准备工作向协调者回应Yes。
2)第二阶段:提交(commit)/回滚(rollback)阶段
协调者根据参与者的投票结果发起最终的提交指令。如果有参与者没有准备好则发起回滚指令。
优点
实现强一致性,部分关系数据库支持(Oracle、MySQL等)。
缺点
整个事务的执行需要由协调者在多个节点之间去协调,增加了事务的执行时间,性能低下。
事务补偿(TCC)
TCC事务补偿是基于2PC实现的业务层事务控制方案
Try、Confirm和Cancel
1、Try 检查及预留业务资源完成提交事务前的检查,并预留好资源。
2、Confirm 确定执行业务操作对try阶段预留的资源正式执行
3、Cancel 取消执行业务操作对try阶段预留的资源释放。
优点
最终保证数据的一致性,在业务层实现事务控制,灵活性好。
缺点
开发成本高,每个事务操作每个参与者都需要实现try/confirm/cancel三个接口。
注意
TCC的try/confirm/cancel接口都要实现幂等性,在为在try、confirm、cancel失败后要不断重试。
消息队列实现最终一致
布式事务拆分成多个本地事务来完成,并且由消息队列异步协调完成
实现最终事务一致要求
预留资源成功理论上要求正式执行成功,如果执行失败会进行重试,要求业务执行方法实现幂等。
优点
由MQ按异步的方式协调完成事务,性能较高。
不用实现try/confirm/cancel接口,开发成本比TCC低。
缺点
此方式基于关系数据库本地事务来实现,会出现频繁读写数据库记录,浪费数据库资源,另外对于高并发操作不是最佳方案。
7.谈谈对volatile的理解
1.volatile是java虚拟机提供的轻量级同步机制
保证可见性
禁止指令重排序
不保证原子性
2.JMM的认识
java内存模型
可见性
原子性
有序性
多线程环境中线程交替执行,由于编译器优化重排的存在,两个线程中使用的变量能否保证一致性是无法确定的
单线程情况下,最终结果是一样的
指令重排
源代码
编译器优化的重排
指令并行的重排
内存系统的重排
最终的执行指令
3.那些地方用过volatile
double check lock的单例模式
8.cas的理解
CompareAndSwap
cpu的一句指令原语
AtomicInteger的compareAndSet(期望值,修改值)
原理
自旋锁 + unSafe(rt.jar/sun/misc)
缺点
循环时间长,开销大
只能保证一个共享变量的原子操作
存在ABA问题
9.QPS、TPS、并发用户数、吞吐量的关系了
QPS
每秒的响应请求数,也即是最大吞吐能力。
特定的查询服务器在规定时间内所处理流量多少的衡量标准
TPS
也就是事务数/秒
QPS和TPS区别
Tps即每秒处理事务数
用户请求服务器
服务器自己的内部处理
服务器返回给用户
Qps基本类似于Tps,但是不同的是,对于一个页面的一次访问,形成一个Tps;但一次页面请求,可能产生多次对服务器的请求,服务器对这些请求,就可计入“Qps”之中。
并发数
系统同时能处理的请求数量,同样反应了系统的负载能力
分析机器1s内的访问日志数量来得到
吐吞量
系统在单位时间内处理请求的数量,TPS、QPS都是吞吐量的常用量化指标
系统吞吐量要素
一个系统的吞吐量(承压能力)与request(请求)对cpu的消耗,外部接口,IO等等紧密关联。
单个request 对cpu消耗越高,外部系统接口,IO影响速度越慢,系统吞吐能力越低,反之越高。
重要参数
QPS(TPS):每秒钟request/事务 数量
并发数:系统同时处理的request/事务数
响应时间:一般取平均响应时间
并发数:系统同时处理的request/事务数
响应时间:一般取平均响应时间
关系
QPS(TPS)=并发数/平均响应时间
PV
面访问量,即页面浏览量或点击量,用户每次刷新即被计算一次。可以统计服务一天的访问日志得到。
UV
独立访客,统计1天内访问某站点的用户数。可以统计服务一天的访问日志并根据用户的唯一标识去重得到。
DAU
日活跃用户数量。常用于反映网站、互联网应用或网络游戏的运营情况
MAU
月活跃用户数量,指网站、app等去重后的月活跃用户数量
系统吞吐量评估
找出系统的最高TPS和日PV
通过压力测试或者经验预估,得出最高TPS
10.AtomicInteger的ABA问题
问题引入
CAS -> Unsafe -> CAS底层思想 -> ABA -> 原子引用更新 -> 如何规避ABA问题
怎么规避ABA问题
AtomicStampedReference,实现是给值加一个版本号
11.集合类不安全问题ArrayList
ArrayList
解决方案
new Vector<>()
Collecttions.synchronizedList(new ArrayList<>())
new CopyOnWriterArrayList()
写时复制
Arrays.conpyOf
java.util.concurrentModificationException
并发修改的异常
HashSet
底层实现是HashMap
new CopyOnWriterArraySet()
HashMap
ConcurrentHashMap
12.java锁
公平锁和非公平锁
公平锁
按照申请锁的顺序来获取锁
非公平锁
ReentrantLock()默认是非公平锁
不按照申请锁的顺序来获取锁
区别
非公平锁上来就直接尝试站有锁,如果尝试失败,在采取公平锁那种方式
非公平锁优点在于吞吐量比公平锁大
可重入锁(递归锁)
线程进入一个同步锁的代码块,里边的方法也具有锁的机制
作用
防止死锁
问题
如果加锁两次,释放锁一次,结果会怎么样
编译正常,运行死锁
自旋锁
线程不会立即阻塞,而是循环的方式尝试获取锁
缺点
循环会消耗cpu
独占锁(写锁)/共享锁(读锁)/互斥锁
独占锁
该锁一次只能被一个线程锁持有
ReentrantLock
Synchronized
共享锁
被多个线程持有
13.CountDownLatch/CyclicBarrier/Semaphore使用过吗?
CountDownLatch
减法
CyclicBarrier
加法
Semaphore
两个目的
多个共享资源的互斥使用
并发线程数的控制
14.阻塞队列
什么是阻塞队列
当队列为空.取元素就会被阻塞
当队列满时,添加元素就会被阻塞
阻塞队列架构
核心方法
插入,移除,取出
15.Synchronized和Lock的区别
Synchronized是关键字,jvm层面
Lock是api层面的锁
16.线程池
特点
线程复用
控制最大并发数
管理线程
优势
降低资源消耗
提高响应速度
提高线程的可管理性
7大参数
底层工作原理
合理配置线程池参数
获取cpu的情况,几核
Runtine.getRuntime() .availableProcessors()
cpu密集
没有阻塞,CPU一直全速执行
cpu核数+1
IO密集
需要大量的IO,即有大量的阻塞
一般是 2*cpu核数
参考公式:cpu核数/(1-阻塞系数)
阻塞系数在0.8-0.9之间
比如8核, 8/(1-0.9)=80个
17.死锁及定位
死锁
因争夺资源而出现的相互等待
产生原因
系统资源不足
资源分配不足
定位
windows
jps
jps -l
查看进程号
jstatck pid
打印故障信息
linux
ps -ef|grep
ls -l
18.jvm结构
结构
私有
共有
那些对象可以作为GC ROOTS的对象
虚拟机栈(栈帧中的局部变量区,也叫做局部变量表)中引用的对象
方法区中的类静态属性引用的对象
方法区中常量引用的对象。
本地方法栈中JNI(Native方法) 引用的对象。
19.怎么查看jvm默认参数
三类参数
标配参数
-version
-help
-showversion
x参数
-Xint
解释执行
-Xcomp
第一次使用就编译成本地代码
-Xmixed
混合模式
xx参数
Boolean类型
公式
-XX +某个属性值
+ 表示开启
- 表示关闭
Case
是否打印GC收集细节
是否使用串行垃圾回收器
KV类型
公式
-XX 属性=属性值
case
-XX:MetaspaceSize=128m
-XX:MaxTenuringThreshold=15
特殊
-Xms
-XX:initialHeapSize
-Xmx
-XX:MaxHeapSize
怎么查看在运行的java程序的某个jvm参数,具体值
jps -l
进程编号
jinfo -flag 配置项 Pid
查看单个jvm参数
jinfo -flags Pid
查看多个jvm参数
java -XX:+PrintFlagsIntitial
查看jvm初始默认值
java -XX:+PrintFlagsFinal
修改过的值
: =就是代表修改过后的
= 代表没有修改过
java -XX:PrintComandLineFlags -version
打印命令行参数
20.常用的jvm参数
-Xms
初始大小内存,默认是物理内存的1/64
-XX:InitialHeapSize
-Xmx
最大分配内存,默认是物理内存的1/4
-XX:MaxHeapSize
-Xss
设置单个线程栈的大小,一般默认为512k-1024k
-XX:ThreadStackSize
-Xmn
设置年轻代的大小
21.强软弱虚引用
强引用
出现了OOM,也不会对该对象的进行回收,
软引用
SoftReference
当系统内存充足时,不会被回收
当系统内存不足的时,被回收
应用
高速缓存
弱引用
只要有gc,一律回收
WeakReference
虚引用
22.OOM的认识
StackoverFlowErrorr
占空间撑满,递归调用
OutofMemeoryError
java heapSpace
GC overhead limit excuet
大部分时间都用处理垃圾收集工作
23.垃圾回收器的理解
垃圾回收器是算法的落地实现
串行
并行
并发
G1
将堆内存分割成不同的的区域然后并发的对其进行垃圾回收
24.查看服务的默认垃圾回收器
查看
java -XX:PrintComandLineFlags -version
java8默认是 -XX: +UseParallelGC
25.redis分布式锁
分布式锁的场景
互联网秒杀--锁库存
抢优惠券
接口幂等性校验
setNx 和set的区别
setNx
set if not exist
当key不存在设置为value,如果存在不做处理
锁失效
超时时间设置不合理的
导致第三个线程释放第二个线程的锁,导致一直失效
解决方案
String clientId=UUID.randomUUID().toString()
加锁时设置线程id
释放锁时判断是当前线程ID
redission
解决锁超时问题,设置不合理问题
3.6.5
lock()
默认超时时间30s
具有锁续命问题
大约是timeout/3的时间尝试检查一次,是否执行结束
26.mysql必考的sql
查询重复的数据
select * from A where `name` in (select A1.`name` from A A1 GROUP BY A1.`name` HAVING COUNT(A1.`name`)>1);
根据条件更新新表数据
update a t1,b t2 set t1.`name` = t2.`name`,t1.p_id=t2.p_id where t1.id = t2.id;
27.Eureka工作原理
Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。
组件
Eureka Server
Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client
用于简化与Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。
心跳30s,轮训三次移除服务节点
Application Service
服务提供方,是注册到Eureka Server中的服务。
Application Client
服务消费方,通过Eureka Server发现服务,并消费。
28.Eureka和Zookeeper的区别
cap组合
CA,放弃P
如果想避免分区容错性问题的发生,一种做法是将所有的数据(与事务相关的)/服务都放在一台机器上。虽然无法100%保证系统不会出错,但不会碰到由分区带来的负面效果。当然这个选择会严重的影响系统的扩展性。
CP,放弃A
相对于放弃"分区容错性"来说,其反面就是放弃可用性。一旦遇到分区容错故障,那么受到影响的服务需要等待一定时间,因此在等待时间内系统无法对外提供服务。
AP,放弃C
这里所说的放弃一致性,并不是完全放弃数据一致性,而是放弃数据的强一致性,而保留数据的最终一致性。以网络购物为例,对只剩下一件库存的商品,如果同时接受了两个订单,那么较晚的订单将被告知商品告罄。
对比
Zookeeper
CP
Zookeeper是主从模式,符合一致性,
但是leader宕机,选举的期间不可用,选举新的leader之后对外提供服务
Eureka
AP
Eureka分布式集群是基于平等模式的,无主模型,所以每个节点可能不会实时一致,
如果某个节点宕机,接受的请求会转交给其他节点
29.dns域名解析
先在本地的host文件查找是否配置域名解析,如果没有配置,就去运营商查找
30.nginx的原理
nginx能够实现反向代理、负载均衡、故障转移、解决跨域、静态资源的缓存、服务器对的限流
Kafka、ActiveMQ、RabbitMQ、RocketMQ
1.为什么使用消息队列
解耦
一个系统或者一个模块,调用了多个系统或者模块,互相之间的调用很复杂,维护起来很麻烦。
异步
削峰
减少高峰期对服务器的压力
2.消息队列有什么优缺点
系统可用性降低
系统引入的外部依赖越多,越容易挂掉。如何保证消息队列的高可用
系统复杂度提高
保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性?
一致性问题
多个系统是否结果一致性
3,优缺点
单机吞吐量
ActiveMQ
万级,比 RocketMQ、Kafka 低一个数量级
RabbitMQ
同 ActiveMQ
RocketMQ
10 万级,支撑高吞吐
Kafka
10 万级,高吞吐,一般配合大数据类的系统来进行实时数据计算、日志采集等场景
topic 数量对吞吐量的影响
ActiveMQ
RabbitMQ
RocketMQ
topic 可以达到几百/几千的级别,吞吐量会有较小幅度的下降,这是 RocketMQ 的一大优势,在同等机器下,可以支撑大量的 topic
Kafka
topic 从几十到几百个时候,吞吐量会大幅度下降,在同等机器下,Kafka 尽量保证 topic 数量不要过多,如果要支撑大规模的 topic,需要增加更多的机器资源
时效性
ActiveMQ
ms 级
RabbitMQ
微秒级,这是 RabbitMQ 的一大特点,延迟最低
RocketMQ
ms 级
Kafka
延迟在 ms 级以内
可用性
ActiveMQ
高,基于主从架构实现高可用
RabbitMQ
高,基于主从架构实现高可用
RocketMQ
非常高,分布式架构
Kafka
非常高,分布式,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用
消息可靠性
ActiveMQ
有较低的概率丢失数据
RabbitMQ
基本不丢
RocketMQ
经过参数优化配置,可以做到 0 丢失
Kafka
同 RocketMQ
功能支持
ActiveMQ
MQ 领域的功能极其完备
RabbitMQ
基于 erlang 开发,并发能力很强,性能极好,延时很低
RocketMQ
MQ 功能较为完善,还是分布式的,扩展性好
Kafka
功能较为简单,主要支持简单的 MQ 功能,在大数据领域的实时计算以及日志采集被大规模使用
4.如何保证消息队列的高可用
RabbitMQ 的高可用性
比较有代表性的,因为是基于主从(非分布式)做高可用性的,我们就以 RabbitMQ 为例子讲解第一种 MQ 的高可用性怎么实现
RabbitMQ 有三种模式
单机模式
普通集群模式(无高可用性)
这就没有什么所谓的高可用性,这方案主要是提高吞吐量的,就是说让集群中多个节点来服务某个 queue 的读写操作。
镜像集群模式(高可用性)
每个 RabbitMQ 节点都有这个 queue 的一个完整镜像,包含 queue 的全部数据的意思。然后每次你写消息到 queue 的时候,都会自动把消息同步到多个实例的 queue 上。
Kafka 的高可用性
天然的分布式消息队列,就是说一个 topic 的数据,是分散放在多个机器上的,每个机器就放一部分数据。
写数据的时候,生产者就写 leader,然后 leader 将数据落地写本地磁盘,接着其他 follower 自己主动从 leader 来 pull 数据。一旦所有 follower 同步好数据了,就会发送 ack 给 leader,leader 收到所有 follower 的 ack 之后,就会返回写成功的消息给生产者。(当然,这只是其中一种模式,还可以适当调整这个行为)
消费的时候,只会从 leader 去读,但是只有当一个消息已经被所有 follower 都同步成功返回 ack 的时候,这个消息才会被消费者读到。
4.mq常见问题
消息顺序问题
消息有序是可以按照消息的发送顺序来消费
解决方案
保证生产者一对一关系
缺陷
并行度就会成为消息系统的瓶颈(吞吐量不够)
更多的异常处理
比如消费端出现异常,导致流程阻塞
不关注乱序的应用实际大量出现
队列无序并不意味着消息无序,还要从业务逻辑控制
消息重复问题
根本原因
网络不可达
如果消费端收到两条一样的消息,支持幂等性
5.RabbitMQ
特点
消费并不需要确保提供方存在,实现了服务之间的高度解耦
使用场景
服务间异步通信
顺序消费
定时任务
请求削峰
基本概念
Broker:
简单来说就是消息队列服务器实体
Exchange:
消息交换机,它指定消息按什么规则,路由到哪个队列
Queue:
消息队列载体,每个消息都会被投入到一个或多个队列
Binding:
绑定, 它的作用就是把exchange和queue按照路由规则绑定起来
Routing Key
路由关键字, exchange根据这个关键字进行消息投递
VHost
vhost可以理解为虚拟broker, 即mini-Rabbit MQ server。其内部均含有独立的queue、exchange和binding等, 但最最重要的是, 其拥有独立的权限系统, 可以做到vhost范围的用户控制。当然, 从Rabbit MQ的全局角度, vhost可以作为不同权限隔离的手段(一个典型的例子就是不同的应用可以跑在不同的vhost中) 。
Producer
消息生产者,就是投递消息的程序
Consumer:
消息消费者,就是接受消息的程序
Channel:
消息通道, 在客户端的每个连接里, 可建立多个channel, 每个channel代表一个会话任务
由Exchange、Queue、Routing Key三个才能决定一个从Exchange到Queue的唯一的线路。
工作模式
Simple模式
简单的收发模式
work工作模式
资源竞争
多个消费者谁先抢到谁消费
发布订阅
共享资源
由交换机将消息转发到绑定次交换机的每个队列
routing
路由模式
topic主题模式
路由模式一种
怎么保证消息的顺序性
拆分多个多个消息队列
每个消息队列一个消费者
或者一个消息队列
消息如何分发
若该队列至少有一个消费者订阅, 消息将以循环(round-robin) 的方式发送给
消费者。每条消息只会分发给一个订阅的消费者(前提是消费者能够正常处理消
息并进行确认)。通过路由可实现多消费的功能
消费者。每条消息只会分发给一个订阅的消费者(前提是消费者能够正常处理消
息并进行确认)。通过路由可实现多消费的功能
消息怎么路由
消息提供方->路由->一至多个队列消息发布到交换器时,消息将拥有一个路由
键(routing key) , 在消息创建时设定。通过队列路由键, 可以把队列绑定到
交换器上。消息到达交换器后, Rabbit MQ会将消息的路由键与队列的路由键
进行匹配(针对不同的交换器有不同的路由规则);
键(routing key) , 在消息创建时设定。通过队列路由键, 可以把队列绑定到
交换器上。消息到达交换器后, Rabbit MQ会将消息的路由键与队列的路由键
进行匹配(针对不同的交换器有不同的路由规则);
交换器
1.fanout:如果交换器收到消息, 将会广播到所有绑定的队列上
2.direct:如果路由键完全匹配, 消息就被投递到相应的队列
3.topic:可以使来自不同源头的消息能够到达同一个队列时,可以使用通配符
消息基于什么传输
使用信道传输数据,信道是建立tcp连接的,每条tcp上的信道数量没有限制
怎么保证消息正确发送值RabbitMq
发送方确认模式
接收方确认机制
怎么保证消息的可靠传输
不可能传输可能是消息丢失
生产者消息丢失
消费列表消息丢失
消费者消息丢失
劫持
6.kafka
什么是kafka
发布订阅开源消息代理应用程序
几个组件
topic
producer
consumer
brokers
使用场景
日志收集
消息系统
用户活动追踪
运营指标
流式处理
解释偏移的作用
给每个分区的消息提供一个序列ID号
什么是消息组
kafka独有的,每个kafka消费群体都有一个或者多个共同消费一组订阅主题的消费者组成
zookeeper在kafka中起什么作用
使用zookeeper构成的分布式系统
kafka的优点
高吞吐量
容错
低延迟
耐久性
kafka的缺点
没有完整的监控工具集
不支持通配符选择主题
kafka主要性能API
生产者
消费者
流
连接器
领导者和追随者
kafka每个分区中,都有一个服务器充当领导者,0-多个充当追随者
kafka怎么确保负载均衡
领导者执行分区的所有读写请求
追随者被动复制领导者
副本和ISR
复制日志的节点就是副本
ISR是与领导者同步副本
kafka的复制为什么重要
确保消息不被丢失,
jvm
1.jvm的内存模型以及分区情况和作用
jvm内存结构
线程共有
方法区
用于存储虚拟机加载类的类信息,常亮,静态变量等数据
堆
是JVM所管理的内存中最大的一块区域
存放对象实例,所有的对象和数组都要早堆上分配分配
线程私有
栈
java方法执行的内存模型
存储局部变量表,操作数栈,动态链接,方法出口等信息
本地方法栈
同虚拟机栈,不同点是本地方法栈为native方法执行服务
程序计数器
当前线程所执行的行号指示器
执行字节码就是利用程序计数器来选取下一条需要执行的字节码指令
2.java内存分配
寄存器
静态域
static定义的静态成员
常量池
.class文件中final常量和一些修饰的符号引用
类和接口的全限定名
字段的名称和描述符
方法的名称和描述符
非RAM存储
磁盘等永久存储空间
堆内存
new 创建的对象和数组,由java虚拟机自动垃圾回收器管理,回收慢
栈内存
基本类型的变量和对象的引用变量(堆内存空间的访问地址)
速度快,可以共享,但是大小与生存期必须确定,缺乏灵活性
3.堆内存结构
JVM的堆是运行时数据区, 所有类的实例和数组都是在堆上分配内存
在JVM启动的时候被创建,由存活和死亡的对象组成的。
死亡的对象是应用不可访问尚且还没有被垃圾收集器回收掉的对象。
4.内存泄漏和内存溢出
内存泄露(memory leak)
不在使用的对象或者变量在内存中占有存储空间
内存泄漏堆积后的后果就是内存溢出
内存溢出(out of memory)
程序申请内存时,没有足够的内存供申请者使用
例如int类型数据的存储空间,但是你却存储long类型的数据.内存不够用,就会报错OOM
关系
内存泄漏的堆积最终会导致内存溢出
内存溢出就是需要的空间超过实际分配的空间
内存泄漏是向系统申请的内存,没有清理,系统不能重新分配给所需的程序,jvm不能及时清理
内存溢出
栈满在进栈
栈空再退栈
常见场景
静态集合类
容器为静态的,那么它们的生命周期与程序一致,则容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏
各种连接
数据库连接、网络连接和IO连接等
Connection、Statement或ResultSet不显性地关闭,将会造成大量的对象无法被回收,从而引起内存泄漏。
变量不合理的作用域
一个变量的定义的作用范围大于其使用范围,很有可能会造成内存泄漏。
内部类持有外部类
外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内部类持有外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会造成内存泄露。
改变哈希值
对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,造成内存泄露
5.GC是什么?为什么使用GC
垃圾收集器(GabageCollection)
自动检测对象是否超过作用域从而达到自动回收内存的目的
java没有提供释放已分配内存的显示操作方法
6.java的垃圾回收机制
JVM中有一个低优先级的回收线程
正常情况下不会执行,只有当虚拟机空闲或者当堆内存不足时,才会触发执行,扫描没有任何引用的,并回收
7.判断一个对象存活
引用计数法
一般不采用
可达性算法
从一个被GC RootS的对象向下搜索,如果一个对象到GC Roots没有任何引用链,说明对象不可用
java中可以作为GC ROOTS的对象有几种
虚拟栈中引用的对象
方法区类静态属性引用的对象
方法区常量池引用的对象
本地方法栈JNI引用的对象
8.简述java内存分配与回收速率Minor GC 和FullGC
过程
对象优先在堆得Eden区分配
大对象直进入老年代
长期存活的对象直接进入老年代
当Eden区没有足够的空间进行分配时, 虚拟机会执行一次Minor GC(判断依据就是GC ROOT,看是不是被引用)。Minor
GC通常发生在新生代的Eden区, 在这个区的对象生存期短, 往往发生Gc的频率较高, 回收速度比较快;
Full GC/Major GC发生在老年代, 一般情况下,触发老年代GC的时候不会触发Minor GC, 但是通过配置, 可以在Full GC
之前进行一次Minor GC这样可以加快老年代的回收速度。
GC通常发生在新生代的Eden区, 在这个区的对象生存期短, 往往发生Gc的频率较高, 回收速度比较快;
Full GC/Major GC发生在老年代, 一般情况下,触发老年代GC的时候不会触发Minor GC, 但是通过配置, 可以在Full GC
之前进行一次Minor GC这样可以加快老年代的回收速度。
新生代
占1:3,其中eden 和幸存区(from .to 交替变化)的比例是8:1:1,每次在幸存区中存在一次,年龄增加1
minorGC
老年代
占2:3,当年龄到15,变成老年代,大对象直接变成老年代
FULL GC
9.介绍下JVM的中垃圾收集器由那些
新生代垃圾收集器
Serial Coping
只能使用一条线程进行垃圾收集工作,并且在进行垃圾收集的时候,所有的工作线程都需要停止工作,等待完成后,其他线程才可以继续工作
关注缩短垃圾回收时间
使用算法
复制算法
Paraller New
是Serial收集器的多线程版本
关注缩短垃圾回收时间
使用算法
复制算法
Parallel Scavenge
关注如何控制系统运行的吞吐量
吞吐量=CPU用于运行应用程序的时间和CPU总时间(CPU用于运行应用程序的时间+垃圾收集时间)的占比
使用算法
复制算法
老年垃圾收集器
Serial Old
也可以作为服务端应用程序的垃圾收集器
使用算法
标记-整理
串行回收
Paraller Old
关注吞吐量的
通常和Parallel Scavenge配合使用。可以实现对java堆内存的吞吐量优先的垃圾收集策略
使用算法
标记-整理
并行回收
CMS
Concurrent Mark Sweep
四个阶段
初始标记(用户线程暂停执行)
并发标记
重新标记
并发清理
使用算法
复制+标记清理
并发标记清除
其他
G1
步骤
初始标记
并发标记
重新标记
复制清除
使用算法
复制+标记整理
10.垃圾收集的方法有哪些
引用计数法
一般不采用
标记清除
产生问题
效率不高
会产生大量不连续的碎片
先标记然后统一回收
复制算法
解决效率问题
将内存一分为二,只用其中一块内存,就爱能存活的对象复制到另一块内存上,一次往复
标记整理
解决了产生碎片问题
当对象存活率较高时,也就解决了复制算法的效率问题.
清除对象的时候,将可回收对象移到一端,然后清理掉端界以外的对象,这样就不会产生内存碎片
分代收集
现在虚拟机垃圾收集大多采用这种方式,根据对象的生命周期,将堆分为新生代和老年代
新生代中,对象生存期短,使用复制算法
11.什么是类记载器
实现通过类的全限定名获取该类的二进制字节流的代码块叫做类加载器
四种类加载器
启动类加载器
加载java核心类库
扩展类加载器
加载java的扩展类
系统类记载器
java应用的类路径来加载java类
用户自定义加载器
继承ClassLoader
12.类加载器双亲委派机制
基本定义
如果一个类加载器,收到了类加载的请求,不会自己去加载这个类,而是委托父加载器去加载,依次向上
如果父加载器没有找到子类,则子类会尝试加载类
如果父加载器没有找到子类,则子类会尝试加载类
作用
避免类的重复加载
保证java程序安全稳定,java核心API定义类型不会被随意替换
13.什么是Class文件,class文件主要信息结构有哪些
calss文件是一组以8位字节为单位基础的二进制流,
class文件格式---伪结构
无符号数
是基本数据类型
以u1、u2、u4、u8分别代表1个字节、2个字节、4个字节、8个字节的无符号数,能够用来描写叙述数字、索引引用、数量值或者依照UTF-8编码构成的字符串值。
表
多个无符号数或者其它表作为数据项构成的复合数据类型
全部表都习惯性地以_info结尾。
14.JVM数据运行区,哪些会造成OOM的情况
除过数据运行区,其他区域
堆溢出
java.lang.OutOfMemoryError:Java heap space
栈溢出
java.lang.Stack Overflow Error
永久代溢出
java.lang.OutOfMemoryError:Perm Gen space
15,线上常用的JVM参数
数据区设置
Xms:初始堆大小
Xmx:最大堆大小
Xss:Java每个线程的Stack大小
XX:NewSize=n:设置年轻代大小
XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4。
XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5.
XX:MaxPermSize=n:设置持久代大小。
收集器设置
XX:+UseSerialGC:设置串行收集器
XX:+UseParallelGC::设置并行收集器
XX:+UseParalledIOldGC:设置并行年老代收集器
XX:+UseConcMarkSweepGC:设置并发收集器
GC日志打印设置
XX:+Print GC:打印GC的简要信息
XX:+Print GC Details:打印GC详细信息
XX:+Print GC TimeStamps:输出GC的时间戳
16.JVM提供的常用工具
jps
显示本地的java进程
jps
jinfo
运行环境参数
jinfo pid
jstat
监视虚拟机各种运行状态信息的命令工具
jstat -gc pid
jstack
监视JVM中当前所有线程的运行情况和线程当前状态
jastacj pid
jmap
监视jvm中物理内存占用情况
jmap pid
17.jvm调优
调优步骤
1.监控GC的状态
使用各种JVM工具,查看当前日志,分析当前JVM参数设置,并且分析当前堆内存快照和gc日志,根据实际的各区域内存划分和GC执时间,觉得是否进行优化。
2.生成堆的dump文件
通过JMX的MBean生成当前的Heap信息,大小为一个3G(整个堆的大小)的hprof文件,如果没有启动JMX可以通过Java的jmap命令来生成该文件。
3.分析dump文件
打开这个3G的堆信息文件,显然一般的Window系统没有这么大的内存,必须借助高配置的Linux,几种工具打开该文件:
Visual VM
IBM HeapAnalyzer
JDK 自带的Hprof工具
Mat(Eclipse专门的静态内存分析工具)推荐使用
备注:文件太大,建议使用Eclipse专门的静态内存分析工具Mat打开分析。
Visual VM
IBM HeapAnalyzer
JDK 自带的Hprof工具
Mat(Eclipse专门的静态内存分析工具)推荐使用
备注:文件太大,建议使用Eclipse专门的静态内存分析工具Mat打开分析。
5.调整GC类型和内存分配
如果内存分配过大或过小,或者采用的GC收集器比较慢,则应该优先调整这些参数,并且先找1台或几台机器进行beta,然后比较优化过的机器和没有优化的机器的性能对比,并有针对性的做出最后选择。
6.不断的分析和调整
通过不断的试验和试错,分析并找到最合适的参数,如果找到了最合适的参数,则将这些参数应用到所有服务器。
Tomcat
1) 解释什么是Jasper?
是Tomcat的JSP引擎
解析JSP,编译成java作为servlet
运行时,jasper允许自动检测jsp文件的更改并重新编译他们
2) 请说明select*from tab的输出结果是什么??
3) 请解释如何配置Tomcat来使用I IS和NTLM
4)请解释一下什么时候可以使用“.”,什么时候可以使用“0”?
5) 请解释Tomcat的默认端口是什么
6) 请解释Tomcat中使用的连接器是什么?
7) 请阐述Catalina的配置文件有哪些?
8) 请解释将Tomcat作为一个Windows服务运行会带来哪些好处?
9) 解释何时在Tomcat使用SSL?
10) 解释如何使用WAR文件部署web应用程序?
11) 解释什么是Tomcat Valve
12) 说明Tomcat配置了多少个Valve.?
13) 解释servlet如何完成生命周期?
14) 请说明NAT协议的目的是什么?
15) 请解释一下MAC代表什么.?
16) 请解释什么是Tomcat Coyote?
Nginx
1、请解释一下什么是Nginx?
Nginx是一个web服务器和反向代理服务器,用于Http、Https、SMTP、POP3和IMAP协议
2、请列举Nginx的一些特性
反向代理/L7负载均衡器
嵌入式Perl解释器
动态二进制升级
可用于重新编写URL, 具有非常好的PCRE支持
3、请列举Nginx和Apache之间的不同点
4、请解释Nginx如何处理HTTP请求.
Nginx使用反应器模式。主事件循环等待操作系统发出准备事件的信号, 这样数据就可以从套接字读取,在该实例中读取到缓冲区并进行处理。单个线程可以提供数万个并发连接。
5、在Nginx中,如何使用未定义的服务器名称来阻止处理请
只需将请求删除的服务器就可以定义为:Server(listen 80; servername”; return 444;}
这里,服务器名被保留为一个空字符串,它将在没有“主机”头字段的情况下匹配请求, 而一个特殊的Ng in x的非标准代码444被返回, 从而终止连接。
6、使用“反向代理服务器”的优点是什么?
反向代理服务器可以隐藏源服务器的存在和特征。它充当互联网云和web服务器之间的中间层这对于安全方面来说是很好的, 特别是当您使用web托管服务时。
7、请列举Nginx服务器的最佳用途,Nginx服务器的最佳用法是在网络上部署动态HTTP内容,使用SCGI、WSGI应.
用程序服务器、用于脚本的Fast CGl处理程序。它还可以作为负载均衡器。
8、请解释Nginx服务器上的Master和Worker进程分别是什么?
Master进程
读取及评估配置和维持
Worker进程
处理请求
9、请解释你如何通过不同于80的端口开启Nginx
为了通过一个不同的端口开启Nginx, 你必须进入/etc/Nginx/sitesenabled/, 如果这是默认文件, 那么你必须打开名为“default”的文件。编辑文件,并放置在你想要的端口:
Like server(listen 81;)
Like server(listen 81;)
10、请解释是否有可能将Nginx的错误替换为502错误、503
502=错误网关
503=服务器超载
11、在Nginx中,解释如何在URL中保留双斜线
12、请解释ngx_http_upstream_module的作用是什么.?
13、请解释什么是C10K问题?C10K问题是指无法同时处理大量客户端(10,000)的网络套接字。
14、请陈述stub_status和sub_filter指令的作用是什么?
15、解释Nginx是否支持将请求压缩到上游?
16、解释如何在Nginx中获得当前的时间?
17、用Nginx服务器解释-s的目的是什么?
18、解释如何在Nginx服务器上添加模块?
Netty
1.Netty是什么?
一款基于NIO(Nonblocking I/O)开发的网络通信卡框架
2.Netty的特点是什么?
高并发
对比与BIO(Blocking I/O),提高并发性
传输快
依赖零拷贝,尽量减少不必要的内存拷贝,实现高效传输
封装好
封装了NIO操作细节,易于接口调用
3.什么是Netty的零拷贝?
三个方面
Netty的接受哈发送ByteBuffer采用Direct Buffers ,使用堆外内存直接进行Socket读写,不需要进行字节缓冲的二次拷贝
提供了多个组合Buffer对象,可以聚合多个buffer对象
文件传输采用transferTo方法,可以直接将文件缓冲区的数据发送到目标Channel,避免传统通过循环write方式导致的内存拷贝问题
传统拷贝,
jvm将堆内存Buffer拷贝一份到直接内存中,然后才写入到Socket,多了一次内存拷贝
4.Netty的优势有哪些?
使用简单:封装了NIO的很多细节, 使用更简单。
功能强大:预置了多种编解码功能,支持多种主流协议。
定制能力强:可以通过Channel Handler对通信框架进行灵活地扩展
性能高:通过与其他业界主流的NIO框架对比, Netty的综合性能最优。
稳定:Netty修复了已经发现的所有NIO的bug, 让开发人员可以专注于业务本身。
社区活跃:Netty是活跃的开源项目, 版本迭代周期短, bug修复速度快。
5.Netty的应用场景有哪些?
Dubbo,默认使用Netty作为基础通讯组件
RocketMQ
6.Netty高性能表现在哪些方面?
IO线程模型:同步非阻塞,用最少的资源做更多的事。
内存零拷贝:尽量减少不必要的内存拷贝,实现了更高效率的传输。
内存池设计:申请的内存可以重用,主要指直接内存。内部实现是用一颗二叉查找树管理内存分配情况。
串形化处理读写:避免使用锁带来的性能开销。
高性能序列化协议:支持proto buf等高性能序列化协议。
7.Netty和Tomcat的区别?
作用不同
Tomcat是Servlet容器, 可以视为Web服务器
Netty是异步事件驱动的网络应用程序框架和工具用于简化网络编程, 例如TCP和UDP套接字服务器。
协议不同
Tomcat是基于http协议的Web服务器
Netty能通过编程自定义各种协议, 因为Netty本身自己能编码/解码字节流, 所有Netty可以实现, HTTP服务器、FTP服务器、UDP服务器、RPC服务器、Web Socket服务器、Red is的Proxy服务器、MySQL的Proxy服务器等等。
8.Netty中有那种重要组件?
Channel
Netty网络操作抽象类,它除了包括基本的I/O操作,如bind、connect、read、write等
Event Loop
主要是配合Channel处理I/O操作, 用来处理连接的生命周期中所发生的事情。
ChannelFuture
Netty框架中所有的I/O操作都为异步的,因此我们需要Channel Future的addListener) 注册一个Channel Future Listener监听事件,当操作执行成功或者失败时,监听就会自动触发返回结果。
Channel Handler
充当了所有处理入站和出站数据的逻辑容器。
Channel Pipeline
为Channel Handler链提供了容器, 当channel创建时,就会被自动分配到它专属的Channel Pipeline, 这个关联是永久性的。
9.Netty发送消息有几种方式?
直接写入Channel中, 消息从Channel Pipeline当中尾部开始移动;
写入和Channel Handler绑定的Channel Handler Context中, 消息从Channel Pipeline中的下一个Channel Handler中移动。
10.默认情况Netty起多少线程?何时启动?
Netty默认是CPU处理器数的两倍, bind完之后启动。
11.Netty支持哪些心跳类型设置?
readerldleTime
为读超时时间(即测试端一定时间内未接受到被测试端消息) 。
writerldleTime
为写超时时间(即测试端一定时间内向被测试端发送消息) 。
allldleTime
所有类型的超时时间
web
1.http和https的区别
区别
HTTP 的URL 以http:// 开头,而HTTPS 的URL 以https:// 开头
HTTP 是不安全的,而 HTTPS 是安全的
HTTP 标准端口是80 ,而 HTTPS 的标准端口是443
在OSI 网络模型中,HTTP工作于应用层,而HTTPS 的安全传输机制工作在传输层
HTTP 无法加密,而HTTPS 对传输的数据进行加密
HTTP无需证书,而HTTPS 需要CA机构wosign的颁发的SSL证书
HTTP 是不安全的,而 HTTPS 是安全的
HTTP 标准端口是80 ,而 HTTPS 的标准端口是443
在OSI 网络模型中,HTTP工作于应用层,而HTTPS 的安全传输机制工作在传输层
HTTP 无法加密,而HTTPS 对传输的数据进行加密
HTTP无需证书,而HTTPS 需要CA机构wosign的颁发的SSL证书
2.session和cookie的区别
概念
无状态的HTTP协议
超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器。
会话(Session)跟踪
Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份
cookie
用户请求服务器,服务器需要记录用户状态,给客户端颁发的cookie
分类
会话cookie
关闭浏览器,自动清除
持久cookie
cookie保存在硬盘,再次可以请求
cookie具有不可跨域性
Session
客户端访问服务器,服务器以某种形式将客户端信息记录在服务器上
session复制
session共享
比较
cookie数据存放在客户的浏览器上,session数据放在服务器上。
cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。
session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。
单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
可以考虑将登陆信息等重要信息存放为session,其他信息如果需要保留,可以放在cookie中。
应用场景
登录网站。第二天无法登录就是cookie
购物车就是session
3.get和post的区别
http报文请求头结构
区别
get比post更不安全
get传输的数据长度比post小,get通常为2k
get通过在URL后拼接字符串的形式传递参数,post将参数放在RequestBody中
get产生一个TCP数据包;post产生两个TCP数据包。
get会把 httpheader 和 data 一起发送给服务器,服务器会响应200
post会先把httpheader发送给服务端,服务端响应100,提示客户端继续发送。浏览器接着发送data给服务端。最终服务端响应200
get请求可以被缓存起来,post不行
4.防止XSS攻击
即跨站脚本攻击, 是一种常见于web应用于web应用程序中的计算机安全漏洞
方法
1.获取用户输入, 不用.innerHtml, 用innerText
2.对用户输入进行过滤, 如Html Encode函数实现应该至少进行&<>”'/等符号转义成&It>"&#x 27/
5.防sql注入
严格检查输入变量的类型和格式
过滤和转义特殊字符
利用mysql的预编译机制
PreparedStatement
前端参数检验
6.拦截器、过滤器、监听器的区别和使用
过滤器(Filter)
容器初始化时调用一次。使用过滤器的目的,是用来做一些过滤操作,获取我们想要获取的数据
拦截器(Interceptor)
只能对controller请求进行拦截
拦截器与过滤器的区别
拦截器是基于java的反射机制的。而过滤器是基于函数回调
拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
拦截器只能对action请求起作用,针对类,拦截器可以多次被调用。
滤器则可以对几乎所有的请求起作用,在容器启动是初始化调用init方法,以后每个请求都调用doFilter()。作用范围包含拦截器。
滤器则可以对几乎所有的请求起作用,在容器启动是初始化调用init方法,以后每个请求都调用doFilter()。作用范围包含拦截器。
拦截器可以访问action上下文、值栈里的对象(即方法中的对象),而过滤器不能访问
拦截器可以在方法前后,异常前请求后各调用一次后等调用,而过滤器只能在请求前和。
Filter在Servlet前后作用,Interceptor在方法的前后作用,异常抛出前后,具有更大的弹性。所以优先使用拦截器。
完整加载顺序就是 :ServletContext -> context-param -> listener-> filter -> servlet
完整加载顺序就是 :ServletContext -> context-param -> listener-> filter -> servlet
使用
监听器,实现 ServletContextListener 接口
在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。
过滤器必须实现java定义好的javax.servlet.Filter接口
doFilter(ServletRequest, ServletResponse, FilterChain)
一个完成过滤行为的方法。这同样是上游过滤器调用的方法。
init(FilterConfig)
由Web容器来调用完成过滤器的初始化工作。它保证了在第一次doFilter()调用前由容器调用。您能获取在 web.xml 文件中指定的初始化参数。
destroy()
由Web容器来调用来释放资源,doFilter()中的所有活动都被该实例终止后,调用该方法。
拦截器必须实现HandlerInterceptor接口
preHandle()
这个方法在handler执行之前被调用,在该方法中对用户请求 request 进行处理。如果程序员决定该拦截器对 请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件去处理请求,则返回false。
postHandle()
这个方法在handler执行后,但是DispatcherServlet 向客户端返回响应前被调用,在该方法中对用户请求request进行处理。
afterCompletion()
这个方法在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。view渲染完成、dispatcherServlet返回之前执行。
7.什么是CSRF攻击,如何避免?
跨站请求伪造
方式
1.请求令牌
2.token验证
3.配置angular提交表头
4.再次测试跨域post
8.请求转发和重定向
请求转发
request.getRequestDispatcher(URL地址).forward(request, response)
流程
客户端发送请求,Servlet做出业务逻辑处理。
Servlet调用forword()方法,服务器Servlet把目标资源返回给客户端浏览器
重定向
response.sendRedirect(URL地址)
流程
客户端发送请求,Servlet做出业务逻辑处理。
Servlet调用response.sendReadirect()方法,把要访问的目标资源作为response响应头信息发给客户端浏览器。
区别
请求转发,内部转发一个请求,url不会发生变化;重定向两个请求,url发生变化
重定向可以跨域,转发不行
9.简述TCP和UDP的区别?
1.基于连接与无连接
2.对于系统资源的要求(TCP较多,UDP少)
3.UDP程序结构较为简单
4.流模式与数据报模式5.TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证
2.对于系统资源的要求(TCP较多,UDP少)
3.UDP程序结构较为简单
4.流模式与数据报模式5.TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证
10.TCP为什么要三次握手,两次不行吗?为什么?
不行,因为为了防止已失效的连接请求又传送到服务器端,因而产生错误
11.说一下TCP粘包是怎么产生的?
要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包
接收数据端的应用层没有及时读取接收缓冲区中的数据,将会发生粘包
接收数据端的应用层没有及时读取接收缓冲区中的数据,将会发生粘包
12.OSI的七层模型都有哪些?
应用层,表示层,会话层,传输层,网络层,数据链路层,物理层
SpringCloud
1.什么是SpringCloud
基于SpringBoot的Spring集成应用程序,用于快速构建执行有限数据处理的应用程序
2.SpringCloud的优势
1与分布式系统相关的复杂性,网络问题、延迟开销,宽带问题
2服务发现
3.解决分布式系统的冗余问题
4负载均衡
5性能问题
6部署的复杂度
3.什么是微服务
1微服务是一种架构风格,不是服务
2.微服务颗粒度比较小
3.采用UNIX设计理念,每种服务只做一件事
4.微服务之间如何通讯
Http RestFul
5.服务熔断和服务降级
服务熔断
如果检查出啦频繁超时,就会把Consumer和provide的请求直接短路掉,不实际调用,而是返回一个mock的值
服务降级
Consumer
如果consumer发现某个provide出现异常,基本返回固定的数据
provide
当provide发现流量激增,保护自身稳定,可以降级
直接给consumer返回固定数据
需要写入数据库的,先写缓存,异步写入数据库
6.微服务的优缺点
优点
单一职责
自治
每个微服务可以独立部署、升级、标准化通信。对其他服务不产生影响
逻辑清晰
简化部署
可扩展
灵活组合
缺点
复杂度高
被调用方故障、过载、消息丢失等各种异常情况
运维复杂
通讯延迟
7.遇到的难点
超时
确保Hystrix超时时间长于Ribbon超时时间
feihn path
feign客户端若有contextpath,path="/*****" 来匹配服务名
版本
SpringBoot和Springcloud版本兼容
8.eureka和zookeeper的区别
zookeeper
选举机制.
选举大概是30-120s,有可能导致注册服务瘫痪
eureka
15分钟如果85%的节点没有正常的心跳,会认为客户端和注册中心出现了网络问题
Eureka从注册列表中移除没有心跳而过期的服务
Eureka节后新服务的注册和查询,但是不会同步到其它节点
当网络稳定时,当前实例会同步到其它节点
服务注册与发现原理
优点
每30s发送心跳检测,他将在90s内移除
注册信息和更新会每30s被复制到其它的Eureka节点
客户端会缓存一些服务实例信息
缺点
当服务不在线,不能及时知道.需要1-3个心跳
NetFlix的服务调用端使用Hystrrix来容错和降级
9.限流
http限流
nginx的limitzone
dubbo限流
提供请求相关的filter
ActiveLimitFilter
作用于客户端
ExecuteLimitFilter
服务端
TPSLimitFilter
作用于服务端
控制一定时间内的请求数
可配置请求间隔,无法找到默认是60s,根据tps表示允许调用的次数
使用AtomicInteger递减
SpringCloud限流
semaphore.maxqueue等
漏桶算法
令牌算法
Resis计数器限流
10.Eureka的缓存
第一层缓存,readOnlyCacheMap
本质是ConcurrentHashMap.JVM层次的只读缓存
通过和第二层缓存对比,如果不一致,以第二层缓存为准,定时刷新的时间是30s
第二层缓存readWriterCacheMap
本质是Guava缓存,最终缓存
缓存过期时间180s
缓存机制
每30s执行一次定时任务,定时去服务端获取注册信息,存入本地
11.熔断器
调用者调用异常服务时,快速返回结果,避免出现的同步等待,并且熔断器在一定时间后继续侦测执行结果,提供恢复调用的可能
12.雪崩效应
概念
因服务提供者不可用,并将不可用逐步放大的过程
形成原因
服务提供不可用
重试加大流量
调用者不可用
采用策略
流量控制
改进缓存模式
服务自动扩容
调用者降级
13.Hystrix断路器
由于某些原因,会回退方法,返回一些默认值
14.多个消费者调用同一个接口,eureka的分配方式
轮训策略
随机选择
最大可用策略
区域感知策略
15.接口限流方法
1限制瞬时并发数
2限制时间窗口内的平均速率
3限制远程接口调用速率
4限制mq消费速率
5根据网络连接数量,网络流量,CPU或内存负载等来限流
16.Rest和RPC的对比
RPC缺点是服务方和调用方依赖太强,需要对每一种就行定义
Rest是轻量级的接口,按照约定进行编码
17.SpringCloud bus
讲分布式的节点轻量的消息代理连接起来.用于广播配置文件的更改或者服务直接的通讯,监控
使用
添加依赖
配置rabbitmq
18.什么是幂等性,如何使用
重复执行一项任务,结果不变
主要作用数据源或远程调用,当接收一组以上指令时,只能处理一组指令
19.Zuul
相当于一个网络微服务架构的入口,所有的网络请求必须通过网关转发到内部请求
作用
统一管理微服务请求,权限控制,负载均衡,路由转发等等
20.网关和过滤器的区别
网关是对所有的服务的请求进行分析过滤,过滤器是对单个服务而言
网关
Niginx
Zuul
GateWay
21.分布式的配置中心
apollo
zookeeper
SpringCloud config
SpringBoot
1.SpringBoot的最大优势
约定优先配置
2.约定优先配置体现在哪里
SpringBoot Starter
启动时对资源进行初始化
SpringBoot Jpa
自动生成sql
3.SpringBoot Starter的工作原理
1SpringBoot启动去寻找spring.factories文件,扫描项目中所依赖的jar包
2.根据spring.factories加载AutoConfig类
2,根据@Confitional注解条件,自动配置并将Bean注入SpringContext
4.SpringBoot 的自动配置如何实现
@SpringBootApplication
@Configuration
@ComponentScan
@EnableAutoConfiguration
实现自动配置的入口
5.微服务同时调用多个接口,怎么支持事物
利用消息补偿机制来处理分布式的事物
6.各服务之间的通信,对Restful和Rpc这2中方式的选择
rpc通讯效率比较好
传统SOA治理中,rpc较多
SpringCloud默认使用restful
7.Spring Cache三种常用的缓存注解和意义
@Cacheable
用来声明方法可缓存
@CachePut
执行方法之前不会检查缓存,而是每次都会执行该方法,将结果保存在缓存
@CacheEvcit
触发缓存的清理
8.SpringBoot支持跨域请求
Jsonp
利用<script>的Src不受同源策略约束来跨域获取数据
利用代理
将请求发到后端同源地址的后端,后端通过请求转发避免跨域
H5支持的CORS协议
springBoot配置非同源请求
9.JPA和Hibernate的区别
JPA是一种ORM,Hibernate时Jpa的一个实现集
10.SpringBoot有那些特点
1较少开发,测试时间
2使用JavaConfig有助于避免使用XML
3.避免大量的maven导入和版本冲突
4,没有单独的web服务器需要,意味着不依赖Tomcat
5需要更少的配置
6基于环境的配置
11.javaConfig时什么
提供了IOC容器的纯java方法
面向对象的配置
减少消除XML配置
类型安全,重构友好
12.如何加载SpringBoot上更改,不需要重启
DevTools(生成环境禁用)
13.SpringBoot应用程序的安全性
Spring-boot-starter-security
配置类必须扩展WebSecurityConfigurerAdapter
14.SpringBoot实现分页
Spring Data-Jpa
15.使用SpringBoot实现异常处理
Spring提供了一种ControllerAdvice处理异常的有用方法
16.什么是CSRF攻击
跨站请求伪造
17.什么是WebSocket
一种计算机通讯协议,通过单个TCP连接提供全双工通讯
18.怎么监视所有的SpringBoot微服务
提供监视器端点以监控各个微服务的度量
SpringBoot Actuator
spring
1.Spring FrameWork
概念
开源应用,降低程序开发复杂度,轻量级、松耦合
优点
用户选择自己的组件
功能
轻量级
2MB
控制反转
实现了松散耦合
面向切面编程
将业务逻辑和系统服务分开
容器
管理对象的生命周期和配置
事物管理
可以扩展到本地事物或者全局事物
MVC
WEB框架的替代
JDBC异常
模块
2.Spring应用程序有哪些不同组件
接口
Bean类
Spring面向切面编程(AOP)
Bean配置文件
用户程序
3.什么是SpringIOC容器
使用依赖注入来管理组成应用程序的组件。通过读取配置元数据来接收对象实例化,配置和组装的指令
4.IOC和DI
概念
创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者 实例的工作通常由Spring容器来完成,然后注入调用者
三种方式
5.有多少中IOC容器
BeanFactory
ApplicationContext
6.IOC的好处
最小化代码量
易于测试
最小的影响和最小的侵入机制促进耦合
支持及时的实例化和延迟加载服务
7.Spring提供了哪些配置
1xml
注解
java API
8.Spring的作用域
request
每次Http请求会创建一个
session
一个HTTP session 会创建一个实例
global session
个全局的HTTP Session中,一个bean定义对应一个实例
9.Spring的生命周期
1.根据bean定义实例化bean
2.依赖注入填充属性
3.如果实现BeanNameAware,调用setBeanName()
4.如果实现BeanFactoryAware,调用setBeanFactory()
5.如果实现BeanPostProcess,调用preProcessBeforeInitalization()
6.如果指定了init方法,则调用
7.如果关联BeanPostProcessors,调用postProcessAfterInitalization()
8.如果实现了DiposableBean,当容器关闭,调用destory()
9.如果bean指定了destory,则调用
10.Spring的内部bean
bean作为另一个bean的属性
11.自动装配的方式
局限性
重写
基本数据类型
模糊特性
方式
byName
byType
构造函数
autodetect
先尝试autowire,在尝试byType
12.常用注解
1.Component
java类标记为bean
任何组件的通用构型
2.Repository
使未经检查的异常转换为Spring DataAccessException
3.Required
应用于bean属性的setter方法
3.Qualifier
多个bean,消除装配歧义
13.Spring支持的事物
三种类型
JDBC事务
局限于一个数据库
JTA(Java Transaction API)事务
跨越多个数据库,或者dao
容器事务
J2e提供事务,主要应用于ejb
两种方式
编程式事务
声明式事务
14.AOP
面向切面编程 Aspect
pointcount
横切和连接点的概念
一个方法的执行,或者异常的处理
advice
作为拦截器
Before,....
实现
静态代理
动态代理
JDK代理
CGLIB代理
15.SpringMVC的理解
概念
模型-视图-控制器
DispatcherServlet
1 http请求向前端控制器DisparcheServlet
2DispatcheServlet根据url调用handlerMapping获取Handler配置的对象
3.填充Handler入参,开始执行Handler(Controller)
4.Handler执行完成后,向DispatcheServlet返回一个ModelandView对象
5.ModleAndView解析View
6.视图负责将渲染的结果返回给客户端
16.为什么spring实例化是调用getbean()
当调用getBean()方法后,会判断容器中有没有bean,如果有getBean(bean),如果没有用getBean()创建
多线程
1.守护线程和用户线程的区别
分类
守护线程(Daemon)
用户线程(User)
区别
判断虚拟机何时离开,守护线程为其它线程服务,如果全部用户线程撤离,jvm将撤离
2.进程和线程的区别
进程是操作系统分配资源的最小单元,线程是操作系统调度的最小单元
3.线程上下文
切换和恢复cpu状态的过程
4.死锁活锁,和饥饿
死锁
两个以上线程抢占资源相互等待
产生条件
互斥条件
请求与保持条件
不可剥夺条件
循环等待条件
活锁
任务或者执行者没有被阻塞,但是某些条件没有满足,导致一直重复尝试
饥饿
一种或者多个线程因种种原因一直没有获取所需资源,一直无法执行
产生原因
高优先级线程吞噬所有低优先级的CPU时间
线程被永久堵塞在一个等待进入的同步快的状态
线程在等待一个也处于永久等待的完成的对象
5.线程的调度算法
时间片轮转,可以设置优先级
分时调度模型
轮流平均分配
抢占式调度模型
根据优先级分配
6.什么是线程组,为什么不推荐使用
ThreadGroup,安全隐患
7,Executor和Executors的区别
Executors工具类提供了多种线程池
Executor是接口执行我们的线程任务
ExecutorService继承Executor,进行扩展
内部使用ThreadPoolExecutor来创建线程
Future异步计算的结果
8.阻塞队列
阻塞队列是一个支持两个附加操作的队列
两个附加
在队列为空,获取元素的线程会等待队列为空
队列满时,存储元素的线程会等待队列可用
7个阻塞队列
9.什么是Callablle和Future
Callable接口类似于Runnable
带有返回值,Runnable没有返回值
Future
异步任务
10.线程状态
new
Runnable
Running
Blocked
位于对象等待池中的阻塞状态
位于对象锁池中的阻塞状态
其它阻塞状态
Dead
11.CycliBarriar和CountDownLatch的区别
CycliBarriar可以重复利用,CountDownLatch不能重复利用
12.不可变对象,对并发的作用
不可变类型即为不可变的类
String,基本类型的包装类.StringBuffer,BigDicimal
作用
不可变对象线程安全
那些对象是不可变的
状态不能在创建后在被修改
所有域都是final,并且被争取创建
13.几种方式可以创建线程
继承Thread
优势
直接用this代表当前线程
劣势
不能继承其它父类
实现Runnable
优势
还可以继承其它类
劣势
访问当前线程,用Thread,currentThread()
实现Callable,实现call()方法
14.停止线程
interrupt
中断线程
interrupted
查询当前线程的中断状态
15.可重入锁
Synchronized和ReentrantLock
线程可以进入任何一个它已经拥有的锁所同步的代码块
16.乐观锁和悲观锁
悲观锁
拿数据的时候认为比人会修改,因此拿数据会加锁
Synchronized
ReentrantLock
teyLock()
不会阻塞
如果没有获取到锁,返回为false
lock()
会阻塞
乐观锁
拿数据认为不会被修改,更新时判断会不会改变
atomic类库中的变量类就是CAS
实现
使用版本标识确定数据是否一致
CAS
缺点
ABA问题
循环时间开销大,造成cpu利用率增加
只能保证一个共享变量的原子操作
17.SynchronizedMap和ConcurrentHashMap的区别
SynchronizedMap
一把大锁
ConcurrentHashMap
锁住一个桶
18.CopyOnWriteArrayList应用场景
免锁容器
读写分离
最终一致性
另外开辟空间的思想,解决并发冲突
19.什么是线程安全,servlet是线程安全额吗
线程安全是指某个多线程在环境中能正确处理线程之间的共享变量,是程序功能正确完成
servlet不是线程安全的,
20为什么会重排序
单线程 不影响结果,多线程会被破坏
处理器和编译器会对指令重排序
单线程不改变程序运行结果
存在数据依赖关系的不会重排序
21.wait和sleep的区别
wait notify,notifyAll是Object的方法,会释放锁
22.如何在线程间共享数据
共享变量就是共享数据
一般要求共享变量是线程安全的
23.ThreadLocal变量
每个线程都有自己独立的变量,为每个线程提供独有的变量副本,减少创建对象
场景
seesion
数据源
线程上下文
24.检测线程是否持有锁
holdsLock()
25.yield什么作用
将当前线程从执行状态变为可执行状态
26.submit和excutor的区别
27.线程优先级的理解
1-10, 10是最高的优先级
线程会委托操作系统去处理
28,线程调度器(Thread Schedule)和时间分片(Time Slicing)
线程调度不受java虚拟机控制,线程调度器是一个操作系统服务,负责Runnable状态的线程分配CPU时间,当创建好线程,就会依赖线程调度器的实现
时间分片
将可利用的CPU时间分配给可用的Runnable线程的过程,基于优先级和等待时间
29.同步块和同步方法,那个好?
同步块好
同步块不会锁住整个对象
同步方法锁住整个对象
设计模式
1.什么是设计模式
在软件工程中,设计模式是一种通用的、可重复使用的用于解决既定范围内普遍发生的重复性问题的软件设计方法
优势
使用成熟可靠的设计模式,可以提高代码复用性,节省开发时间,从而实现功能更强大、高度可维护的代码
2.分类
建造类设计模式
主要用于定义和约束如何创建一个新的对象
单例模式,工厂模式,抽象工厂模式,建造器模式和原型模式
结构类设计模式
主要用于定义如何使用多个对象组合出一个或多个复合对象
适配器模式,组合模式,代理模式,享元模式,过滤器模式,桥接模式,修饰模式和外观模式
行为类设计模式
主要用于定义和描述对象之间的交互规则和限定对象的职责边界线
模板方法模式,解释器模式,责任链模式,观察者模式,战略模式,命令模式,状态模式,访客模式,转义模式,迭代器模式和备忘录模式
3.设计原则
单一原则
一个类或者一个方法只负责一项职责
里氏替换原则
子类可以扩展父类的功能,但不能改变原有父类的功能;
依赖倒置原则
面向接口编程;
接口隔离
建立单一接口;
迪米特原则
最少知道原则,尽量降低类与类之间的耦合;
开闭原则
抽象构建架构,用实现扩展原则;
4.常用的设计模式
1单例模式
双检
静态内部类
2建造者模式
并发编程
1.并发编程三要素
原子性
可见性
实现方法
Synchronized或Lock
保证同一时刻只有一个线程获取锁执行代码,代码释放之前把罪行的值刷到主存
有序性
2.多线程的价值
发挥多核cpu的优势
防止阻塞
便于建模
3.线程池的优点
重用存在线程,减少对象创建开销
可有效控制最大并发数,提高系统利用率
提供定时执行,定期执行,单线程,并发控制等功能
4.AQS
AbustactQueuedSynchronizer
一个提高底层同步类工具
基于冲突检测的乐观锁
同步方式
独占式
ReentrantLock
共享式
CountDownLatch
Semaphore
5.Synchronized和ReentrantLock的区别
ReentrantLock
是Synchronized的升级
是一个类
可以被继承,可以有方法
可以获取等待时间进行设置,避免死锁
获取各种锁信息
灵活实现多路通知
锁机制
底层调用Unsafe的park方法加锁
Synchronized
jvm层面的锁
是关键字
升级
无锁,偏向锁,轻量级,重量级锁
锁机制
对象头中的markword
共同点
都是具有可重入锁
6.线程B怎么知道A修改了变量
1 Volatile
2 Synchronized
3 wait/notify
4 while 轮询
7.线程调度策略
1 线程中调用了yield方法让出了cpu的占用权利
2 调用sleep 使线程进入了睡眠
3 由于IO操作受到阻塞
4 另外一个更高优先级线程出现
5 支持时间片的系统中,该线程的时间片用完
8.concurrentHashMap的并发度是什么
就是segment的大小
9.linux怎么查看那个线程使用CPU时间最长
获取PId
ips
ps -ef| grep java
top -H -p Pid
10.线程调度算法
抢占式
操作系统根据优先级和线程饥饿程度等数据算出一个总的优先级分配下一个时间片给某个线程执行
11.什么是自旋
在Synchronized的边界做忙循环,如果多次循环没有获取锁,在阻塞
12.单例模式的线程安全
饿汉式
安全
懒汉式
非安全
双检式
安全
13.线程类的构造方法,静态块被那个线程调用
线程类的构造方法和静态块是被new 的这个线程类所在线程执行的
run是被线程自身调用的
14.线程过多会造成什么异常
线程声明周期开销非常高
消耗过多的CPU资源
降低稳定性
15.为什么使用并发编程
提高多核cpu的利用率
适应复杂的业务
优势
缺点
并不总是能提升运行速度
产生问题
内存泄露
上下文切换
线程死锁
16.java怎么保证多线程的运行安全
线程切换带来原子问题
使用Synchroniaed或者Lock
缓存导致可见性
Synchroniaed.Lock.volatile
编译优化的有序性
happens-before
17.并发和并行
并发
多个任务在同一个CPU核上,按时间片轮流执行
同时执行
并行
多个处理器处理多个任务
同时进行
串行
有n个任务,由一个线程按顺序执行
18.线程池有哪些状态
Running
接收新的任务
ShutDown
不接收任务提交
Stop
中断正在执行的线程
Tidying
所有任务销毁
Terminated
terminated()方法结束
19.拒绝策略
跑出异常,拒绝新任务
增加队列容量
不处理新的任务,直接丢弃
丢弃最早未处理的任务
20.线程池执行原理
21.合理分配线程池大小
CpU密集
任务需要大量运算,而没有阻塞
可以少配置线程数,和机器cpu核数相当,使得每个线程都在执行任务
IO密集
任务需要大量的IO,大量的阻塞
大部分线程都阻塞,2*cpu核数
结论
线程等待时间比CPU执行时间比例越高.
越多线程
线程等待时间比CPU执行时间比例越少
越少线程
22.并发容器
Vector
HashTable
ConcurrentHashMap
23.并发队列
消息队列
消息队列是分布式系统的重要组建,是系统和系统的通信
并发队列
多个线程有次序共享数据的重要组件
阻塞队列和非阻塞队列的区别
当队列阻塞队列为空的时,从队列中获取元素的操作将会被阻塞。
或者当阻塞队列是满时,往队列里添加元素的操作会被阻塞。
或者试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往空的队列插入新的元素。
试图往已满的阻塞队列中添加新元素的线程同样也会被阻塞,直到其他的线程使队列重新变得空闲起来
常用队列
非阻塞队列
ArrayDeque
数组双端队列
PriorityQueue
优先级队列
ConcurrentLinkedQueue
基于链表的并发队列
阻塞队列
DelayDueue
基于时间优先级队列,延期阻塞队列
ArrayBlockingQueue
基于数组并发阻塞队列
LinkedBlockingQueue
基于链表的FIFO阻塞队列
LinkedBlockingDeque
基于链表的FIFO双端阻塞队列
PriorityBlockingQueue
带优先级的无界阻塞队列
synchronousQueue
并发同步阻塞队列
并发队列常用方法
add
插入元素,成功返回true,如果队列已满否则跑出异常
offer
队列尾部插入元素,成功true,如果队列已满,返回false
put
满了就等待,直到可用
take
获取值,没有值会阻塞
poll(long timeout,TimeUnit unit)
指定时间获取值,没有获取抛出异常
remove
移除元素
24.并发队列和并发集合的区别
队列是"先进先出"的规则,解决大数据量采集处理和显示的
并发集合是多线程中共享数据的
25.谈谈volatile的认识
javav虚拟机提供的轻量级同步机制
保证可见性
禁止指令重排序
不保证原子性
Zookeeper
1.zooleeper是什么
一个开源分布式协调服务
目标就是封装好复杂易出错的关键服务,将简单的接口和性能高效,功能稳定的系统提供给用户
2.zookeeper保存分布式一致性
顺序一致性
原子性
单一视图
可靠性
实时性
3.zookeeper提供了什么
通知系统
文件系统
多层级节点命名空间Znode
为了保证高吞吐和低延迟,每个节点存放数据上限为1M
4.主从节点怎么同步
恢复模式
广播模式
5.四种节点
持久节点
临时节点
持久顺序节点
临时顺序节点
6.zookeeper如何保证事物一致性
全局递增的事物ID
7.zookeeper的典型应用场景
数据发布订阅
pull模式
push模式
负载均衡
命名服务
分布式协调/通知
几圈管理
Mster选举
分布式锁
分布式队列
8.zookeeper和dubbo的关系
zookeeper用来注册服务和进行负载均衡
dubbo讲注册中心进行抽象,可以外界不同的存储媒介给注册中心提供服务
Dubbo
1.Dubbo是什么?
高效,轻量的RPC框架,提供服务自动注册,自动发现等高效服务治理方案.可以和spring无缝集成
2.Dubbo的使用场景有哪些?
透明化的远程方法调用
就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。
软负载均衡及容错机制
可在内网替代F5等硬件负载均衡器,降低成本,减少单点。
服务自动注册与发现
不再需要写死服务提供方地址,注册中心基于接口名查询
服务提供者的IP地址,并且能够平滑添加或删除服务提供者。
服务提供者的IP地址,并且能够平滑添加或删除服务提供者。
3.Dubbo核心功能有哪些?.
Remoting:网络通信框架
提供对多种NIO框架抽象封装, 包括“同步转异
步”和“请求-响应”模式的信息交换方式
步”和“请求-响应”模式的信息交换方式
Cluster:服务框架
提供基于接口方法的透明远程过程调用, 包括多协议支持,
以及软负载均衡,失败容错,地址路由,动态配置等集群支持。
以及软负载均衡,失败容错,地址路由,动态配置等集群支持。
Registry:服务注册
基于注册中心目录服务, 使服务消费方能动态的查找服务
提供方,使地址透明,使服务提供方可以平滑增加或减少机器
提供方,使地址透明,使服务提供方可以平滑增加或减少机器
4.Dubbo核心组件有哪些?
Provider:暴露服务的服务提供方
Consumer:调用远程服务消费方
Registry:服务注册与发现注册中心
Monitor:监控中心和访问调用统计
Container:服务运行容器
5.Dubbo服务器注册与发现的流程?
Provider(提供者) 绑定指定端口并启动服务。
提供者连接注册中心,并发本机IP、端口、应用信息和提供服务信息发送至注册中心存储。
Consumer(消费者) , 连接注册中心, 并发送应用信息、所求服务信息至注册中心。
注册中心根据消费者所求服务信息匹配对应的提供者列表发送至Consumer应用缓存。
Consumer在发起远程调用时基于缓存的消费者列表择其一发起调用
Provider状态变更会实时通知注册中心、在由注册中心实时推送至Consumer。
6.Dubbo支持哪些协议, 它们的优缺点有哪些?
Dubbo
单一长连接和NIO异步通讯, 适合大并发小数据量的服务调用, 以
及消费者远大于提供者。传输协议TCP, 异步Hessian序列化。
及消费者远大于提供者。传输协议TCP, 异步Hessian序列化。
RMI:
采用JDK标准的RMI协议实现, 传输参数和返回参数对象需要实现
Serializable接口, 使用Java标准序列化机制
Serializable接口, 使用Java标准序列化机制
WebService:
基于WebService的远程调用协议, 集成C XF实现, 提供和原
生WebService的互操作。多个短连接, 基于HTTP传输, 同步传输, 适用
系统集成和跨语言调用。
生WebService的互操作。多个短连接, 基于HTTP传输, 同步传输, 适用
系统集成和跨语言调用。
HTTP:
基于Http表单提交的远程调用协议, 使用Spring的Http Invoke
实现。多个短连接, 传输协议HTTP, 传入参数大小混合, 提供者个数多于消费
者,需要给应用程序和浏览器JS调用。
实现。多个短连接, 传输协议HTTP, 传入参数大小混合, 提供者个数多于消费
者,需要给应用程序和浏览器JS调用。
Hessian:
集成Hessian服务, 基于HTTP通讯, 采用Servlet暴露服务,Dubbo内嵌Jetty作为服务器时默认实
架现, 提构供与Hes师sion服务专互操作。管多个短连接, 同步HTTP传输, Hessian序列化, 传入参数较大, 提供者大于消
费者,提供者压力较大,可传文件。
架现, 提构供与Hes师sion服务专互操作。管多个短连接, 同步HTTP传输, Hessian序列化, 传入参数较大, 提供者大于消
费者,提供者压力较大,可传文件。
Memcache:
基于Memcache实现的RPC协议。
Red is:
基于Red is实现的RPC协议
7.Dubbo推荐什么协议?
推荐使用Dubbo协议。
8.Dubbo有哪些注册中心?
Multicast注册中心
Zookeeper注册中心
Red is注册中心
Simple注册中心。
9.Dubbo的注册中心集群挂掉, 发布者和订阅者之间还能通信么?
可以通讯。
启动Dubbo时, 消费者会从Zookeeper拉取注册的生产者的地址接口等数据,缓存在本地。每次调用时,按照本地存储的地址进行调用。
10.Dubbo使用的是什么通信框架?
默认使用Netty作为通讯框架。
11.Dubbo集群提供了哪些负载均衡策略?
默认是随机调用
随机选取提供策略
轮询选取提供策略
最少活跃度调用策略
一致性hash策略
12.Dubbo的集群容错方案有哪些?
默认的容错方案是Failover Cluster
Failover Cluster:失败自动切换, 当出现失败, 重试其它服务器。通常用于读操作,但重试会带来更长延迟。
Fail fast Cluster:快速失败, 只发起一次调用, 失败立即报错。通常用于非幂等性的写操作,比如新增记录。
Failsafe Cluster:失败安全, 出现异常时, 直接忽略。通常用于写入审计日志等操作。
Failback Cluster:失败自动恢复, 后台记录失败请求, 定时重发。通常用于消息通知操作。
Forking Cluster:并行调用多个服务器, 只要一个成功即返回。通常用于实时性要求较高的读操作, 但需要浪费更多服务资源。可通过forks=”2”来设置最大并行数。
Broadcast Cluster:广播调用所有提供者, 逐个调用, 任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。
13.Dubbo支持哪些序列化方式?
hessian,dubbo,fastJson,java序列化
14.Dubbo超时设置有哪些方式?
服务提供者设置超时
消费者设置超时
15.服务调用超时会怎么样?
默认重试两次
16.Dubbo在安全方面有哪些措施?
通过Token令牌防止用户绕过注册中心直连,然后在注册中心上管理授权
还提供黑白名单,控制服务所允许的调用方
17.Dubbo类似的分布式框架还有哪些?
18.Dubbo和Spring Cloud有什么关系?
dubbo是SOA的产物,关注点在于服务的调用,流量分发,流量的监控和熔断
19.Dubbo和Spring Cloud有什么哪些区别?
Dubbo底层使用Netty的NIO框架,是基于TCP传输协议的,配合以hessian序列化的rpc通信
SpringCloud是基于HTTP协议REST接口调用远程过程的通讯
20.dubbo和dubbox的关系
Dubbox是当当网基于dubbo开发的扩展项目,增加了restful调用
21.dubbo可以支持服务降级吗
可以,在<dubbo:reference mock=return null />
mock类实现自己的降级逻辑
22.Dubbo支持分布式事务吗
目前不支持
可以结合tcc-transcation框架实现
23.Dubbo可以对结果进行缓存吗
可以,在<dubbo:reference cache=true />
24.rpc使用了那些技术
动态代理
序列化和反序列化
NIO通信
服务注册中心
25.Rpc实现原理
建立通信
服务寻址
网络传输
服务调用
redis
1.什么是redis?简述优缺点
概念
Remote Dictionary Server ,本质是一个key -value的内存数据库.整个数据库记载在内存中,定期通过异步将数据flush到磁盘上保存
优点
纯内存操作,性能出色,最快的key-value数据库
支持多种数据结构
例如:list可以实现消息队列服务.set可以用来做tag系统
可以设置过期时间
缺点
不能用于海量数据的高性能读写
2.Redis和memcached的区别
memcache只支持简单字符串,redis支持更多
redis比memcached速度更快
redis可以持久化数据
3.redis支持那些数据类型
String
List
Set
Sorted Set
hashSet
4.消耗什么物理资源
内存
5.哪几种淘汰策略
1.noeviction:返回错误当内存限制达到,并且客户端尝试执行会让更多内存被使用的命令。
2.allkeys-lru:尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
3.volatile-Iru:尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放.
4.allkeys-random:回收随机的键使得新添加的数据有空间存放。
5.volatile-random:回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
6.volatile-ttl:回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。
6.字符串类型的值能存储最大容量是多少
512M
7.为什么吧数据放到内存中?
提高性能和持久化,并通过异步讲数据写入磁盘,原因是redis具有快速持久化德特征
8.Redis的并发竞争问题如何解决?
单进程单线程模式,采用队列模式将并发访问变为串行访问。Redis本身没有锁的概念,Redis对于多个客户端连接并不存在竞争,利用setnx实现锁。
9.Redis是单线程的,但Redis为什么这么快?
1、完全基于内存
2、数据结构简单
3、采用单线程
4、使用多路I/O复用模型
5、使用底层模型不同,构建了VM机制
10.Redis内存模型
used_memory
Redis分配器分配的内存总量(单位是字节),包括使用的虚拟内存(即swap);Redis分配器后面会介绍。used_memory_human只是显示更友好。
used_memory_rss**
**Redis进程占据操作系统的内存(单位是字节),与top及ps命令看到的值是一致的;除了分配器分配的内存之外,used_memory_rss还包括进程运行本身需要的内存、内存碎片等,但是不包括虚拟内存。
mem_fragmentation_ratio**
**内存碎片比率,该值是used_memory_rss / used_memory的比值。
mem_allocator**
**Redis使用的内存分配器,在编译时指定;可以是 libc 、jemalloc或者tcmalloc,默认是jemalloc;截图中使用的便是默认的jemalloc。
11.Redis内存划分
数据
used_memory中。
进程本身运行需要的内存
缓冲内存
这部分内存由jemalloc分配,因此会统计在used_memory中。
内存碎片
内存碎片是Redis在分配、回收物理内存过程中产生的
子主题
12.Reids主从复制
优点
复制是高可用Redis的基础,哨兵和集群都是在复制基础上实现高可用的
复制主要实现了数据的多机备份,以及对于读操作的负载均衡和简单的故障恢复。
缺点
故障恢复无法自动化
写操作无法负载均衡;
存储能力受到单机的限制。
13.Redis哨兵
在复制的基础上,哨兵实现了自动化的故障恢复。缺陷:写操作无法负载均衡;存储能力受到单机的限制。
14.Reids持久化触发条件
手动和自动
15.RDB和AOF的优缺点
RDB持久化
优点:RDB文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比AOF快很多。当然,与AOF相比,RDB最重要的优点之一是对性能的影响相对较小。
缺点:RDB文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此AOF持久化成为主流。此外,RDB文件需要满足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)
AOF持久化
与RDB持久化相对应,AOF的优点在于支持秒级持久化、兼容性好,缺点是文件大、恢复速度慢、对性能影响大。
16.为什么需要持久化?
内存型数据库,服务器在运行时可能宕机,要持久化讲数据写入磁盘
17.缓存和数据库间数据一致性问题
不一致场景
1. 数据库有数据,缓存没有数据;
2. 数据库有数据,缓存也有数据,数据不相等;
3. 数据库没有数据,缓存有数据。
读写顺序
并发不高
读redis->没有,读mysql->把mysql数据写回redis,有的话直接从redis中取;
写mysql->成功,再写redis;
并发高
读redis->没有,读mysql->把mysql数据写回redis,有的话直接从redis中取;
异步话,先写入redis的缓存,就直接返回;定期或特定动作将数据保存到mysql,可以做到多次更新,一次保存;
18.缓存雪崩问题
问题
存在同一时间内大量键过期(失效),接着来的一大波请求瞬间都落在了数据库中导致连接异常。
解决方案
1、也是像解决缓存穿透一样加锁排队。
2、建立备份缓存,缓存A和缓存B,A设置超时时间,B不设值超时时间,先从A读缓存,A没有读B,并且更新A缓存和B缓存;
19.缓存并发问题
问题
并发指的是多个redis的client同时set key引起的并发问题
解决方案
内存碎片是Redis在分配、回收物理内存过程中产生的
20.Redis分布式锁
原理
redis支持主从的模式。
原则:Master会将数据同步到slave,而slave不会将数据同步到master。Slave启动时会连接master来同步数据。
减少并发:分布式读写分离模型。我们可以利用master来插入数据,slave提供检索服务。
实现
先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。
21.redis通讯协议
是redis客户端和服务端之前使用的一种通讯协议;RESP 的特点:实现简单、快速解析、可读性好
22.事务不支持回滚
23.Reids三种不同删除策略
定时删除
设置键的过期时间,加定时任务,
惰性删除
检查过期就清理,否则不处理
定期删除
每过一段时间清理,由算法决定
24.集群怎么选择数据库
无法选择,只能在0数据库
25.redis最适合的场景
1会话缓存
2.全页缓存
3.队列
4.计数器
4.发布订阅
26.redis事物
redis没有隔离级别
不能保证原子性
事物三个阶段
开始事物
MULTI
命令入队
执行事物
EXEC
27.redis集群的三种方式
主从复制
哨兵
集群
linux
1.查看日志的常用命令
tail,head,cat,tac,more
tail,head,cat,tac,more
tail
tail -f test.log 查看实时日志
head
跟tail是相反的,tail是查看后多少行日志
cat
cat test.log | tail -n 1000 #输出test.log 文件最后1000行
tac
more
more -s test.log 逐页显示日志,如有连续两行以上空白行则以一行空白行显示
more joint.log | grep ‘60007746’ #根据某退货号查询日志
vi
vi test.log
/ 搜索内容
2.查看进程
ps -ef|grep 进程名
3.杀死进程
kill -9 PID
Mybatis
1.原理
底层是对JDBC的封装,不完全的OPM映射
2.优点
1.基于sql编程灵活
2.与各种数据库兼容
3.与JDBC相比,减少代码量
4.与spring集成
4.提供映射标签,只是对象与数据库的ORM字段关系映射
3.缺点
1.sql语句的编写工作量大
2.sql依赖数据库,导致移植性差
4.使用场合
1.灵活的DAO层解决方案
2.对性能要求或是需求变化较多的项目
5.#{}和${}的区别
#{}
预编译处理
先替换为'?',在调用set赋值
${}
字符串替换
替换成变量的值,防止sql注入
6.分页
RowBounds
7.批量提交
ExecutorType.BATCH
8.返回主键
属性 useGeneratedKeys="true" keyProperty="userId"
标签<selectKey
9.动态sql,执行原理,还有那些动态sql
作用
标签形式编写动态sql
原理
根据表达式的值,完成逻辑判断并动态拼接SQL的功能
9种其他的动态标签
trim|where|set|foreach|if|choose|when|otherwise|bind
10.一对一,一对多关联查询
一对一
association
一对多
Collection
11.是否支持延迟加载?原理
支持association和collection关联集合的延迟加载,
配置lazyLoadingEnabled=true|false
原理
使用CGLIB创建目标对象,get方法会把事先保存的关联属性赋值给属性
同hibernate
12.一二级缓存
一级缓存
作用域session,session flush或者close之后,缓存清空
默认打开
二级缓存
作用域mapper,需要实现序列化.配置文化中配置<cache>
默认不开启
缓存更新机制
一个作用域进行了CUD操作,默认该作用域下的所有查询缓存被清空
13.mapper编写几种方式
mapper接口
mapper接口实现类
mappper.xml
14.mybatis编程步骤
1创建SqlSessionFactory
2通过SqlSessionFactory创建SqlSession
3通过SqlSession执行数据库操作
4调用session.commit提交事物
5调用session.close关闭会话
15.工作原理
1.读取配置文件
2.记载映射文件
3.构造会话工厂
4.创建会话对象
5.Executor执行器
底层封装的接口
SimpleExecutor
每执行一次update/select,创建一个statement,用完关闭
ReuseExecutor
执行update/select,以sql作为satatemen,存在就使用,不存在就创建,用完不关闭
BatchExecutor
执行update,缓存多个statement.等待addBatch()完毕后,逐一执行executeBatch批处理
6.MappedStatement类型的传参
7.输入参数映射
8.输出结果映射
16.功能架构
1API接口层
开发人员通过调用操作数据库
2数据处理层
负责sql查找,解析.执行,映射等
3基础支撑层
连接管理,事物管理等
17.模糊查询怎么写
1 ' % ${question}% '
2 " %"${question}"%"
3CONCAT('%',${question},'%') 推荐写法
4使用bind标签
Mysql
1.mysql中有那几种锁
表级锁
开销小,加锁快,颗粒度大,并发读最低
行级锁:
开销大,加锁慢,颗粒度小,并发高
页面锁:
介于上述两个之间
2.mysql的存储引擎
MyISAM
Merge
Heap
INNODB
ISAM
3.MyISAM和InnoDb的区别
MyIsAM
不支持事物,但是每次查询都是原子的
支持表级锁
存储标的总行数
表有三个文件
索引文件
表结构文件
数据文件
采用非聚合索引
INNODB
支持ACID的事物,支持事物的四种隔离级别
支持行级锁和外键约束,支持写并发
不存储总行数
聚合索引
4.InnoDb支持的四种隔离级别
read uncmmited 读未提交
read committed:脏读,不可重复读
repeatable read:可重读
serializable串行事物
5.char和varChar的区别
char
长度不可变
类型char(10), 值为:abc,存储为:abc (abc+7个空格)
超出长度自动截取
类型char(3), 值为:abcdefg,存储为:abc(defg自动删除)
char最多可以存放255个字符
char(10),都表示可存10个字符,无论存放的是数字、字母还是UTF8汉字(每个汉字3字节),都可以存放10个
varchar
长度是可变的
类型varchar(10), 值为:abc,存储为:abc (自动变为3个的长度)
超出长度自动截取
类型varchar(3), 值为:abcdefg,存储为:abc (defg自动删除)
varchar的最大长度为65535个字节,varchar可存放的字符数跟编码有关
varchar(10),都表示可存10个字符,无论存放的是数字、字母还是UTF8汉字(每个汉字3字节),都可以存放10个
6.主键和候选键的区别
主键就是候选键
7.MyISAM表格在哪里存储,提供其存储格式
存储在磁盘
三种格式
.frm 文件存储定义
.MYD 数据文件
.MYI 索引文件
8.优化Distinct
Distinct所有列转换为Group By ,并与Obder by子句结合使用
9.显示前50行
limit 0,50
10.可以使用多少列创建索引
最多可以创建16个
11.索引失效
1.有or必全有索引;
2.复合索引未用左列字段;
3.like以%开头;
4.需要类型转换;
5.where中索引列有运算;
6.where中索引列使用了函数;
7.如果mysql觉得全表扫描更快时(数据少);
12.慢查询
开启慢查询日志
配置项:slow_query_log
可以使用show variables like 'slow_query_log‘查看是否开启「如果状态值
为OFF,可以使用set GLOBAL slow_query_log=orr来开启r它会在datadir
下产生一个xxx-slow.log的文件。
设置临界时间
配置项:long_query time
查看:show VARIABLES like'long_query_time'「单位秒
设置:set long_query time=0.5
实操时应该从长时间设置到短的时间,即将最慢的SQ[优化掉
查看日志,一旦SQL超过了我们设置的临界时间就会被记录到xxx-slow.log中
配置项:slow_query_log
可以使用show variables like 'slow_query_log‘查看是否开启「如果状态值
为OFF,可以使用set GLOBAL slow_query_log=orr来开启r它会在datadir
下产生一个xxx-slow.log的文件。
设置临界时间
配置项:long_query time
查看:show VARIABLES like'long_query_time'「单位秒
设置:set long_query time=0.5
实操时应该从长时间设置到短的时间,即将最慢的SQ[优化掉
查看日志,一旦SQL超过了我们设置的临界时间就会被记录到xxx-slow.log中
13.sql优化的经验
1有外键约束的话会影响增删改的性能,如果应用程序可以保证数据库的完整性就去除外键
2.SQL语句全部大写,特别是列名称
3、如果可以保证数据库完整性,可以不按照三大范式
4.不必要创建更多索引
14.优化sql查询语句
1、对查询进行优化, 应尽量避免全表扫描, 首先应考虑在where及order by
2、用索引可以提高查询
3、SELECT子句中避免使用*号, 尽量全部大写SQL
4、应尽量避免在where子句中对字段进行is null值判断, 否则将导致引擎放弃使用索引而进行全表扫描, 使用IS NOT NULL
5、where子句中使用or来连接条件, 也会导致引擎放弃使用索引而进行全涉及的列上建立索引表扫描
6、in和not in也要慎用, 否则会导致全表扫描
15.怎么知道sql语句性能是高是低
explain
16.SQL的执行顺序
1、FROM:将数据从硬盘加载到数据缓冲区, 方便对接下来的数据进行操作。
2、WHERE:从基表或视图中选择满足条件的元组。(不能使用聚合函数)
3、JOIN(如right left右连接------从右边表中读取某个元组,并且找到该元组在左边表中对应的元组或元组集)
4、ON:joinon实现多表连接查询,推荐该种方式进行多表查询,不使用子查询。
5、GROUP BY:分组, 一般和聚合函数一起使用。
6、HAVING:在元组的基础上进行筛选, 选出符合条件的元组。(一般与GROUPBY进行连用)
7、SELECT:查询到得所有元组需要罗列的哪些列。
8、DISTINCT:去重的功能。
9、UNION:将多个查询结果合并(默认去掉重复的记录) 。
10、ORDER BY:进行相应的排序。
11、LIMIT 1:显示输出一条数据记录(元组)
2、WHERE:从基表或视图中选择满足条件的元组。(不能使用聚合函数)
3、JOIN(如right left右连接------从右边表中读取某个元组,并且找到该元组在左边表中对应的元组或元组集)
4、ON:joinon实现多表连接查询,推荐该种方式进行多表查询,不使用子查询。
5、GROUP BY:分组, 一般和聚合函数一起使用。
6、HAVING:在元组的基础上进行筛选, 选出符合条件的元组。(一般与GROUPBY进行连用)
7、SELECT:查询到得所有元组需要罗列的哪些列。
8、DISTINCT:去重的功能。
9、UNION:将多个查询结果合并(默认去掉重复的记录) 。
10、ORDER BY:进行相应的排序。
11、LIMIT 1:显示输出一条数据记录(元组)
17.怎么优化大表数据
1、优化shema、sql语句+索引;
2、第二加缓存, memcached, redis;
3、主从复制,读写分离;
4、垂直拆分,根据你模块的耦合度,将一个大的系统分为多个小的系统,也就是分布式系统;
5、水平切分,针对数据量大的表,这一步最麻烦,最能考验技术水平,要选择一个合理的
sharding key, 为了有好的查询效率,表结构也要改动, 做一定的冗余, 应用也要改,
sql中尽量带s harding key, 将数据定位到限定的表上去查,而不是扫描全部的表;
2、第二加缓存, memcached, redis;
3、主从复制,读写分离;
4、垂直拆分,根据你模块的耦合度,将一个大的系统分为多个小的系统,也就是分布式系统;
5、水平切分,针对数据量大的表,这一步最麻烦,最能考验技术水平,要选择一个合理的
sharding key, 为了有好的查询效率,表结构也要改动, 做一定的冗余, 应用也要改,
sql中尽量带s harding key, 将数据定位到限定的表上去查,而不是扫描全部的表;
18.有哪些函数
1.数学函数
ABS
AVG
MAX
2.字符串函数
CONCAT
LEFT
TRIM
3.日期和时间函数
WEEK(d)
now
4.条件判断函数
IF
CASE
IFNULL
5.系统信息函数
VERSION()
USER
6.加密函数
MD5
7.其他函数
18.哪些索引
主键
唯一索引
普通
全文索引
19.哪些类型的索引
B+tree索引
hash索引
20.三大范式
第一,原子性,不可再分
第二,实体唯一约束
第三,要求字段没有冗余
容器
1.java 容器都有哪些?
2. Collection 和 Collections 有什么区别?
java.util.Collection是一个集合接口
对集合对象进行基本操作的通用接口方法。
其直接继承接口有List与Set。
Collections则是集合类的一个工具类/帮助类
静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
3. List、Set、Map 之间的区别是什么?
list
继承接口
Collection
常见实现类
AbstractList(其常用子类有
ArayList、LinkedList、Vector)
ArayList、LinkedList、Vector)
常见方法
add()、remove()、clear()、
get()、contains()、size()
get()、contains()、size()
元素
可重复
顺序
有序
线程安全
Vector线程安全
Set
继承接口
Collection
常见实现类
AbstractSet(其常用子类有HashSet、LinkedHashSe、TreeSet)
常见方法
add()、remove()、clear()、get()、contains()、size()
元素
不可重复(用equals()判断
顺序
无序(实际上由HashCode决定
线程安全
Map
继承接口
常见实现类
HashMap、HashTable
常见方法
put()、get()、remove()、clear()、containsKey()、
containsValue()、keySet()、values()、size()
contains()、size()
containsValue()、keySet()、values()、size()
contains()、size()
元素
不可重复
顺序
线程安全
Hashtable线程安全
4.HashMap
1.jdk1.7版本
数组+链表
头插法
局限
当两个线程同时处理时,可能会存在死循环
2.jdk1.8版本
数组+链表+红黑树
尾插法
什么条件下回变成红黑树
数组个数>64.单个链表的长度>8
什么条件下由红黑树变成链表
单个链表数量<6
3.为什么数组初始化的大小为2的n次幂,
就是扩容后方便扩容
4.默认数组大小和扩容因子
数组大小16,扩容因子0.75
5.扩容是扩容多大?
容量的<< 1,也就是原来容量的2倍
6.线程是否安全
不安全
7.可以存放为空的key和value吗
可以
8.继承关系
继承自AbstartMap,AbstartMap实现自Map
9.hash算法
从新计算hash值
key.hashCode & Entery.length-1
5,HashTable
1.数据结构同HashMap
2.继承关系
继承自Dictionary,Dictionary实现自Map
3.hash算法
直接使用对象的hashcode
4.是否线程安全
线程安全
5.是否可以存放空的key和value
不可以
6.扩容后数组大小大小
HashTable中hash数组默认大小是11,增加的方式是 old*2+1。
6.ConcurrentHashMap
1.jdk1.7
数据结构
segment数组+链表
默认的参数
数组长度16,扩容因子0.75,锁级别16
数组长度/锁级别就是每个segment数组的大小了
优点
构造参数中可以灵活的配置锁级别
如果数组给定的是32,则在put方法执行之后依然是32
hash算法
从新计算hash值
key.hashCode & Entery.length-1
0101 & 1111=0101
头插法
2.jdk1.8
数据结构
Node+CAS+Synchronized
优点
构造参数中可以灵活的配置锁级别
如果数组给定的是32,则在put方法执行之后,数组长度变成64
尾插法
3.应用场景
并发
7,集合关系图
两种类型
集合(Collection)
图(Map)
8.常用的集合有哪些?
Collection接口的子接口包括:Set、List、Queue
List是有序的允许有重复元素的Collection,实现类主要有:ArrayList、LinkedList、Stack以及Vector等
Set是一种不包含重复元素且无序的Collection,实现类主要有:HashSet、TreeSet、LinkedHashSet等
Map没有继承Collection接口,Map提供key到value的映射。实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap 以及 Properties 等
9.ArrayList 和 Vector 的区别
相同点
ArrayList 和 Vector 都是继承了相同的父类和实现了相同的接口(都实现了List,有序、允许重复和null)
底层都是数组(Object[])实现的
初始默认长度都为10
不同点
同步性
Vector
Vector 中的 public 方法多数添加了 synchronized 关键字、以确保方法同步、也即是 Vector 线程安全
ArrayList
ArrayList 线程不安全
性能
Vector 存在 synchronized 的锁等待情况、需要等待释放锁这个过程、所以性能相对较差
扩容大小
扩容机制
扩容方法其实就是新创建一个数组,然后将旧数组的元素都复制到新数组里面。其底层的扩容方法都在 grow() 中
Vector
扩展 1 倍
ArrayList
扩展 0.5 倍
ArrayList以1.5 倍的方式在扩容(oldCapacity >> 1 ,右移运算,相当于除以 2,结果为二分之一的 oldCapacity)
10.ArrayList 与 LinkedList 区别
是否保证线程安全
ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
底层数据结构
Arraylist
底层使用的是 Object 数组
LinkedList
底层使用的是双向循环链表数据结构
插入和删除是否受元素位置的影响
ArrayList
插入和删除元素的时间复杂度受元素位置的影响
LinkedList
插入,删除元素时间复杂度不受元素位置的影响,
ArrayList 一般应用于查询较多但插入以及删除较少情况,如果插入以及删除较多则建议使用 LinkedList
是否支持快速随机访问
ArrayList
实现了 RandomAccess 接口,对应于 get(intindex)方法
LinkedList
不支持高效的随机元素访问
内存空间占用
ArrayList
list 列表的结尾会预留一定的容量空间
LinkedList
每一个元素都需要消耗比 ArrayList 更多的空
11.HashMap 和 Hashtable 的区别
线程是否安全
HashMap 是非线程安全的
HashTable 内部的方法基本都经过 synchronized 修饰
效率
因为线程安全的问题,HashMap 要比 HashTable 效率高一点
对Null key 和Null value的支持
HashMap 中,null 可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为 nul
ashTable 中 put 进的键值只要有一个 null,直接抛出 NullPointerException。
扩充容量大小
Hashtable
默认的初始大小为11,之后每次扩充,容量变为原来的2n+1
HashMap
默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。
初始容量大小
如果给定了容量初始值
Hashtable
Hashtable 会直接使用你给定的大小
HashMap
HashMap 会将其扩充为2的幂次方大小
底层数据结构
JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。
迭代器
HashMap的迭代器(Iterator)是fail-fast迭代器
Hashtable的迭代器(enumerator)不是 fail-fast的
12.Hashtable 和 ConcurrentHashMap 的区别
底层数据结构
JDK1.7
ConcurrentHashMap
分段的数组+链表
Hashtable
的底层数据结构类似都是采用 数组+链表 的形式
JDK1.8
ConcurrentHashMap
数组+链表/红黑二叉树
Hashtable
的底层数据结构类似都是采用 数组+链表 的形式
实现线程安全的方式
Hashtable
synchronized 来保证线程安全,效率非常低下
ConcurrentHashMap
jdk1.7
ConcurrentHashMap(分段锁) 对整个桶数组进行了分割分段(Segment)
默认分配16个Segment,比Hashtable效率提高16倍。
jdk1.8
ConcurrentHashMap
摒弃了Segment的概念,而是直接用 Node 数组+链表/红黑树的数据结构来实现,并发控制使用 synchronized 和 CAS 来操作
13.Java快速失败(fail-fast)和安全失败(fail-safe)区别
快速失败(fail—fast)
在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了修改(增加、删除、修改),则会抛出ConcurrentModificationException。
原理
遍历过程中使用一个 modCount 变量,每当迭代器使用 hashNext()/next() 遍历下一个元素之前,都会检测 modCount 变量是否为 expectedmodCount 值,是的话就返回遍历;否则抛出异常,终止遍历。
注意
条件是检测到 modCount!=expectedmodCount 这个条件
不能依赖于这个异常是否抛出而进行并发操作的编程
场景
java.util包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改)。
安全失败(fail—safe)
采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。
原理
由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发 Concurrent Modification Exception。
场景
java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。
如何避免fail-fast
单线程的遍历过程中
调用迭代器 ListIterator 的 remove 方法而不是集合类的 remove方法
使用并发包(java.util.concurrent)中的类来代替 ArrayList 和 hashMap
CopyOnWriterArrayList 代替 ArrayList
ConcurrentHashMap 代替 HashMap
14.Iterator 和 Enumeration 区别
函数接口
Enumeration只有2个函数接口,能读取集合的数据,而不能对数据进行修改
terator只有3个函数接口。Iterator除了能读取集合的数据之外,也能数据进行删除操作。
Iterator支持 fail-fast机制,而Enumeration不支持。
15.Comparable 和 Comparator接口有何区别
对象实现Comparable 接口
内部只有一个方法 compareTo()
定义比较器,实现 Comparator接口
compare
equals
区别
Comparator 位于 java.util 包下,而 Comparable 位于 java.lang 包下
Comparable 接口的实现是在类的内部(如 String、Integer已经实现了 Comparable 接口)
Comparable 接口要重写 compareTo 方法
Collections.sort(list) 或者 Arrays.sort(arr)实现排序。通过 Collections.sort(list,Collections.reverseOrder()) 对list进行倒序排列。
Comparator需要重写 compare 方法
16.HashSet
用来存储没有重复元素的集合类,并且它是无序的。HashSet 内部实现是基于 HashMap ,实现了 Set 接口。
HashSet如何检查重复
数据结构
HashSet是实现了Set接口并且把数据作为K值,而V值一直使用一个相同的虚值来保存
HashMap的K值本身就不允许重复,并且在HashMap中如果K/V相同时,会用新的V覆盖掉旧的V,然后返回旧的V。
17.Iterater 和 ListIterator 之间有什么区别?
Iterator来遍历Set和List集合,而ListIterator只能遍历List
ListIterator有add方法,可以向List中添加对象,而Iterator不能
ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator不可以
istIterator可以定位当前索引的位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能
都可实现删除操作,但是 ListIterator可以实现对象的修改,set()方法可以实现。Iterator仅能遍历,不能修改
java采坑整理
1.Arrays.asList(),为什么不能用add,remove等方法
1.asList参数为泛型,如果是基本数据类型的数组,会将整个数组作为参数
2.静态内部类中ArraryList
2.list移除元素
特殊场景
List<Intehger> ,for循环,移除元素,怎么判断移除的是下标还是元素
主要是看remove的是int还是Integer,只有int是下标
3.HashMap之如何正确遍历并删除元素
不能通过myHashMap.entrySet(),或者myHashMap.keySet()
myHashMap.entrySet().iterator() ,使用迭代器移除
4.Arrays.toString
会给每个元素末尾增加空格
5.Arrays,toCharArr(Srting ss)
会变成字符数组
java基础
1. JDK 和 JRE 有什么区别
JDK:Java Development Kit 的简称
开发环境和运行环境。
JRE:Java Runtime Environment 的简称
java 的运行提供了所需环境。
我们利用JDK(调用JAVA API)开发了属于我们自己的JAVA程序后,通过JDK中的编译程序(javac)将我们的文本java文件编译成JAVA字节码,在JRE上运行这些JAVA字节码,JVM解析这些字节码,映射到CPU指令集或OS的系统调用。
2. == 和 equals 的区别是什么
==
基本类型:比较的是值是否相同;
引用类型:比较的是引用是否相同;
equals
本质上就是 ==
String、Integer 等把它变成了值比较
3.两个对象的 hashCode()相同,则 equals()也一定为 true
两个对象的 hashCode()相同,equals()不一定 true
4. final 在 java 中有什么作用
final 修饰的类叫最终类,该类不能被继承。
final 修饰的方法不能被重写。
final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。
5. java 中的 Math.round(-1.5) 等于多少?
等于 -1
6. String 属于基础的数据类型吗?
7. java 中操作字符串都有哪些类?它们之间有什么区别?
String
声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象
StringBuffer
Synchronized 修饰线程安全
多线程环境
StringBuilder
非线程安全
单线程环境
StringBuilder 的性能却高于 StringBuffer
8. String str="i"与 String str=new String("i")一样吗
String x = "string";
存在于常量池中
String z = new String("string");
堆中开辟了内存
9. 如何将字符串反转?
StringBuilder 或者 stringBuffer 的 reverse() 方法。
10. String 类的常用方法都有那些?
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
substring():截取字符串。
equals():字符串比较。
length():返回字符串长度。
getBytes():返回字符串的 byte 类型数组。
11. 抽象类必须要有抽象方法吗?
不需要
12. 普通类和抽象类有哪些区别?
普通类不能包含抽象方法,抽象类可以包含抽象方法。
抽象类不能直接实例化,普通类可以直接实例化。
13. 抽象类能使用 final 修饰吗?
不能,定义抽象类就是让其他类继承的.
14. 接口和抽象类有什么区别?
实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。
构造函数:抽象类可以有构造函数;接口不能有。
main 方法:抽象类可以有 main 方法,并且我们能运行它;接口不能有 main 方法。
实现数量:类可以实现很多个接口;但是只能继承一个抽象类。
访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符
16. BIO、NIO、AIO 有什么区别?
BIO
Block IO 同步阻塞式 IO
模式简单使用方便,并发处理能力低。
NIO
New IO 同步非阻塞 IO
客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
AIO
Asynchronous IO 是 NIO 的升级
异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。
17. Files的常用方法都有哪些?
Files.exists():检测文件路径是否存在。
Files.createFile():创建文件。
Files.createDirectory():创建文件夹。
Files.delete():删除一个文件或目录。
Files.copy():复制文件。
Files.move():移动文件。
Files.size():查看文件个数。
Files.read():读取文件。
Files.write():写入文件。
Files.createFile():创建文件。
Files.createDirectory():创建文件夹。
Files.delete():删除一个文件或目录。
Files.copy():复制文件。
Files.move():移动文件。
Files.size():查看文件个数。
Files.read():读取文件。
Files.write():写入文件。
18.继承关系中代码块,构造方法等执行顺序?
特点
子类可以用父类属性,父类不可用子类属性
顺序
父类静态代码块>子类静态代码块>父类非静态代码块>父类构造方法>子类非静态代码块>子类构造方法
无惨构造方法是否一定被执行
不是,如果没有调用无惨,将不会执行无惨构造器
19.B/S架构?C/S架构
BS
浏览器,服务器
CS
客户端/服务端
桌面应用程序
19.你所知道网络协议有那些?
HTTP:超文本传输协议
FTP:文件传输协议
SMPT:简单邮件协议
TELNET:远程终端协议
POP 3:邮件读取协议
20.Java都有那些开发平台?
JAVA SE:主要用在客户端开发
JAVA EE:主要用在web应用程序开发
JAVA ME:主要用在嵌入式应用程序开发
21.什么是JVM?java虚拟机包括什么?
JVM:Java虚拟机, 运用硬件或软件手段实现的虚拟的计算机
包括
寄存器,堆栈,处理器
22.Java是否需要开发人员回收内存垃圾吗?
不需要的, Java提供了一个系统级的线程来跟踪内存分配, 不再使用的内存区将会自动回收
23.什么是数据结构
计算机保持,组织数据的方式
24.java的数据结构有哪些
线性表(ArrayList)
链表(LInkedList)
栈(Stack)
队列(Queue)
图(Map)
树(Tree)
25.什么是OOP
面向对象编程
26.什么是面向对象?
物体的动态行为和静态属性
27.类与对象的关系?
类是对象的抽象,对象是类的具体,类是对象的模板,对象是类的实例
28.Java中有几种数据类型
整形:byte, shor, int, long
浮点型:float double
字符型:char
布尔型:boolean
浮点型:float double
字符型:char
布尔型:boolean
29.什么是隐式转换,什么是显式转换
显示转换就是类型强转,把一个大类型的数据强制赋值给小类型的数据;
隐式转换就是大范围的变量能够接受小范围的数据
隐式转换和显式转换其实就是自动类型转换和强制类型转换.
30.Char类型能不能转成nt类型?能不能转化成string类型, 能不能转成double类型
它的int值从1开始, 一共有2的16次方个数据;
Char<int<long<float<double;
Char类型可以隐式转成int, double类型! 但是不能隐士转换为String
转化为Byte,Short需要强转
31.什么是拆装箱?
拆箱
包装类到基本数据类型
装箱
基本类型到包装类型
32,Java中的包装类都是那些?
byte:Byte
short:Short
int:Integer
long:Long
float:Float
double:Double
char:Character
boolean:Boolean
short:Short
int:Integer
long:Long
float:Float
double:Double
char:Character
boolean:Boolean
33.一个java关中包含那些内容?
属性、方法、内部类、构造方法、代码块。
34.例如:if(a+1.0=4.0).这样做好吗?
不好,因为计算机在浮点型数据运算的时候,会有误差
布尔表达式中不便用浮点型数据
if, while, switch中判断条件不使用浮点型
35.那针对浮点型数据运算出现的误差的问题,你怎么解决?
Bigdecimal
36.++i与i++的区别?
++i
先加后赋值
i++
是先赋值后加
37.程序的结构有那些?
顺序,选择,循环
38.数组实例化有几种方式?
静态实例化
int[] a=new int[3]{1,2,3}
动态实例化
只指定了长度,元素为数组类型的默认值
39.Java中各种数据默认值
Byte, short, int, long默认是都是0
Boolean默认值是false
Char类型的默认值是'’
Float与double类型的默认是0.0
对象类型的默认值是null
40.Java常用包有那些?
Java.lang
Java.io
Java.sql
Java.util
Java.math
41.Java最顶级的父类是哪个?
Object
42.Object类常用方法有那些?
equals
hashCode
wait
notify
clone
getClass
43.Java中有没有指针?
有,无法直接操作,由JVM操作
44.Java中是值传递还是引用传递?
理论上说, java都是引用传递
某本数据类型
传递是值的副本, 而不是值
对于一些不可变的如Boolean,Integer,String,可以认为是值传递
对象类型
传递是对象的引用,当在一个方法操作参数的时候,
其实操作的是引用所指向的对象。
其实操作的是引用所指向的对象。
45.假设把实例化的数组的变量当成方法参数,当方法执行的时候改变了数组内的元素,那么在方法外,数组元素有发生改变吗?
改变了,因为传递是对象的引用,操作的是引用所指向的对象
46.实例化数组后,能不能改变数组长度呢?
不能,数组一旦实例化,它的长度就是固定的
47.假设数组内有5个元素,如果对数组进行反序,该如何做?
创建一个新数组,从后边遍历,放入新的数组
48.形参与实参
形参
全称为“形式参数
在定义方法名和方法体的时候使用的参数,用于接收调用谅方法时传入的实际值
实参
全称为“实际参数”
是在调用方法时传递给该方法的实际值.
49.构造方法能不能是式调用
不能
只有在创建对象的时候它才会被系统调用
50.构话方法能不能重写?能不能重?
可以重写,也可以重载
51.什么是方法重载?
同名方法,但是参数类型,个数,顺序不同
52.内部类与静志内部类的区别?
静态内部类相对与外部类是独立存在的
静态内部类
特点
在静态内部类中无法直接访问外部类中变量、方法, 如果要访问的话, 必须要new一个外部类的对象, 使用new出来的对象来访间,但是可以直接访问静态的变量、调用静态的方法;
访问方式
其他类
创建一个静态内部类对象即可。
普通内部类
特点
作为外部类一个成员而存在,在普通内部类中可以直接访问外部类属性,调用外部类的方法。
访问方式
外部类
必须要创建一个内部类的对象,便用该对象访问属性或者调用方法。
其他的类
必须要在外部类中创建一个普通内部类的对象作为一个属性,外同类可以通过该属性调用普通内部的方法或者访问普通内部类的属性
53.Static关键字有什么作用?
内部类
方法
表示该方法属于当前类的, 而不展于某个对象的,
静态方法也不能被重写, 可以直接使用类名来调用.在static方法中不能使用this或者super关键字。
静态方法也不能被重写, 可以直接使用类名来调用.在static方法中不能使用this或者super关键字。
变量
静态变量被所有实例所共享, 不会依于对象。
静志变量在内存中只有一份拷贝, 在JVM加载类的时候, 只为静志分配一次内存。
静志变量在内存中只有一份拷贝, 在JVM加载类的时候, 只为静志分配一次内存。
代码块
会执行一次
54.String str="aa”, String s="bb”String aa=aa+s; 一种创建了几个对象?
一共有两个引用,三个对象。
会创建一个新的常量是"aabbb”, 有将其存到常量池中。
55.将下java中的math类有那些常用方法?
Pow() :幂运算
Sqrt() :平方根
Round ():四舍五入
Abs() :求绝对值
56.判断两个对象是香相同, 能使用equlas比较吗?
不能,使用==
57.面向对象的语言有那些特征?
继承、封装、多态
58.Java中的继承是单承还是多壁承
单继承
java类来说只能有一个父类
多继承
对于接口来说可以同时继承多个接口
59.什么是重写?什么是重或?
多态
60.构造方法能不能重载?能不能重写?
可以重载,必须重写
61.如果父类只有有参构请方法,那么子类必须要重写父类的构适方法吗?
必须重写
62.创建一个子类对象的时候,那么父类的构造方法会执行吗?
会执行
当创建一个子类对象,调用子类构造方法的时候,子类构造方法会默认调用父类的构造方法。
63.什么是父类引用指向子类对象?
是java多态一种特殊的表现形式。创建父类引用, 让该引用指向一个子类的对象
64.当父类引用指向子类对象的时候,子类重写了父类方法和属性,那么当访问属性的时候,访问是谁的属性?调用方法时,调用的是谁的方法?
子类重写了父类方法和属性,访问属性是父类的,调用的方法是子类的
65.Super与this表示什么?
Super当前类的父类对象
this当前的类对象
66.抽象的关键字是什么?
Abstract
67.抽象类必须要有抽象方法吗
非必须
68.如果一个类中有抽象方法,那么这个一定是抽象类?
一定是抽象类
69.抽象类可以使用final修饰吗?
70.普通类与抽象类有什么区别?
普通类
不能包含抽象方法,可以被实例化
抽象类
可以包含抽象方法,不能被实例化
71.什么是接口?
对外提供一种功能的声明
72.JAVA为什么需要接口?
弥补了单继承的缺点
73.接口有什么特点?
声明全称是 public static final的常量
所有方法是抽象方法
没有构造方法
不能被实例化
可以多继承
74.Java中异常分为哪两种?
编译
运行
75.说几个常见的编译时异常类?
NullPointerException:空指针异常
ArrayIndexOutOfBoundsException:数组下标越界
NumberFormatException:数字转换异常
IlegalArgumentException:参数不匹配异常
InstantiationException:对象初始化异常
ArithmeticException:算术异常
ArrayIndexOutOfBoundsException:数组下标越界
NumberFormatException:数字转换异常
IlegalArgumentException:参数不匹配异常
InstantiationException:对象初始化异常
ArithmeticException:算术异常
76.异常的处理机制有几种?
捕捉,抛出
77.如何自定义一个异常
继承RuntimeException 或者Ecxeption
78.在异常捕捉时, 如果发生异常, 那么try.catch.finally块外的retum语句会执行吗?
有fianlly,就会执行
79.Try.catch.finally是必须要存在的吗?
try必须存在,
80.Thow与thorws区别
Throw
写在代码块内
方法后边
Throws
方法后边
异常类可以出现多个
81.Error与Exception区别?
都继承了Throwable类。
Exception表示的异常, 异常可以通过程序来捕捉, 或者优化程序来避免.
Error表示的是系统错误, 不能通过程序来进行错误处理。
82.使用Log4j对程序有影响吗?
有, log4j是用来日志记录的, 记录一些关键敏感的信息, 通常会将日志记录到本
地文件或者数据库中,记录在本地文件中,会有频繁的io操作,会耗费一些系统
资源,记录在数据库中,会颜繁地操作数据库表,对系统性能也有一定的影响,
但是为了程序安全以及数据的恢复或者bug的跟踪, 这点资源消耗是可以承受的
地文件或者数据库中,记录在本地文件中,会有频繁的io操作,会耗费一些系统
资源,记录在数据库中,会颜繁地操作数据库表,对系统性能也有一定的影响,
但是为了程序安全以及数据的恢复或者bug的跟踪, 这点资源消耗是可以承受的
83.Log4j日志有几个级别?
debug/info/warn.error
84.除了使用new创建对象之外, 还可以用什么方法创建对象?
反射
85.Java反射创建对象效率高还是通过new创建对象的效率高?
new 效率高
反射慢
找资源类,使用类加载器创建,过程繁琐
86.JDBC操作的步骤
记载数据库驱动类
打开数据库连接
执行sql语句
处理返回结果
关闭资源
87.86.在使用jdbc的时候, 如何防止出现sql注入的问题.
使用PreparedStatement,不使用Statement
88.怎么在JDBC内调用一个存储过程
CallableStatement
89,是否了解连接池,使用连接池有什么好处?
数据库连接是非常消耗资源的,影响到程序的性能指标,连接池是用来分配、管
理、释放数据库连接的,可以使应用程序重复使用同一个数据库连接,而不是每
次都创建一个新的数据库连接,通过释放空闲时间较长的数据库连接避免数据库
因为创建太多的连接而造成的连接遗漏问题,提高了程序性能.
理、释放数据库连接的,可以使应用程序重复使用同一个数据库连接,而不是每
次都创建一个新的数据库连接,通过释放空闲时间较长的数据库连接避免数据库
因为创建太多的连接而造成的连接遗漏问题,提高了程序性能.
90.你所了解的数据源技术有那些?使用数据源有什么好处?
Dbcp, c3p0等, 用的最多还是c3p0, 因为c3p0比dbcp更加稳定, 安全; 通过
配置文件的形式来维护数据库信息,而不是通过硬编码,当连接的数据库信息发
生改变时,不需要再更改程序代码就实现了数据库信息的更新。
配置文件的形式来维护数据库信息,而不是通过硬编码,当连接的数据库信息发
生改变时,不需要再更改程序代码就实现了数据库信息的更新。
91.Java的io流分为哪两种
功能
输出流
输入流
类型
字节流
字符流
92.常用io类有那些?
93.字节流与字符流的区别
字节流8位传输
字符流16位传输
94.final、finalize() 、finally
性质
final为关键字;
finalize() 为方法;
finally为区块标志, 用于try语句中;
作用
1、final为用于标识常量的关键字, final标识的关键字存储在常量池中(在这
里final常量的具体用法将在下面进行介绍) ;
里final常量的具体用法将在下面进行介绍) ;
2、finalize() 方法在Object中进行了定义, 用于在对象“消失”时, 由JVM进
行调用用于对对象进行垃圾回收,类似于C++中的析构函数;用户自定义时,用
于释放对象占用的资源(比如进行/0操作);
行调用用于对对象进行垃圾回收,类似于C++中的析构函数;用户自定义时,用
于释放对象占用的资源(比如进行/0操作);
3、finally 0用于标识代码块, 与try() 进行配合, 不论try中的代码执行完或没
有执行完(这里指有异常),该代码块之中的程序必定会进行;
有执行完(这里指有异常),该代码块之中的程序必定会进行;
95.线程同步的方法
wait()
等待,将线程存储到另一个线程中
notifyAll()
被唤醒的所有线程处于阻塞
notify()
被唤醒线程处于阻塞
96.线程与进程的区别
概念
进程
进程是系统进行资源分配和调度的一个独立单位
线程
线程是CPU调度和分派的基本单位
关系
一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
2、资源分配给进程,同一进程的所有线程共享该进程的所有资源.
线程在执行过程中,需要协作同步。不同进程的线程问要利用消息通信的办法实现同步。
线程是指进程内的一个执行单元,也是进程内的可调度实体,
区别
调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位.
并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可以并发执行.
拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源.
系统开销:在创建或撒销进程的时候,由于系统都要为之分配和回收资源,
导致系统的明显大于创建或撒销线程时的开销。但进程有独立的地址空间,进程
丽溃后,在保护模式下不会对其他的进程产生影响,而线程只是一个进程中的不
同的执行路径,线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,
一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,
但是在进程切换时,耗费的资源较大,效率要差些。
导致系统的明显大于创建或撒销线程时的开销。但进程有独立的地址空间,进程
丽溃后,在保护模式下不会对其他的进程产生影响,而线程只是一个进程中的不
同的执行路径,线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,
一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,
但是在进程切换时,耗费的资源较大,效率要差些。
97.&和&&的区别
&
位运算
逻辑且
不会短路
&&
逻辑且
短路
98.如果对象的引用被置为null, 垃圾收集器是否会立即释放对象占用的内存
不会,下一个垃圾回收周期中,这个对象可以被回收
99.串行(seria) 收集器和吞吐量(throughput) 收集器的区别是什么?
吞吐量收集器使用并行版本的新生代垃圾收集器,它用于中等规模和大规模数据
的应用程序,而串行收集器对大多数的小应用(在现代处理器上需要大概100M左
右的内存)就足够了.
的应用程序,而串行收集器对大多数的小应用(在现代处理器上需要大概100M左
右的内存)就足够了.
分支主题
https://app.xunjiepdf.com/ocr/
自由主题
收藏
收藏
0 条评论
下一页