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