Java架构成长之路
2021-09-09 08:39:48 0 举报
AI智能生成
Java架构成长之路
作者其他创作
大纲/内容
软件架构
SOA
是一种粗粒度、松耦合服务架构,各服务间均需要基于ESB(Enterprise Service Bus,企业服务总线)进行消息通信
微服务
它是SOA的细粒度体现,将单体架构系统按照业务进行垂直切分成独立的服务,并独立部署、运行;各服务间通常是基于RESTful API(同步)和消息队列(MQ,异步)进行通信。
框架工具
Spring Boot、Spring Cloud
Docker容器
主要解决的问题:1、通过镜像的方式将应用和运行环境一起打包部署,能做到开发、测试、线上环境保持一致;2、作为一种新的虚拟化技术,降低了传统虚拟化技术带来的成本。
Docker的安装
yum -y install docker
相关概念
镜像
镜像是一个只读的文件系统,包括应用文件、环境文件。它通常包含堆叠在彼此之上的联合分层文件系统。一个Docker容器中往往有多个不同的镜像。镜像没有状态并且始终不会发生更改。
自定义镜像
通过Dockerfile文件快速创建镜像
编写Dockerfile文件,然后执行docker build命令创建镜像
使用docker commit命令从容器创建一个新的镜像
仓库
本地镜像仓库
远程镜像仓库
容器
Docker 容器是 Docker镜像的运行时实例。Docker 容器中包含Docker 镜像执行环境一组标准指令。此概念借用自船运集装箱,它们定义了在全球运送货物的标准。Docker 定义了交付软件的标准。
常用命令
docker login [OPTIONS] [SERVER]
登录到一个Docker镜像仓库
docker pull [OPTIONS] NAME[:TAG|@DIGEST]
从远程仓库拉取镜像到本地,默认tag(版本号)是latest
OPTIONS:-a :拉取所有 tagged 镜像
如:docker pull centos 表示拉取最新的centos 镜像到本地
docker rmi [OPTIONS] 镜像ID/仓库名:镜像名
删除本地仓库中的镜像
OPTIONS:-f:强制删除
docker search [OPTIONS] TERM
搜索远程仓库镜像,如docker search centos 表示搜索与centos相关的镜像
docker run [OPTIONS] [镜像ID/仓库名:镜像名]
包含两步操作:1、将镜像放到容器中;2、启动容器,相当于docker start
OPTIONS:1)-i:以交互模式运行,通常与 -t 一起使用简写为 -it;2)-d:以后台程序运行,并返回容器ID;3)-p:指定端口映射,宿主机端口:容器端口;4)--name:为容器指定一个名称。
docker run -it 镜像ID/仓库名:镜像名 /bin/bash可以进入docker容器中的命令行模式,exit 或 Ctrl+D 命令退出并销毁当前docker容器Ctrl+P,Ctrl+Q也可以退出,且不会销毁docker容器
端口映射
命令格式:docker run -p 宿主机端口:容器端口 docker run -p
-p:指定映射端口,-P:随机映射端口
1)使用-P标记时,Docker会随机映射一个 49000~49900 的端口到内部容器开放的网络端口;
2)-p则可以指定要映射的IP和端口,但是在一个指定端口上只可以绑定一个容器。支持的格式有 hostPort:containerPort、ip:hostPort:containerPort、ip::containerPort。
2)-p则可以指定要映射的IP和端口,但是在一个指定端口上只可以绑定一个容器。支持的格式有 hostPort:containerPort、ip:hostPort:containerPort、ip::containerPort。
如:docker run -p 80:80 --name mynginx -p 80:80:将容器的80容器映射到主机的80端口 --name mynginx:将容器命名为mynginx
如创建并启动mysql容器:docker run --name mysql -p 3306:3306 -v /var/lib/mysql/:/var/lib/mysql/ -e MYSQL_ROOT_PASSWORD=123 -d mysql:5.7 其中--name 指定容器以mysql命名,-p指定端口映射,-v指定挂载宿主主机目录,-e指定环境变量,-d指定镜像
docker start <容器名或ID>
启动容器
docker stop <容器名或ID>
停止容器运行
docker restart <容器名或ID>
重启容器,相当于 stop 或 start 组合命令
docker rm <容器名或ID>
删除指定的容器,该容器必须已经停止运行
docker commit <容器名或ID>
使用容器创建镜像
docker push [仓库名:镜像名]
将本地镜像推送至远程仓库
docker ps [OPTIONS]
查看容器
如:docker ps:查看正在运行的容器docker ps -a:查看所有的容器,包括已经停止的
docker images [OPTIONS] [REPOSITORY[:TAG]]
查看本地有哪些镜像
docker logs <容器名或ID>
查看容器日志
docker port <容器名或ID>
查看容器端口映射情况
docker exec -it <容器名或ID> bash
以交互模式进入正在运行的镜像,输入 exit 则退出
Java SE
基础语法
数据类型
8种基本数据类型
数值型
整形
byte,1字节8位,127~-128,默认值0
short,2字节16位,默认值0
int,4字节32位,默认值0
long,8字节64位,定义时需要加L,默认值0
浮点型
float,4字节32位,定义时需要加F,默认值0.0
double,8字节64位,默认值0.0
字符型char
2字节16位,默认值空格,表述范围0~65535
布尔型boolean,1字节或4字节,默认值false
包装类
Byte
Short
Integer
Long
Float
Double
Boolean
Character
引用类型
类
接口
数组
数组可以存放基本数据类型和引用数据类型,长度不可变
枚举类型enum
类型转换
强制转换
大表述范围转小表述范围
自动转换
小表述范围转大表述范围
常量赋给表述范围小于int的类型的值自动转换前提是这个常量的值在其表述范围内
运算符与表达式
算术运算符
一元运算符
- 、 ++ 、 --
b = -a
二元运算符
+ 、- 、 * 、 / 、 %
条件运算符(三目)
? :
关系运算符
>、>=、< 、<= 、==、!=
逻辑运算符
&&
a&&b,短路与
2>1&&3<4 = true
||
a||b,短路或
2<1||3>4 = false
!
!a , 逻辑非
!(2>4) = true
|
a|b,逻辑或
1>2|3>5 = true
&
a&b , 逻辑与
1<2&3<5 = true
扩展运算符(算术赋值)
+= 、-= 、*= 、/= 、 %=
byte i = 5;
i+=500; // i = -7; 虽然这里超出了byte的存储范围,但是还会将505对应的二进制仍然会存进一个字节当中去。
(byte 127 ~ -128)
i+=500; // i = -7; 虽然这里超出了byte的存储范围,但是还会将505对应的二进制仍然会存进一个字节当中去。
(byte 127 ~ -128)
位运算符
&,按位进行与运算(AND)
4&5 = 4
|,按位进行或运算(OR)
4 | 5 = 5
^, 按位进行异或运算(XOR)
4^5 = 1
~,按位进行取反运算(NOT)
~4 = -5
移位运算符
<< 、 >> 、 >>>
流程控制结构
顺序结构
选择结构
if-else
switch-case
支持可以自动转int的类型
支持String类型(JDK7版本以后支持)
支持枚举
循环结构
for
while
do-while
foreach
底层就是迭代器
循环关键字
break,结束当前层循环
continue,结束当前层该次循环
return,结束方法
变量
成员变量
定义在类全局
有默认值
数字默认为0
引用类型默认为null
布尔默认false
系统不会给final修饰的成员变量初始化
局部变量
仅在该代码块可用
无默认值
系统不会对局部变量初始化
方法
参数的传递
值传递(call by value)
在java中,传递参数时只是把实参的副本赋给形参,改变副本不影响原来的值;Java中,不管是值传递还是址传递,实质上都是值传递
地址传递(call by reference)
址传递时发生在引用类型的参数传递上,实质上也是将引用类型的副本赋给形参,但此时赋给形参的是他所引用的对象的地址,所以形参跟实参指向同一个引用,执行方法以后,这个引用的对象可能会因方法的执行而改变,从而造成实参引用改变。表面上,我们可以把引用类型的参数传递理解为址传递。
方法重载 Overload
针对于同一个类或接口而言
同一个类中的多个同名方法之间参数列表必须不同。与返回值是否相同无关
方法重写/覆盖 Override
以继承为基础,子类可以覆盖父类实现的方法,实现自己的功能。
1、要保证子类中重写的方法签名要和父类一致,即返回值、方法名、参数列表必须完全一致;2、子类抛出的异常不能超过父类相应方法抛出的异常(子类异常不能大于父类异常);3、子类中重写的方法访问控制权限不能低于父类。
不允许方法重写的两种特殊情况
private 关键字修饰的方法
final 关键字修饰的方法
方法所属性
类方法
属于该类本身
不经过对象
普通方法
属于该类对象
方法默认主调者
静态方法默认由类直接调用
普通方法由该类对象默认调用
抽象方法
默认由public abstract修饰,也可以不写public,但abstract必须有
不写public为默认权限
不写public为默认权限
只有方法签名,没有方法体
不可被调用
必须被重写,重写规则在本思维导图的面向对象三大特征的继承中
权限修饰符
public
整个项目可用
protected
包内可用
包外子类可用
default
包内
private
本类
static
只能修饰属性、方法和初始化块
由它修饰的属性和方法属于类本身,不属于对象
由它修饰的属性或方法,该类所有对象共享,在内存中仅有一份
static修饰的在类加载时就初始化了
static修饰的可以直接用类名调用
不能使用this
静态代码块在类加载时初始化,并且只加载一次,第一次使用到该类时加载类
final
可以修饰普通类、方法和属性
用final修饰的变量不可被二次赋值
用final修饰的类不可被继承。只是不能被继承,只要构造方法是公共的,就可以创建对象
final修饰的方法不可被重写
重写final修饰的方法会发生编译错误
final修饰的成员变量必须指定初始值
由final修饰的类变量
必须在静态初始化块中指定初值或声明该类变量的时候指定初值,但只能在这两个地方的其中之一指定
final修饰的实例变量
必须在非静态初始化块中、声明该实例变量时或构造器中指定初始值,而且只能在这三个地方的其中之一指定
final修饰的成员变量不允许在显式初始化前直接访问,但允许通过方法访问
修饰局部变量
final修饰引用变量
该变量不可被二次赋值
该变量引用指向的对象的内部可以发生改变
宏变量
被final修饰
在编译时,初始值就被确定
只有在定义该变量时指定其初始值才有宏变量的效果
面向对象
对象
在软件系统中视一切事物皆为对象,不仅包括现实中客观存在的事物,还包括抽象的东西
对象的创建
new关键字
创建对象时根据构造器对对象成员变量进行初始化
对象的引用
对象赋给引用变量
引用变量存对象的地址
this:总是指向调用该方法的对象
构造器中this指向正在初始化的对象
方法中,this指向调用该方法的对象
在静态方法中不可使用this
必须写在构造器第一行
类
对于同一类型对象的抽象表达
类是对象的抽象体
一个类只能有一个公共类
类中元素
成员变量
方法
初始化块
顺序
静态初始化块
父类的普通初始化块
父类构造方法
子类的初始化块
子类的构造方法
可包含
局部变量
调用其它对象的方法
控制语句
静态初始化块
只能被static修饰
类加载时执行
普通初始化块
创建对象时执行
构造方法
内部类
接口
枚举
抽象
抽象类
包含元素
可以包含普通方法和抽象方法
成员变量
初始化块
内部类
含有构造器,但是不是用来实例化对象的,是用来供给子类调用的
特点
用abstract关键字修饰类
抽象类不可被实例化
抽象类不可被private和protected修饰
抽象类可以继承抽象类
抽象类可以实现接口
主要作为多各类的模板
abstract
static和abstract不能同时修饰方法
final和abstract不能同时修饰方法
接口
对行为的抽象表达,可以看作是一种协议,其中仅包含对行为的定义,不包含具体实现
接口定义
接口是比抽象类更抽象的类
不再使用class关键字,而是使用interface
不可被实例化
不能被final和protected修饰
一个类可以实现多个接口
接口可以多继承接口
接口中元素
接口中只能定义静态常量,不可定义普通成员变量,静态常量必须赋初值
接口中不能声明引用
Java7
成员变量只能是静态常量
抽象方法
Java8新特性
可以在接口中定义默认方法
可以在接口中定义静态方法
Java9新特性
可以在接口中写私有方法
可以在接口中写私有静态方法
枚举
枚举的本质是用enum修饰的final类
抽象与非抽象
非抽象枚举类默认由final修饰但不能显示使用final修饰该类
抽象枚举类不能用final修饰,并且默认用abstract修饰且不能显示使用abstract修饰该类
枚举类里实现抽象方法,每个枚举值分别实现抽象方法,语法与匿名内部类大致相似
枚举也是一个类,在编译后,也会生成 .class文件,枚举是一个特殊的类
枚举类可以实现多个接口
如果按照普通类实现接口那样,重写接口中的方法,那么枚举类中所有实例的行为就会相同
枚举类实现接口,应该让每个枚举值分别实现接口中的方法
这样写实质上是写的枚举的匿名内部子类,在编译时也会生成匿名子类的 .class文件
包含元素
成员变量
枚举值
枚举值是静态常量,默认由
public static final修饰
public static final修饰
方法
构造器
一旦定义了带参构造器,那么在列出枚举值的时候就要传入相应的参数
与普通类的区别
构造器只能用private修饰
默认继承java.lang.Enum抽象类
Enum类实现了java.lang.Serializable和java.lang.Comparable两个接口
默认使用final修饰不能被继承
枚举类的所有实例在第一行列出,并且默认用public static final修饰
枚举不可以显示继承任何类
Enum提供的方法
values()
获取枚举类的所有实例,返回一个该类类型的数组
该方法为静态方法
该方法是在编译期做的事情,在api中没有介绍
toString()
实例方法
返回枚举常量名称
正是由于这个方法,所以可以直接输出枚举类型的常量名
String name()
返回枚举实例名称
与toString方法功能相同
三大特性
封装
对内将对象具有的特征与行为进行统一管理;对外隐藏实现细节,仅提供公开接口。
属性
用于表达对象具有的某些特征,如大小、颜色等
方法
定义一系列对属性进行操作的行为
类和类之间的关系
泛化关系
继承
实现
依赖关系
例如人类拧螺丝方法,需要依赖工具类的实例
关联关系
若A与B有关联,说明AB两个类有关系,他们两个并不能共同构成一个整体,例如人类和车有关联,但人类和车类并不能组合起来构成一个更大的整体,但妻子丈夫儿女有关联且能构成一个家庭,这叫聚合
聚合关系
聚合关系是建立在关联关系之上的,两个类是聚合关系那么一定相关联,反之则否
弱聚合
通常把弱聚合称为聚合
若AB弱聚合关系,则AB可以共同构成更大的整体,但AB不用同时出现,例如丈夫妻子和儿子,当儿子不出现的时候,丈夫和妻子也为一个家庭,而后可以出现不同个儿子共同构成家庭
强聚合
通常把强聚合称为组合
若两个类具有强聚合关系,则一个类在实例化时就必须把另一个类实例化,例如选择题类和选项类,在一道选择题被实例化的同时需要实例化n个选项,即两个类必须同时出现
继承/派生
用于子类对父类的功能的扩展
表现形式
子类继承父类
子类实现接口
子类获得父类全部成员变量和方法,但仅部分可被公开访问
子类可获得父类静态方法
子类可获得父类静态方法
子类可获得父类静态属性
静态属性只属于该类,虽然子类也可以通过类名去调用父类静态属性,但这种做法是错误的,不能因为可以调用就说子类继承到了父类的静态属性或者方法。
继承抽象类必须重写抽象类中的所有抽象方法
重写
重写父类方法将覆盖父类方法
子类对象不可调用被覆盖方法
子类中可以调用被覆盖方法
实例方法用关键字super调用
类方法用类名调用
@Override
只能标注方法
重写规则
重写权限修饰符不能变小
重写必须方法名一致参数列表一致,返回值类型可不同
父类被重写方法的返回值可以是子类重写方法的返回值的父类,反之不可以
不能重写私有方法
用private修饰的方法对子类隐藏,无法构成重写
父类设计规则
尽量隐藏父类内部数据
不让子类随意访问、修改父类方法
成员变量都用private修饰
不被访问的方法可以用private修饰
不想被重写但让子类访问的方法可以用public final修饰
希望某方法被子类访问和重写但不希望其他类自由访问可以用protect修饰
尽量不在构造器中使用将被重写的方法
继承和组合的使用
继承的两个类之间是“是”的关系
组合两个类之间是“有”的关系
类只能单继承类,但接口可以多继承接口,类可以多实现接口
多态
即多种形态,通常表现于接口或抽象类中抽象方法的不同实现
表现形式就是方法重写
分类
编译时类型
运行时类型
成员变量不存在多态,多态只可能发生在行为上
多态存在的必要条件
存在继承关系
存在重写
存在父类引用指向子类对象
向下转型
父类向子类转需要强转
强转后释放子类的拓展属性和方法
向上转型
子类可以自动转换为父类
转换成父类以后将隐藏子类的拓展属性和方法
七大设计原则
单一职责原则
就是使类所具有的功能尽量单一
开闭原则
对扩展开放,对修改关闭
依赖倒转原则
抽象不应该依赖于细节,细节应该依赖于抽象
针对抽象(抽象类或接口)编程,而不是针对实现编程
里式替换原则
所有引用基类(父类)的地方必须能透明地使用其子类的对象。
接口隔离原则
使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
接口隔离原则与单一职责原则区别:其一,单一职责原则注重的是职责;而接口隔离原则注重对接口依赖的隔离。
其二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口,主要针对抽象,针对程序整体框架的构建。
其二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口,主要针对抽象,针对程序整体框架的构建。
合成复用原则
复用时要尽量使用组合/聚合关系(关联关系),少用继承。
迪米特原则
一个软件实体应当尽可能少地与其他实体发生相互作用,低耦合。
UML建模(visio工具)
常用的几类图:包括类图、用例图、时序图、状态图等
内部类
特征
内部类更好的封装隐藏,不允许同包下其他类访问
内部类可以直接访问外部类私有数据,反之不行
匿名内部类适用于创建仅需使用一次的类
分类
成员内部类
将一个类定义在另一个类的类中
成员内部类可以无条件访问外部类数据,外部类需要创建内部类对象,通过对象访问
若内部类与外部类发生重名,则这些数据在内部类将被隐藏
不可包含静态属性和方法
局部内部类
局部内部类存在于方法中。和成员内部类的区别:局部内部类的访问权限仅限于方法或作用域内
局部内部类只能访问外部类的final变量
不能由权限修饰符和static修饰
匿名内部类
没有构造方法
只能访问外部类的final变量
传参如果是一个接口,可以直接在方法括号内创建接口的匿名内部实现类
静态内部类
由static修饰的内部类
不可访问外部类的非静态变量和方法
静态内部类不可包含非静态成员
不同点
权限修饰符
private
protected
static
default
public
非静态内部类不能拥有静态成员
非静态内部类不可以拥有静态初始化块,可以拥有普通初始化块
内部类实例的创建
外部类.内部类 对象名 = new 外部类.内部类();
外部类.内部类 对象名 = 外部类对象名.new 内部类();
Java包和类
java.lang
String
String常用方法
indexOf
返回int下标
传字符或字符串
查找第一次出现的字符的位置
split
返回字符串
传入字符串
按指定字符分割字符串
codePointAt
返回整形
传整形下标
将指定位置字符转换成Unicode码
valueOf
返回字符串
传入八种数据类型+Object
将传入的转换为字符串
getByte
返回byte[]
不传参
按默认编码集将指定字符串转换成字节码
charAt
返回char
传int下标
按照下标取字符
startWith
返回boolean
传int,int
判断该字符串是否以指定字符串开始
endWith
返回boolean
传int,int
判断是否以指定字符串结束
substring
返回string
截取字符串
equals
返回boolean
判断字符串是否相等
equalsIgnoreCase
返回boolean
忽略大小写比较字符串
isEmpty
返回boolean
判断字符串是否为空字符串
lastIndexOf
返回int
判断字符串最后一次出现指定子字符串的下标
contains
返回boolean
传CharSequence(String的父类)
判断字符串是否包含指定字符串
concat
返回String
将两个字符串连接
length
返回int
返回字符串长度
trim
返回String
删除字符串两端空格
compareTo
返回int
比较两个字符串在字典中的位置
为什么设计成final的
常量池需要
虚拟机对字符串是有优化的,有字符串常量池
如果字符串可以改来改去,那字符串常量将没有意义
缓存hash值
安全性
Java对String的特殊支持
+、+=用于字符串拼接
加号操作一定出现新的String对象
“asa”可以直接创建一个字符串对象
jvm对String拼接的优化
底层
1.8之前 final修饰的char数组
1.9 final修饰的byte数组
该字符串长度不可变,只要是改变字符串的值,一定是new一个新的字符串对象
StringBuilder
底层是没有final修饰的char数组
利用数组复制实现可变字符串
利用数组复制实现可变字符串
常用方法
substring
字符串截取
该方法是StringBuilder父类的方法
该方法与String的substring方法类似
append
字符串拼接
delete
insert(int offset, String str)
初始容量为16个字符
StringBuffer
跟StringBuilder本质一样
主要区别是StringBuilder多了线程安全
Math
System
arraycopy
Thread
使用lang包中的类不用使用import导包,系统自动导入
java.util
工具类
Arrays
copyOf
toString
binarySearch()
List
Set
java.io 输入输出流
java.net 网络编程有关
java.sql JDBC相关类
java.lang.reflect、java.nio、java.util.concurrent
swing、awt 图形用户界面
不可变类
用final和private修饰类的成员变量
提供有参构造方法给成员变量初始化
只提供getter方法
必要时提供hashCode和equals
java.lang.String和八个包装类均为不可变类
不可变类的实例变量不可被改变,可以缓存实例,下次直接拿来用,不必再创建对象
例如Integer就是缓存Integer的实例,缓存的是Integer的value值在-128到+127的实例
enum类通常应该被设计成不可变类,使其成员变量不允许改变
AWT
abstract Window Toolkit,抽象窗口工具包,该包提供了一套与本地图形界面进行交互的接口,是Java提供的用来建立和设置Java的图形用户界面的基本工具
Swing
对AWT的扩展,更好的实现Java图形化编程
IO
流的分类
按方向
输入流(将文件读入到内存称为输入流)
只能从中读取数据而不能写
输出流(将内容从写入到文件称为输出流)
只能向其写数据而不能读
按功能
字节流
操作的数据单元是8位的字节
主要是InputStream和OutputStream作为基类
他们都是抽象类,无法直接创建实例
字符流
操作的数据单元是16位的字符
主要有Reader和Writer作为基类
主要有Reader和Writer作为基类
字符流可以将字符串作为物理节点
对象流
按角色
节点流:构造器参数是物理节点的流
低级流
程序直接与数据源连接
处理流(也称包装流):构造器参数不是物理节点,而是已存在的流
高级流
程序与数据源不直接连接,通过处理流包装已存在的流进行数据处理
IO的四十多个类的抽象基类
所有输入流基类
InputStream:字节输入流
方法
int read()
读取一个字节数据,返回这个字节数据的十进制整数值
int read(byte[] b)
读取一组字节数据并放入byte类型的数组中
返回读取的字节数
int read(byte[] b, int off, int len)
读取一组字节数据放入byte数组中
从off开始
读取len个字节放入数组
返回读取的字节数
FileInputStream -> InputStream
Reader:字符输入流
方法
int read()
读取一个字符数据返回这个字符的int值
int read(char[] c)
读取一组字符并放入char类型的数组中
返回读取的字符数
int read(char[] c, int off, int len)
读取一组字符放入char类型的数组中
从off开始
读取len个字符
返回读取的字符数
FileReader -》 InputStreamReader -》 Reader
所有输出流基类
OutputStream:输出字节流
write(int c)
将指定的字节输出到流中
void write(byte[] b)
将指定字节数组输出到指定流
void write(byte[] b, int off, int len)
将指定字节数组输出到流
从off开始
输出len个字节
FileOutputStream继承自OutputStream
Writer:输出字符流
write(int c)
将指定的字符输出到流中
void write(byte[] b)
将指定字符数组输出到指定流
void write(byte[] b, int off, int len)
将指定字符数组输出流
从off开始
输出len个字节
void write(String s)
将字符串输出到指定流
void write(String s, int off, int len)
将制定字符串输出到指定流
从字符串的off开始输出
输出len个字符
FileWriter -》 OutputStreamWriter -》 Writer
流的关闭
void close()
保证流的物理资源被收回
保证缓冲当中的数据flush到数据节点即输出目标中
处理流
特点
只要构造器中传的不是物理节点而是一个已有的节点流,那这个流一定是处理流
处理流的关闭只需要将最开始定义的处理流关闭即可,系统会自动关闭被该处理流包装的节点流
常见处理流
打印流
特点
此流不负责数据源,只负责数据目的
为其他流添加功能
永远不会抛出IOException,但会抛出别的异常
两个打印流的方法是一致的
PrintStream:字节打印流
PrintWriter:字符打印流
转换流
InputStreamReader:将字节输入流转换为字符输入流
参数传字节输入流
将字节输入流转换为字符输入流
该类父类为Reader
OutputStreamWriter:将字节输出流转换字符输出流
参数为字节输出流
将字节输出流转换为字符输出流
该父类为Writer
BufferedReader:字符输入流
提供readLine()方法每次读一行
继承自Reader
BufferedWriter:字符输出流
newLine()写入一个换行符
继承自Writer
输入流/输出流
字节流/字符流
区分阻塞、非阻塞、同步、异步
阻塞:等待结果返回,当前操作线程被挂起,后续操作被阻断
非阻塞:不等待返回结果,直接执行后续操作
非阻塞:不等待返回结果,直接执行后续操作
同步:轮询模型
异步:监听模型
异步:监听模型
序列化与反序列化
序列化的目的
序列化机制允许将实现序列化的对象转换成字节序列,这些字节序列
可以存到磁盘或者通过网络传输,以备以后重新恢复成原来的对象
可以存到磁盘或者通过网络传输,以备以后重新恢复成原来的对象
序列化的意义
使得对象可以脱离程序的运行而独立存在
什么是序列化
对象的序列化指将一个Java对象写入IO流
方法不会被序列化,序列化的仅仅是数据
对象的反序列化是从IO流中恢复Java对象
序列化
序列化类型
JDK Serializable 对象序列化
ObjectInputStream、ObjectOutputStream
JSON 序列化
Fastjson、Jackson、Gson等库
XML序列化
XStream、JAXB等
序列化协议
反序列化
实现Externalizable接口
对象流实现序列化
首先该对象的类实现可序列化接口
静态不是对象的一部分所以不参与序列化
序列化步骤
1、创建ObjectOutputStream,该输出流是一个处理流
2、调用该处理流的writeObject()方法输出可序列化对象
当一个可序列化类有多个父类时,(包括直接父类和间接父类),这些父类要么有无参构造器,要么是可序列化的
否则在反序列化时将抛出InvalidClassException异常,如果父类不是可序列化的,只是带有无参构造器,那么在
序列化时,父类中定义的成员变量的值不会序列化到二进制流中
否则在反序列化时将抛出InvalidClassException异常,如果父类不是可序列化的,只是带有无参构造器,那么在
序列化时,父类中定义的成员变量的值不会序列化到二进制流中
反序列化
1、创建ObjectInputStream流,该流同样是处理流
2、调用处理流的readObject()方法读取流中的对象,如果知道对象的类型,可以强转
反序列化读取的是Java对象的数据而不是Java类,因此采用反序列化恢复对象时必须提供Java对象所属的class文件
如果找不到,则发生类找不到异常。另外,反序列化无须调用构造函数来初始化Java对象。
如果找不到,则发生类找不到异常。另外,反序列化无须调用构造函数来初始化Java对象。
使用序列化机制向文件写入多个Java对象,使用反序列化恢复对象时必须按照写入顺序进行读取
反序列化对象时,不会调用该对象的构造函数,但如果该对象所属类有父类,且父类是不可序列化的,则会调用父类无参构造函数
如果父类是可序列化的,则不会调用
如果父类是可序列化的,则不会调用
对象引用序列化
当一个类中的成员变量是一个引用类型,那这个引用类型必须是可序列化的,
否则,不管你实现还是不实现Serializable接口,你的类都不可以实现序列化
否则,不管你实现还是不实现Serializable接口,你的类都不可以实现序列化
特殊序列化机制
1、所有保存到磁盘的对象都有一个序列化编号
2、当程序试图序列化一个对象时,程序将先检查该对象是否已被序列化,只有该对象从未被序列化的时候,才会被序列化
3、如果对象已经被序列化过,那么程序将只是输出一个序列化编号,而不是再次重新序列化该对象
**当反序列化两次一个对象时,他们返回的对象用==判断则返回true
注意
当程序序列化一个可变对象时,只有第一次使用writeObject()方法输出时才会将该对象转换成字节序列并输出。
当程序第二次调用方法输出,程序只是输出前面序列化编号,即使后面对象实例变量值已经改变,改变的实例变量也不会被输出
当程序第二次调用方法输出,程序只是输出前面序列化编号,即使后面对象实例变量值已经改变,改变的实例变量也不会被输出
自定义序列化
递归序列化
序列化一个对象,若它的成员变量引用到另一个对象,那也会序列化引用到的对象
引用到的对象的成员变量又引用到另一个对象,则也会序列化这个对象
引用到的对象的成员变量又引用到另一个对象,则也会序列化这个对象
transient
只能修饰实例变量
作用是让序列化忽略该实例变量
该变量称为瞬态实例变量
特殊签名的方法
readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
writeObject(ObjectOutputStream out) throws IOException
序列化注意事项
对象的类名、实例变量(包括基本类型、数组和对其他独享的引用)都会被序列化;方法、类变量,transient都不会被序列化
实现Serializable接口的类如果需要让某个实例变量不被序列化,用transient关键字,而不是static,虽然static可实现此效果,但不合理
保证序列化对象的成员变量类型也是可序列化的,否则使用transient关键字,不然这个类不可序列化
反序列化对象时必须有序列化对象的class文件
当通过文件、网络来读取序列化对象时,必须按照实际写入顺序读取
序列号冲突问题
在编辑器将java文件编译成class文件的同时,如果这个类可序列化,则给这个类可序列化,则给这个类计算序列号,第一次
序列化该类对象时,按照该序列号为准,当序列化以后改变了类的内容,则编辑器重新编译且生成新序列号,此时再反序列化
则会出现序列号冲突,反序列化异常
序列化该类对象时,按照该序列号为准,当序列化以后改变了类的内容,则编辑器重新编译且生成新序列号,此时再反序列化
则会出现序列号冲突,反序列化异常
给该可序列化类定义序列号:格式要求static final long serialVersionUID = 222L
IO(同步阻塞IO)
字节流/字符流
对象序列化
实现Serializable接口
readObject(ObjectInputStream ois)、writeObject(ObjectOutputStream oos)方法
文件操作(磁盘读写)
创建/删除文件
读/写文件
NIO(同步非阻塞IO),利用多路复用技术
传统IO(BIO)与NIO的区别:IO是面向流的,NIO是面向缓冲区的
主要组成
Channel(通道,双向)
多路复用。传统IO的流是单向的,不能同时用来进行读写操作,而Channel则是双向的
通过open()静态方法打开一个通道
Selector(选择器)
Selector类是NIO的核心类,它能够检测多个注册的Channel上是否有事件发生,如果有事件发生,便获取事件然后进行相应的处理
通过Selector.open()静态方法选择一个事件进行处理
Buffer(缓存区)
其作用相当于BIO编程中常用的基本类型数组(byte[]、char[]等),比如ByteBuffer就是对byte数组进行的封装,使得操作起来更方便。
1、使用的是堆外内存,不受GC管理(GC主要是堆内存);2、非线程安全。
1、使用的是堆外内存,不受GC管理(GC主要是堆内存);2、非线程安全。
Netty/Mina框架
基于NIO的网络框架,通常用于分布式应用开发中进行网络数据传输
AIO(异步非阻塞IO)
File
特点
File可以创建删除重命名文件和目录(目录就是文件夹)
File不可以访问文件本身的内容
常用方法
exists()判断文件或目录是否存在
isFile()判断File对象对应的是否是文件而不是目录
isDirectory()判断对象是否是目录而不是文件
createFile()当此File对象对应的文件不存在时将创建一个新文件,创建成功返回true,否则返回false
delete()删除对象对应的文件或空路径,如果想要产出一个文件夹下所有东西,
包括这个文件夹下的目录文件与子目录及其文件,可以使用递归
包括这个文件夹下的目录文件与子目录及其文件,可以使用递归
mkdir()创建目录,但需要有父目录
mkdirs()创建目录不需要父目录存在
getName()以字符串形式返回文件或目录名
list()获取路径下所有子目录和文件的名,返回String数组
listFile()获取File对应的路径下的目录和文件的全路径,返回File数组
过滤器
FileFilter
方法accept(File pathname)
accept的参数是listFile方法传递过来的
在accept方法中,进行判断,如果满足自己要求,则将true返回给listFile方法,此时listFile将
此时拿到的全路径保存到File数组中
此时拿到的全路径保存到File数组中
若拿到的路径不满足自己的要求,则返回给listFile方法false,此时不保存该路径
listFile(FileFilter接口实现类)
该方法在获取到文件全路径的同时,会去调用过滤器的accept方法,并将全路径作为参数传给accept方法
遍历多级目录需要使用递归
多线程
线程与进程
线程的本质
线程本质上是进程中一段并发操作的代码,所以线程需要操作系统投入CPU资源来运行和调度
进程
一个程序进入内存运行时,就变为一个进程
进程是操作系统进行资源分配和调度的一个独立单位
进程的三个特征
独立性
是系统中独立存在的
拥有自己私有的地址空间
拥有自己独立的资源
动态性
进程拥有自己的生命周期和各种状态
并发性
多个进程可以在单个处理器上并发执行,各个进程之间不会相互影响
并发性与并行性
并发性是同一时刻一条指令在单个处理器上执行,
由于处理器快速轮换,就好像多条指令同时执行
由于处理器快速轮换,就好像多条指令同时执行
并行性是同一时刻多条指令在多个处理器上同时执行
线程
当一个程序运行时,内部包含多个顺序执行流,每个顺序执行流就是一个线程
线程是进程的基本单位,线程是程序的最小执行单元
每个进程包含一个或多个线程
同一个进程内的线程独立运行但资源共享
关联:一个程序至少有一个进程,一个进程又至少包含一个线程
引入线程的目的是充分利用CPU资源,使其可以并行处理多个任务,减少时间消耗
线程分类
用户线程User Thread
一般是程序中创建的线程
守护线程Daemon Thread
为用户线程服务的线程当所有非守护线程结束时才会被终止。如JVM的垃圾回收、内存管理等。
通过thread.setDaemon(true)来将一个线程变成守护线程
isDaemon()判断线程是否为后台线程
当前台线程全部死亡,后台线程也会直接死亡
线程的创建方式
继承Thread类
1、定义Thread的子类并重写run()方法,该方法就是线程执行体
2、创建Thread子类的实例,该实例就是线程对象
3、用该实例调用start()方法就启动了一个线程
实现Runnable接口
1、定义Runnable接口的实现类,并重写run()方法,该方法就是线程执行体
2、创建实现类的实例,并以此实例作为Thread的target来创建Thread对象
3、用Thread对象调用start()方法启动线程
使用Callable和Future创建
Callable接口
call()方法
Callable接口提供了call()方法作为线程执行体,该方法可以有返回值
该方法可以声明抛出异常
该接口不是继承自Runnable接口,所以不可作为Thread的target
Callable有泛型限制,且泛型与call方法的返回值类型一致,Callable是函数式接口,可以用lambda表达式表示
Future接口
提供一个FutureTask实现类,该类实现了Future、Runnable接口,可以作为Thread的target
让FutureTask与Callable关联,来代表Callable接口中call()方法的返回值,并作为Thread的target
提供的方法
cancel()
get()
isDone()
isCancelled()
创建线程步骤
1、创建Callable接口的实现类并实现call()方法,该方法作为线程执行体
2、使用FutureTask类来包装Callable对象,该FutureTask对象封装了call()方法的返回值
3、使用FutureTask对象作为Thread对象的target创建并启动线程
4、调用FutureTask对象的get()方法来获得返回值
线程的生命周期
Java六种线程状态
新建状态New
Thread类
实现了Runnable接口
run方法,无返回值
Runnable接口
run方法,无返回值,通过Thread类或线程池来使用
Callable接口
作为FutureTask构造方法参数使用
call方法,有返回值,且可以抛出异常
call方法实际是在Runnable的run方法中被执行
Runnable
就绪状态
当一个新建线程调用start()方法,该线程由新建状态变为就绪状态
不一定会立即运行,可能需要等待CPU分配时间片
运行状态
当就绪状态的新线程获得cpu,该线程变为运行状态
阻塞状态Blocked
当运行状态的线程遇到IO请求或者调用sleep()方法,线程变为阻塞状态
调用Object的wait方法后等待同步锁的状态(notify通知)
程序调用了线程的suspend()挂起方法,该方法容易导致死锁
等待Waiting
发生在调用以下几个方法时:不带参数的Object.wait()不带参数的Thread.join()/LockSupport.park()
超时等待Timed-Waiting
与Waiting状态不同在于不会一直等待,而是等待指定的时间
发生在调用以下几个方法时:Thread.sleep()、Object.wait(long timeout)、Thread.join(long timeout)、LockSupport.parkNanos()、LockSupport.parkUntil()
终结状态Terminated
线程执行体执行完成正常结束变为死亡状态
线程调用stop()方法,线程变为死亡状态
传统线程模型的3种或5种状态
三种状态:就绪、运行、等待
五种状态:新建、就绪、运行、等待、退出
RUNNABLE拆解成就绪和运行状态,另外Java的BLOCKED、WAITING、TIMED_WAITING都属于传统模型的等待状态。
Thread类的常用方法
Thread.sleep()方法
1、sleep方法是Thread类的静态方法,是为了保证该操作只对当前线程有效,避免线程安全问题,其它几个常用静态方法类似。2、让当前正在运行的线程暂时停止运行,一段时间后会继续执行。
Thread.yield()方法
当前处于运行状态的线程主动放弃占用的CPU资源,转变为就绪状态,让其他优先线程执行(让步)
join方法
在当前线程执行过程中引入另一个线程,并且当前线程需要等待另一个线程执行完毕后才能继续执行
Thread.currentThread()方法
获取当前正在运行的线程
改变线程优先级
setPriority(int priority)
getPriority()
停止线程的方法
Thread.stop方法:已废弃
使用一个标识来表示线程的状态,通过更改它的值来控制线程的运行和停止
interrupt 中断方法
让多个线程顺序执行的方式
利用Thread的join方法
线程间通信
Object类提供了三个控制线程的方法,该方法由线程同步监视器调用
wait()方法
notify方法
这三个方法用于协调多个线程对共享数据的存取(获取锁和释放锁),所以必须先获得锁(即在synchronized语句块内使用),否则会抛出illegalMonitorStateException异常
notifyAll方法
Condition接口下的方法控制线程通信
获取Condition的实例
Condition con = lock.newCondition()
API
await()
singal()
singalAll()
线程其他相关类
ThreadLocal
代表线程局部变量,在共享对象内部创建一个ThreadLocal类型的泛型的成员变量即可
API
set(T value)
设置线程副本的值
get()
获取线程变量副本的值
remove()
remove()
线程同步
volatile
MESI
当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取
volitale会一直嗅探 cas 不断循环无效交互 导致带宽达到峰值
总线风暴
Java内存模型JMM
高速缓存
可见性
线程可见:即一个线程将其改变,其他线程立马可以知道
嗅探机制 强制失效
处理器嗅探总线
有序性
禁止指令重排序:指程序中上下两条无关的代码执行不会被指令重排序
lock 前缀指令 内存屏障
源代码->编译器优化重排序->指令级并行重排序->内存系统重排序->最终执行的指令序列
指令重排序是指在运行程序是,处理器为了优化性能,代码的执行顺序可能不会按代码的顺序执行
happens-before
volatile变量规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读。
as-if-serial
线程每次都从主内存中读取变量,改变后再写回到主内存。其作用如下:
1、使变量在多个线程间具有可见性;
2、禁止JVM进行指令重排序(保证有序性)。
1、使变量在多个线程间具有可见性;
2、禁止JVM进行指令重排序(保证有序性)。
不能保证原子性,非线程安全
只能修饰成员变量,可以称之为轻量级synchronized
应用场景
一写多读,保证变量可见性
开销较低的读写锁策略
只在写操作时需要加synchronized同步锁,读操作不需要
synchronized
在JVM层面实现了对临界资源的同步互斥访问,锁的释放不用人工干预,由虚拟机完成
1、在volatile基础上增加了互斥锁,所谓“互斥”就是同一时间只能有一个线程操作该资源;
2、在JDK1.5以后,为了弥补synchronized的不足,引入了Lock来代替它,将同步锁对象换成了Condition对象,并且Condition对象可以有多个。
2、在JDK1.5以后,为了弥补synchronized的不足,引入了Lock来代替它,将同步锁对象换成了Condition对象,并且Condition对象可以有多个。
用法
同步代码块
通常将外界资源作为锁的对象
synchronized(obj){ // 同步操作代码 }
把对共享资源的操作的代码放在同步代码块中,使其任何时刻只能有一个线程访问该代码块
用于保护外界资源不被多个线程并发修改
与同步方法比较而言,使用同步代码块的好处在于其它线程扔可以访问同步代码块以外的代码
同步方法
用synchronized关键字修饰方法
原子性
被保护的代码只能被一个线程访问
可见性
执行完该关键字保护的代码块后,修改的变量对其他线程是可见的
有序性
锁的对象是当前调用对象this
public synchronized void test() { // 同步操作代码 }
用于保护对象属性值不会被多个线程并发修改,因此需要保证调用方法的对象是同一个才有意义
同步静态方法
锁的对象是类的Class对象
public static synchronized void test() { // 同步代码 }
用于保护类的静态属性值不会被多个线程并发修改
缺点:1、无法知道是否成功获取到锁;2、如果是多个线程需要同时进行读操作,一个线程读操作时其他线程只有等到(互斥)
对象
对象头(Header)
Mark Word(存储对象的HashCode,分代年龄和锁标志位信息。)
Klass Point(对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。)
Monitor
EntryList
Owner(会指向持有 Monitor 对象的线程)
WaitSet
实例数据
对齐填充
方法
ACC_SYNCHRONIZED
monitorenter
monitorexit
锁膨胀
无锁
偏向锁
Mark Word 中有线程信息 cas 比较
轻量级
复制了一份mark work 叫 Lock record 也是cas尝试改变指针
自旋
死循环
重量级
特性保证
有序性
as-if-serial
happens-before
可见性
内存强制刷新
原子性
单一线程持有
可重入性
计数器
重锁
用户态内核态切换
同步锁Lock接口
JDK层面实现的互斥锁,比起synchronized可控性更强,弥补了synchronized的不足。使用后必须手动释放锁,否则可能会导致死锁。
包含lock(如果没获取到,会一直阻塞直到成功获取到锁)、tryLock(尝试获取锁,如果没获取到不会一直阻塞,可以指定等待时间)、unlock(释放锁)几个常用方法,都需要显示调用。
创建锁对象
每次只能有一个线程对Lock对象加锁,访问共享对象之前应先获得Lock对象
ReentrantReadWriteLock
ReadLock(读锁)
WriteLock(写锁)
ReentrantLock(可重入锁)
NonfairSync
tryAcquire
acquireQueued
CAS
FairSync
hasQueuedPredecessors
如果是当前持有锁的线程 可重入
AbstractQueuedSynchronizer
入队 出队
头结点设计
共享和独享的实现
CAS
cpu开销
只能保证一个共享变量原子操作
AtomicReference
ABA
标志位 时间戳
StampedLock
Condition接口
提供了类似Object类中wait、notify、notifyall的方法,主要包括await、signal、signalAll方法,与synchronized和wait、notify/notifyAll的搭配类似,这些方法与Lock锁配合使用也可以实现等待/通知机制
无锁技术CAS
CAS即Compare And Swap的缩写。Java中的原子操作类如AtomicInteger底层就是依赖它实现的。实现原理:CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
sync 和 Lock的区别
synchronized是关键字,是JVM层面的底层啥都帮我们做了,而Lock是一个接口,是JDK层面的有丰富的API。
synchronized会自动释放锁,而Lock必须手动释放锁。
synchronized是不可中断的,Lock可以中断也可以不中断。
通过Lock可以知道线程有没有拿到锁,而synchronized不能。
synchronized能锁住方法和代码块,而Lock只能锁住代码块。
Lock可以使用读锁提高多线程读效率。
synchronized是非公平锁,ReentrantLock可以控制是否是公平锁。
synchronized会自动释放锁,而Lock必须手动释放锁。
synchronized是不可中断的,Lock可以中断也可以不中断。
通过Lock可以知道线程有没有拿到锁,而synchronized不能。
synchronized能锁住方法和代码块,而Lock只能锁住代码块。
Lock可以使用读锁提高多线程读效率。
synchronized是非公平锁,ReentrantLock可以控制是否是公平锁。
劣势
锁升级不可逆
悲观锁
对应现实生活中悲观的人,即什么事情都想的比较坏。在进行数据访问的时候,总是想着一定会有人来争抢资源,所以悲观
锁是在用之前就上锁。数据库中的行锁,表锁等,读锁、写锁等都属于悲观锁,另外synchronized锁和Lock锁都是悲观锁机制
锁是在用之前就上锁。数据库中的行锁,表锁等,读锁、写锁等都属于悲观锁,另外synchronized锁和Lock锁都是悲观锁机制
适用场景
悲观锁适用于多写的应用场景,多写的场景发生线程冲突的情况较多,适合使用之前就加锁
乐观锁
对应于现实生活中乐观的人,即把什么事都想得比较好,在进行数据访问的时候,总是认为没有人访问,所以乐观锁是在使用
数据的时候不会上锁,而是在最后更新的时候通过版本号机制或CAS算法判断有没有其他线程更新,再决定是否驳回操作
数据的时候不会上锁,而是在最后更新的时候通过版本号机制或CAS算法判断有没有其他线程更新,再决定是否驳回操作
适用场景
乐观锁适用于多读应用程序,在这种多读情景下,线程发生冲突较少,适用使用前不加锁
版本号机制
数据库每张表都有一个版本号,每次更新版本号都会加1,在读数据库的时候,也会读取该表的版本号,当对表中数据做更新
的时候,会检查此刻的版本号跟起初读的版本号是否一致,如果不一致,将驳回本次更新操作
的时候,会检查此刻的版本号跟起初读的版本号是否一致,如果不一致,将驳回本次更新操作
CAS算法
无锁算法,所以又叫非阻塞同步
线程池
newFixedThreadPool
newCacheThreadPool
SynchronousQueue
newSingleTheadExecutor
newScheduledThewadPool
DelayedWorkQueue
newWorkStealingPool
ThreadPoolExecutor
参数意义
核心线程数
默认没线程等任务来了才调用 除非调用了 预创建线程 一个或者全部
最大线程数
空闲时间&单位
没有执行任务多久会终止 当线程池的线程数大于核心线程才会起作用 调用allowCoreThreadTimeOut会起作用
缓冲队列
LinkedBlockingQueue
无界 当心内存溢出
ArrayBlockingQueue
有界队列
加锁保证安全 一直死循环阻塞 队列不满就唤醒
入队
阻塞调用方式 put(e)或 offer(e, timeout, unit)
阻塞调用时,唤醒条件为超时或者队列非满(因此,要求在出队时,要发起一个唤醒操作)
进队成功之后,执行notEmpty.signal()唤起被阻塞的出队线程
阻塞调用时,唤醒条件为超时或者队列非满(因此,要求在出队时,要发起一个唤醒操作)
进队成功之后,执行notEmpty.signal()唤起被阻塞的出队线程
在进行某项业务存储操作时,建议采用offer进行添加,可及时获取boolean进行判断,如用put要考虑阻塞情况(队列的出队操作慢于进队操作),资源占用。
Synchronous
线程工厂方法
拒绝策略
抛异常
丢弃
重试
丢弃最早提交的
使用Hash表维护线程的引用
submit
使用future获取任务的执行结果
执行过程
核心线程->队列->最大线程->拒绝策略
运行状态
有个Volatile的状态码
running
shutdown
stop
terminated
所有线程销毁
corePoolSize、maximumPoolSize、largestPoolSize
定时任务
Timer & TimerTask类
Timer:任务调度器,通过schedule(TimerTask task, long delay)等方法进行调度。
TimerTask:实现了Runnable接口。表示需要调度的任务,里面有一个run方法定义具体的任务。
TimerTask:实现了Runnable接口。表示需要调度的任务,里面有一个run方法定义具体的任务。
Timer缺点:内部是单线程,因此如果有异常产生,线程将退出,整个定时任务就会失败
线程池
ScheduledExecutorService,它是ExecutorService的子接口。弥补了Timer的缺陷
通过 scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
和 scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)等方法来实现定时任务调度
和 scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)等方法来实现定时任务调度
并发编程
JUC
线程池
作用
1、减少资源消耗。通过重复利用池中已创建的线程,减少频繁创建、消耗线程带来的资源消耗。
2、提高响应速度。当线程池中有空闲线程,任务到来时无需创建线程就能立即被执行。
3、提高线程的可管理性。由线程池对池中的线程进行统一的管理和监控,可以防止无限制创建线程造成的资源浪费。
2、提高响应速度。当线程池中有空闲线程,任务到来时无需创建线程就能立即被执行。
3、提高线程的可管理性。由线程池对池中的线程进行统一的管理和监控,可以防止无限制创建线程造成的资源浪费。
ExecutorService接口
ThreadPoolExecutor类
Executor的子类
Executors工具类
包含创建线程池的工厂(静态)方法
线程池大小配置
一般需要根据任务类型来配置线程池大小:1、如果是CPU密集型任务,就需要尽量压榨CPU,参考值可以设为 NCPU+1;
2、如果是IO密集型任务,参考值可以设置为2*NCPU。
CPU密集型(计算密集型,IO时间短),IO密集型(CPU在等I/O (硬盘/内存) 的读/写操作)
2、如果是IO密集型任务,参考值可以设置为2*NCPU。
CPU密集型(计算密集型,IO时间短),IO密集型(CPU在等I/O (硬盘/内存) 的读/写操作)
通过Runtime.getRuntime().availableProcessors()获得当前CPU个数
原子操作类,如AtomicInteger
使用CAS无锁技术保证变量的操作在多线程环境下正常,比synchronized控制的粒度更细、量级更轻,并且在多核处理器具有高性能
并发集合
ConcurrentHashMap
Java7
数组+链表
segment分段锁
继承了reentranLock
尝试获取锁,存在并发竞争,自旋,阻塞
get高效,volatile修饰,不需要加锁
volatile修饰节点指针
HashEntry
Java8
数组+链表+红黑树
CAS+synchronized
CAS失败自旋保证成功
再失败就sync保证
NODE
安全失败
CopyOnWriteArrayList
从字面上看就是“写时复制”。原理是当需要对集合中元素进行增删改操作时首先复制一个副本,对副本进行操作
适用于“读多写少”的并发场景
BlockingQueue
阻塞队列:1)当队列为空时,获取元素的线程会等待队列变为非空;2)当队列满时,存储元素的线程会等待队列可用。内部通过Lock与Condition(即通过等待/通知机制)实现,通常用于生产者-消费者场景
ArrayBlockingQueue:有界队列,即队列容量有限,内部是数据结构
LinkedBlockingQueue:即可以是有界队列,又可以是无界队列。若创建时不指定容量,则默认是Integer.MAX_VALUE
SynchronousQueue:同步队列
不保存元素
PriorityBlockingQueue:优先级队列
属于无界队列,按照队列中的任务优先级由高到低进行处理
通过Comparator比较器来决定优先级
ThreadLocal线程本地变量
1、它为每个线程都提供一个独立的变量副本,各个线程都可以改变自己的变量副本,各个线程间互不影响。因此可以解决并发问题。
2、实现的思路:①在ThreadLocal类中有一个静态内部类ThreadLocalMap,用于存储每一个线程的变量副本,键为ThreadLocal对象,而值则是对应线程的变量副本;②每个ThreadLocal实例都有一个唯一的threadLocalHashCode(这个值将会用于在ThreadLocalMap中找到ThreadLocal对应的value值)。
3、工作原理:①在Thread类中维护一个ThreadLocalMap变量(与线程进行绑定);②取值get操作:从ThreadLocal中取变量值时先获取当前线程,通过当前线程得到与之关联的ThreadLocalMap,然后再从ThreadLocalMap中根据当前ThreadLocal获取到其中的变量值(如果ThreadLocalMap为空,则返回初始化方法initialValue()的值);set操作类似。
2、实现的思路:①在ThreadLocal类中有一个静态内部类ThreadLocalMap,用于存储每一个线程的变量副本,键为ThreadLocal对象,而值则是对应线程的变量副本;②每个ThreadLocal实例都有一个唯一的threadLocalHashCode(这个值将会用于在ThreadLocalMap中找到ThreadLocal对应的value值)。
3、工作原理:①在Thread类中维护一个ThreadLocalMap变量(与线程进行绑定);②取值get操作:从ThreadLocal中取变量值时先获取当前线程,通过当前线程得到与之关联的ThreadLocalMap,然后再从ThreadLocalMap中根据当前ThreadLocal获取到其中的变量值(如果ThreadLocalMap为空,则返回初始化方法initialValue()的值);set操作类似。
CountDownLatch(倒计数器)
利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他几个任务执行完毕之后才能执行,就可以使用CountDownLatch来实现。
两个关键方法:await()等待其他线程执行完毕才开始执行、countDown()当有一个线程执行完毕就减1,当减到0时当前线程开始执行。
CyclicBarrier(回环栅栏)
通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用。
关键方法:await()方法,此方法作用是等待其它线程都到同一状态时开始同时执行。类似于长跑比赛中,当所有运动员都准备完毕才开始比赛。
Fork/Join 多线程并行框架
利用分而治之的思想,将大任务分成小任务执行,然后合并结果;分别对应fork、join两个操作。
Fork/Join框架的核心是ForkJoinPool类,它是对AbstractExecutorService类的扩展。ForkJoinPool实现了工作窃取(work-stealing)算法,并可以执行ForkJoinTask任务。
线程死锁
产生死锁的四个必要条件
互斥条件:资源不能被共享。即任一时刻一个资源只能给一个进程使用,其他进程只能等待,直到资源被占用者释放。
不可剥夺条件:已经分配的资源不能从相应的进程中被强制地剥夺,而只能由获得该资源的进程自愿释放。
请求和保存条件:已经得到资源的进程可以再次申请新的资源。
循环等待条件:系统中若干进程组成环路,该环路中每个进程都在等待相邻进程占用的资源。
不可剥夺条件:已经分配的资源不能从相应的进程中被强制地剥夺,而只能由获得该资源的进程自愿释放。
请求和保存条件:已经得到资源的进程可以再次申请新的资源。
循环等待条件:系统中若干进程组成环路,该环路中每个进程都在等待相邻进程占用的资源。
预防死锁的方法
合理对资源进行动态分配,以避免死锁
破坏死锁产生的四个必要条件
常见问题
线程间是怎么进行通信的?
主要可以介绍一下 wait/notify 机制,共享变量的 synchronized 或者 Lock 同步机制等。
volatile
CountDownLatch
CyclicBarrier
ThreadLocal 用来解决什么问题?
可以从尽量减少临界区范围,使用 ThreadLocal,减少线程切换、使用读写锁或 copyonwrite 等机制这些方面来回答。
如何尽可能提高多线程并发性能?
ThreadLocal 是如何实现的?可以重点回答 ThreadLocal 不是用来解决多线程共享变量的问题,而是用来解决线程数据隔离
读写锁适用于什么场景?
可以回答读写锁适合读并发多,写并发少的场景,另外一个解决这种场景的方法是 copyonwrite。
如何实现一个生产者与消费者模型?
可以尝试通过锁、信号量、线程通信、阻塞队列等不同方式实现。
网络编程
网络通信协议
TCP/IP协议
应用最为广泛的协议
包括TCP和IP协议
端口号
程序在电脑中的唯一标识,范围在0~65535, 0~1024由计算机软件占用
IP地址
计算机在网络中的唯一标识
InetAddress
static InetAddress getByName() 通过主机名获取IP地址
static InetAddress getLocalHost() 获取本机IP地址
String getHostName() 获取主机名
String getHostAddress() 获取主机IP地址对象
传输协议
UDP
无连接通信协议
特点
发送端和接收端不会建立逻辑连接:当一台计算机向另一台计算机发送数据的时候不会去管接收端是否存在
就会发送数据,而接收端接收完数据也不会给发送端反馈
就会发送数据,而接收端接收完数据也不会给发送端反馈
资源消耗小、通信效率高
容易造成数据丢失
有传输大小限制,数据限制在64k以内
适用场景
视频会议
微信聊天、发短信
TCP
面向连接通信协议
三次握手
客户端向服务端发送连接请求,等待服务器确认
服务器向客户端回送一个响应,通知客户端收到了连接请求
客户端再次向服务器端发送确认信息,确认连接
特点
资源消耗相对较大,通信效率较低
传输大小理论没有限制
比较安全,不会造成数据丢失
适用
资源下载
文件传输
UDP通信
DatagramPacket
数据报包,用于封装数据
DatagramSocket
用于发送和接收数据包的
发送步骤
创建DatagramPacket对象,封装数据,接收端IP和端口
new DatagramPacket(byte[] b, int length, InetAddress address, int port)
创建DatagramSocket对象
new DatagramSocket()
调用DatagramSocket对象的send方法,发送数据包
关闭资源
接收步骤
创建DatagramSocket对象,绑定端口号,要求和发送数据的端口号一致
new DatagramSocket(int port)
创建字节数组用来接收数据
创建数据包DatagramPacket对象
调用DatagramSocket对象的,receive方法
receive(DatagramPacket dp) 接收数据,数据放在数据包中
拆包
发送的IP地址
接收到的字节个数
发送方的端口号(无意义)
关闭资源
TCP通信
面向连接,服务器先开机,客户端连服务器
ServerSocket
用于服务器端
使用构造方法接收客户端连接请求,传端口号,与客户端一致
new ServerSocket(int port)
使用ServerSocket对象的accept方法获取客户端Socket对象
server.accept()
调用客户端Socket对象获取字节输入流,读入客户端发来的数据
socket.getInputStream()
调用客户端Socket对象获取字节输出流,向客户端写数据
socket.getOutputStream()
Socket
用于客户端
客户端使用构造方法与服务器进行连接,如果连接失败则抛异常
new Socket(String IP, int port)
用客户端Socket对象获取输出流,向客户端写数据
socket.getOutputStream()
用客户端Socket对象获取输入流,读服务器发来的数据
socket.InputStream()
URL、URLConnection、HttpURLConnection
反射机制
涉及到的类或接口
Class(表示一个类或接口)、Constructor(构造方法)、Method(方法)、Field(对应接口或类中的属性)、Modifier(修饰类private、protected、public、static、final等)、ParameterizedType(泛型参数类型)等
JavaBean的内省
针对JavaBean的反射,包括BeanInfo、PropertyDescriptor(属性描述器)、Introspector(工具类)等常用类或接口
注解
注解(Annotation),也叫元数据。是一种代码级别的说明。
分类
元注解
@Target
用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
取值(ElementType)有:1、CONSTRUCTOR:用于描述构造器;2、FIELD:用于描述字段;3、LOCAL_VARIABLE:用于描述局部变量;4、METHOD:用于描述方法;5、PACKAGE:用于描述包;6、PARAMETER:用于描述参数;7、TYPE:用于描述类、接口(包括注解类型)或enum声明,如果:@Target(ElementType.Type)
@Retention
用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
取值(RetetionPoicy)有:1、SOURCE:在源文件中有效(即源文件保留);2、CLASS:在class文件中有效(即class保留);3、RUNTIME:在运行时有效(即运行时保留)如:@Retention(RetentionPolicy.RUNTIME)
@Documented
将此注解包含在javadoc中,它代表着此注解会被javadoc工具提取成文档。
@Inherited
允许子类继承父类的注解
@Repeatable(Java8新增)
允许注解使用多次
内建注解
@Override
供编译器检查,保证方法重写正确
@Deprecated
标记过时的方法或类型,并建议在javadoc指明替代方法或类型
@SuppressWarnings
使编译器忽略警告
@FunctionalInterface(Java8新增)
供编译器检查,接口是否满足函数式接口条件
自定义注解
区别于接口定义,使用@interface进行声明
泛型
?通配符
只读型容器
定界符super、extends
集合框架
Collection接口
Collection接口方法
add(Object)
addAll(Collection)
clear()
contains(Obj)
containsAll(Collection)
iterator
remove(Obj)
removeAll(Collection)
size()
toArray()
List接口
ArrayList
底层是Object类型的可变的数组
利用数组的拷贝来进行对容器内数据的操作
特点
有序
有下标
元素允许重复
在查找与修改某个位置的值时效率较高,元素多时在某个插入值时效率较低
常用方法
add()
add(E)
set(int,E)
addAll()
addAll(Collection<> c)批量插入
addAll(int index, Collection<> c)批量插入
set()
set(E)
set(int, E)
get(int)
remove(int index)
查找 访问速度快,增删效率低,线程不安全
LinkedList
底层是数据结构中的双向链表
利用节点的前后指向将一个个节点连接起来组成链
特点
有序
伪下标(利用循环一直.next就可以找到对应的节点)
元素允许重复
在插入时效率较高,元素多的时候查找效率低
常用方法
linkLast(E e)
linkFirst(E e)
add(E)默认在链表最后插入
addAll()
addAll(Collection<> c)批量插入
addAll(int index, Collection<> c)批量插入
clear()
get()
set(int, E)
add(int, E)
适合插入删除频繁的情况,内部维护了链表的长度
Vector
与ArrayList一样
只是比ArrayList多了线程安全,效率较低,已成为丢弃容器
Stack
栈
后进先出
API
push入栈
pop出栈
peek查看栈顶元素
empty判断是否为空
size元素个数
固定长度的list
调用Arrays的asList方法可将一个数组或指定个数的对象转为List
他是Arrays类中的内部类ArrayList的实例
只能遍历访问该集合元素,不可增删该集合
Set接口
HashSet
特点
按Hash算法来存储集合中的元素,查找插入超级快
无序
不支持排序
不是同步的,线程安全有问题
集合的元素可以为null
HashSet两个元素相等的标准是通过equals返回true并且哈希值相等
LinkedHashSet子类
也是根据哈希值存放
有序
内部多了一个LinkedList列表用来记录元素插入顺序
性能略低
当存入可变对象时,如果修改集合对象的内部成员变量,有可能使该对象与集合中其他对象相等,从而导致集合无法准确操作元素
SortedSet接口
TreeSet
采用红黑树的数据结构来存储集合元素
默认采用自然排序,并不是根据元素的插入顺序排序,而是根据元素的实际大小排序
TreeSet排序规则由两种实现方式
一种是自然排序:放入集合的元素需要实现Comparable接口,该接口定义了比较方法,在将元素添加进集合的时候,集合内部会调用该元素的比较方法进行排序,这也是为什么该集合存null会出现空指针异常
另一种是定制排序,存放的元素不需要实现接口,而是需要给集合传一个比较器,Comparator,该接口是一个函数式接口,传两个参数,返回int,如果等于零两元素相等,小于0,前者小于后者,大于零前者大于后者
默认采用自然排序,并不是根据元素的插入顺序排序,而是根据元素的实际大小排序
TreeSet排序规则由两种实现方式
一种是自然排序:放入集合的元素需要实现Comparable接口,该接口定义了比较方法,在将元素添加进集合的时候,集合内部会调用该元素的比较方法进行排序,这也是为什么该集合存null会出现空指针异常
另一种是定制排序,存放的元素不需要实现接口,而是需要给集合传一个比较器,Comparator,该接口是一个函数式接口,传两个参数,返回int,如果等于零两元素相等,小于0,前者小于后者,大于零前者大于后者
直接父类是SortedSet(继承Set接口)
特点
元素有序
支持排序
元素不可重复
不可有null元素
因为TreeSet中需要排序,所以需要比较,比较时要调用方法,当null调用方法时会发生空指针异常
常用方法
first()
取第一个元素
last()
取最后一个元素
lower()
取指定元素的前一个元素
higher()
取指定元素的后一个元素
截取自TreeSet的方法
headSet(Object)
返回小于指定元素的子集
tailSet(Object)
返回大于指定元素的子集
subSet(o1, o2)
返回在传入参数之间的子集
如果向集合插入可变对象,并且后面程序修改了该对象实例变量,这会导致其顺序发生改变,
但集合不会重新调整顺序,甚至会出现重复元素
但集合不会重新调整顺序,甚至会出现重复元素
自然排序
TreeSet会调用集合元素的compareTo(Object)方法比较元素大小进行升序排列
Comparable是一个接口,提供了比较大小的标准
如果试图把一个对象添加到TreeSet时必须实现Comparable接口并实现比较的方法
定制排序
Comparator是一个函数式接口,里面包含compara(o1, o2)方法,比较并返回整数
在创建TreeSet对象时传入一个Comparator对象,可以写匿名内部类,也可以用Lambda表达式代替
Queue
特点
序列
先进先出FIFO
队列不允许随机访问队列中的元素
API
add(Object e)
向队尾添加元素
offer(Object e)
向队尾添加元素
当使用容量有限的队列时,此方法比add更好
element()
获取队列头部元素但不删除
peek()
获取队列头部元素但不删除
poll()
获取并删除队列头部元素
remove()
获取并删除队列头部元素
Deque接口
ArrayDeque实现类
特点
底层基于Array
双端队列
允许从队列两端操作队列
API
addFirst(Object e)
addLast(Object e)
getFirst()
getLast()
removeFirst()
removeLast()
遍历
普通for循环
foreach循环(底层还是迭代器)
迭代器
先将容器中元素放入迭代器,再根据下面两个方法遍历
hasNext()判断是否还有数据
next()返回元素
就这么说吧,对于集合的三种遍历方式删除:
1、普通for循环:可以删除注意每次删除之后索引要--
2、Iterator遍历:可以删除不过要使用Iterator类中的remove方法,如果用List中的remove方法会报错
3、增强for循环foreach:不能删除强制用List中的remove方法会报错
1、普通for循环:可以删除注意每次删除之后索引要--
2、Iterator遍历:可以删除不过要使用Iterator类中的remove方法,如果用List中的remove方法会报错
3、增强for循环foreach:不能删除强制用List中的remove方法会报错
Map接口
HashMap
特点
键值对
采用哈希算法,查找非常快
key可以存null
value可以重复
无序
不支持排序
HashMap中是用链地址法来解决哈希冲突的
方法
put(T, E)
get(key)
keySet()返回所有key存入set集合
replace(key, value)
clear()
遍历
forEach
Set<Map.Entry<T,E>>
HashMap集合的元素存入后实际被包装成一个Entry对象,即键值对对象,HashMap提供了一个获得所有Entry对象并放入Set集合的方法
LinkedHashMap
LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的。
数据结构
1.7 数组+链表,头插法
1.8 数组+链表+红黑树,尾插法
1.8 数组+链表+红黑树,尾插法
扩容机制
LoadFactory 默认 0.75
创建一个空数组重新Hash
初始容量16,2的幂次
方便位运算
均匀分布
Hashtable
与HashMap的主要区别:
1、HashMap中键(key)和值(value)均可以为null,而Hashtable则不允许。原因:由JDK源码可知,HashMap中key为null时hashCode取0,value没做限制;而Hashtable中key和value为null时均会出现NullPointerException;
2、方法加了synchronized关键字,线程安全其中的对象必须实现equals和hashCode方法,java.util.Properties是其子类。
1、HashMap中键(key)和值(value)均可以为null,而Hashtable则不允许。原因:由JDK源码可知,HashMap中key为null时hashCode取0,value没做限制;而Hashtable中key和value为null时均会出现NullPointerException;
2、方法加了synchronized关键字,线程安全其中的对象必须实现equals和hashCode方法,java.util.Properties是其子类。
线程安全
key,value都不可为null
Properties子类
特点
不可写泛型
键值都是String
可以和IO结合使用,实现永久存储
API
setProperty(k, v)
getProperty(k)
stringPropertyNames()
类似于Map集合中的keySet方法
特有方法
读到集合
load(InputStream in)
load(Reader r)
写到perperties文件
store(OutputStream)
store(Write)
SortedMap接口
Map接口的有序子接口,按照键的自然顺序或指定排序规则Comparator进行排序
TreeMap
实现了SortedMap接口,底层就是红黑树算法的实现,线程不安全
特点
有序
支持排序
不可存null
查找较慢
value可以重复
采用红黑树排序
自然排序
按照元素的实际大小
定制排序
调用传Comparator类型的构造方法(在这直接传匿名内部类,并重写comparator方法)
WeakHashMap
其中的键是弱键,当它不被使用时会自动被GC给回收,同时其所在的entry节点会被删除
java.util.concurrent.ConcurrentHashMap
Collections工具类
提供了常用的集合操作方法,如排序sort等方法;同时还提供常用集合的同步实现,以适应多线程环境
查找替换操作
Collection和Collections
Collection接口是List、Set、Queue的父接口,实现了Iterable接口,提供了可以操作上述三个集合的方法。
Collections是一个操作Set、List、Map等集合的工具类
Iterator和ListIterator的区别
Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List.
Iterator对集合只能是向前遍历,ListIterator即可以前向也可以后向。
ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等
Iterator对集合只能是向前遍历,ListIterator即可以前向也可以后向。
ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等
异常处理
异常的定义及概念
异常是用来处理可能因很多原因出现的以外状况的
异常的五个关键字
try
与catch搭配使用
如果try中某一行代码发生异常,那么此后的代码将不执行
catch()
finally
如果try中有return,那么会先执行finally中的语句,最后return
不管有没有异常,这个块中的程序都会执行,除非整个程序结束
不要在此块中使用return、throw关键字,一旦使用,try块和catch块中的return和throw将失效
throws
写在方法签名处,向调用该方法的上级抛异常,声明抛出异常的类
后面跟异常类
throw
抛出一个具体的异常,是一个独立的语句,后面跟异常的一个对象
语法
try…catch、try…catch…finally、try…finally
throw、throws
Java非正常情况有两种
错误(Error)
此错误无法处理,发生的可能性小,所以不需要处理机制
发生场景
系统崩溃
内存溢出
动态连接失败
异常(Exception)
预定义异常
运行时异常:RunTimeException类的子类
该异常在编译时无需处理
不需要显示的在程序中进行try…catch处理
如:NullPointerException、IllegalArgumentException、ArrayIndexOutOfBoundsException等
受检异常CheckedException:非RuntimeException子类
必须在程序中显示进行异常捕获处理
如:IOException、SQLException、FileNotFoundException等
自定义异常
继承Exception或RuntimeException
Throwable
Error
AWTError
IOError
LinkageError
ThreadDeath
Exception
RuntimeException
NullPointerException
IndexOutOfBoundsException
StringIndexOutOfBoundsException
ArraysIndexOfBoundsException
ClassCastException
IllegalArgumentException
ArithmeticException
NumberFormatException
IOException
SQLException
处理异常的方式
try-catch-finally
异常处理可以嵌套,但会降低执行效率不建议使用
try块catch块遇到return、throw都会结束,然后直接奔向finally
Java7新增多异常捕获
捕获多异常时,异常变量有final隐式修饰
throws
只能在方法签名中使用
后面跟异常类
可以抛出多个异常类,用“,”隔开
一旦是使用了抛出异常,就不能继续捕获异常,只能由调用者捕获或者继续上抛
throw自行抛出异常
直接抛出一个异常的实例,可以当作独立语句使用
在catch块中结合throw使用
所有异常类的通用方法
getMessage()
获取异常详细信息的字符串,包括发送异常的原因和位置
System.out.print(e.getMessage())
printStackTrace()
打印异常错误和位置以及异常跟踪栈信息
getStackTrace()
返回跟踪异常栈信息
自定义异常
继承异常类,然后根据异常的处理方式抛出异常
Java7易忽略的新特性
try-with-resources语句:简化资源的关闭操作,会自动在语句结束后将每个资源正确关闭。注:该资源类必须要直接或间接实现java.lang.AutoCloseable接口,该接口只包含一个close方法
switch语句支持String类型
单个catch捕获多个异常,如 catch(IOException | SQLException | FileNotFoundException ex)
Javadoc标签
@author :标识一个类的作者,一般用于类注释
@deprecated :指明一个过期的类或成员,表明该类或方法不建议使用
{@docRoot} :指明当前文档根目录的路径
@exception :可能抛出异常的说明,一般用于方法注释
{@inheritDoc} :从直接父类继承的注释
{@link} : 插入一个到另一个主题的链接
{@linkplain} :插入一个到另一个主题的链接,但是该链接显示纯文本字体
@param :说明一个方法的参数,一般用于方法注释
@return :说明返回值类型,一般用于方法注释,不能出现再构造方法中
@see :指定一个到另一个主题的链接
@serial :说明一个序列化属性
@serialData :说明通过writeObject() 和 writeExternal() 方法写的数据
@serialField :说明一个ObjectStreamField 组件
@since :说明从哪个版本起开始有了这个函数
@throws :和 @exception 标签一样
{@value} : 显示常量的值,该常量必须是static属性。
@version : 指定类的版本,一般用于类注释
Java EE
JavaEE基础
Servlet
生命周期
init(ServletConfig config)方法,在Servlet初始化时被调用
service(ServletRequest request,ServletResponse response)方法,处理客户端请求
destory()方法,在Servlet销毁时被调用
配置
web.xml配置servlet和servlet-mapping
@WebServlet注解
ServletConfig
代表当前Servlet
获取Servlet初始化参数init-param
ServletContext
代表当前web应用
获取web应用初始化参数context-param
整个web应用数据共享
ServletRequest
代表客户端请求
请求转发forward,转发前后是同一个请求
ServletResponse
代表服务端响应
请求重定向redirect,前后是两个不同的请求
JSP
九大内置对象
pageContext:PageContext类型,页面上下文对象;
request:ServletRequest类型,表示HTTP请求;
response:ServletResponse类型,表示HTTP响应;
session:HttpSession类型,表示当前会话;
application:ServletContext类型,表示当前Web应用;
exception:Throwable类型;
out:JspWriter类型,JSP页面输出流;
page:Object类型,页面对象;
config:ServletConfig对象,表示当前Servlet。
request:ServletRequest类型,表示HTTP请求;
response:ServletResponse类型,表示HTTP响应;
session:HttpSession类型,表示当前会话;
application:ServletContext类型,表示当前Web应用;
exception:Throwable类型;
out:JspWriter类型,JSP页面输出流;
page:Object类型,页面对象;
config:ServletConfig对象,表示当前Servlet。
四大作用域
page:表示页面范围
request:表示请求范围
session:表示当前会话范围
application:表示当前Web应用范围
request:表示请求范围
session:表示当前会话范围
application:表示当前Web应用范围
JSTL
自定义标签
1、继承javax.servlet.jsp.tagext.SimpleTagSupport类,并重写doTag方法;
2、在项目WEB-INF目录下创建tld文件(其中描述了标签的语法,如:标签有哪些属性,标签的属性是否支持表达式等内容)
2、在项目WEB-INF目录下创建tld文件(其中描述了标签的语法,如:标签有哪些属性,标签的属性是否支持表达式等内容)
EL表达式
监听器Listener
分类
ServletRequestListener
ServletRequestAttributeListener
HttpSessionListener
HTTPSessionAttributeListener
ServletContextListener
ServletContextAttributeListener
配置
web.xml配置listener
@WebListener注解
过滤器Filter
生命周期
init()
初始化,由Servlet容器(如tomcat)创建
doFilter()
处理请求过滤
destroy()
销毁,由servlet容器完成
配置
web.xml配置filter和filter-mapping
@WebFilter注解
Cookie
为了弥补HTTP协议无状态的不足而引入的机制。由服务端创建,但由客户端(浏览器)保存。
应用:客户端记住密码
Session
由服务端创建,并保存到服务端
应用:用户登录验证
四种会话跟踪技术:1、URL重写:将会话ID写到URL之后,服务端通过会话ID识别不同用户;2、隐藏表单域:将会话ID放到表单的隐藏域中,随着表单提交到服务端;3、Cookie:第一次请求时服务器主动发一小段信息给浏览器(即Cookie),下次请求时浏览器自动附带该信息发送给服务器,服务器读取Cookie识别用户;4、Session:服务器为每个用户创建一个Session对象保存到内存,并生成一个sessionID放入Cookie发送给浏览器,下次访问时sessionID会随Cookie传回来,服务器再根据sessionID找到对应Session对象。
URL编码
网址路径编码:UTF-8,如xxx.com/title/编码
查询字符串:操作系统默认编码,win7是GBK
GET和POST方法的编码:网页的编码
Ajax调用中的编码:IE总是采用操作系统的默认编码,而Firefox总是采用UTF-8编码
XML
XML基础语法
文档声明
约束
DTD约束
Schema约束
XML解析
DOM
JDOM
Dom4J
SAX
WebSocket
基于TCP,全双工通信协议
@OnOpen,@OnMessage,@OnClose,@OnError关键注解
消息服务 JMS
API
Message
消息是消息服务器在客户端之间发送的一条条信息。
消息类型
StreamMessage:Java原始值的数据流对象;
MapMessage:一套名称-值对;
TextMessage:一个字符串对象;
ObjectMessage:一个序列化的 Java对象;
BytesMessage:一个字节数据流。
MapMessage:一套名称-值对;
TextMessage:一个字符串对象;
ObjectMessage:一个序列化的 Java对象;
BytesMessage:一个字节数据流。
ConnectionFactory
用于创建Connection对象的工厂,通常通过JNDI获取
Connection
连接对象是和JMS提供者通信的媒介
Destination
目标是受控对象。在JMS中表示一个队列或者一个主题
点对点模型:Queue子接口
发布/订阅模型:Topic子接口
Session
用于创建消息的生产者、消费者和消息
MessageProducer
消息生产者,也叫做消息发送者
TopicPublisher子接口
MessageConsumer
消息消费者,也叫做消息接受者
TopicSubscriber子接口
开发步骤
1)用JNDI得到ConnectionFactory对象;2)用ConnectionFactory创建Connection对象;3)用Connection对象创建一个或多个JMS Session;4)用JNDI得到目标队列或主题对象,即Destination对象;5)用Session和Destination 创建MessageProducer和MessageConsumer;6)通知Connection 开始传递消息。
两种消息传递方式
PERSISTENT:持久化消息,将使用暂存后再转送的机理投递。
NON_PERSITENT:非持久化消息,最多只能被投递一次。(默认)
NON_PERSITENT:非持久化消息,最多只能被投递一次。(默认)
分类
点对点模型(P2P)
消息队列Queue
消息生产者(发送者)MessageProducer
消息消费者(接收者)MessageConsumer
同步、异步(通过监听器MessageListener实现)
发布订阅模型(Pub/Sub)
主题Topic
主题发布者TopicPublisher
主题订阅者TopicSubscriber
框架
ActiveMQ
由Apache开发,实现了JMS规范,包括点对点模型和发布/订阅模型
RocketMQ
RabbitMQ
KafKa
命名服务 JNDI
Java Naming Directory Interface
事务API JTA
Java Transaction API
用于处理分布式事务
持久化API JPA
Java Persistence API
邮件服务
JavaMail
Spring JavaMailSender
服务器中间件
Web服务器
Nginx
简介
高性能http和反向代理服务器
并发能力强
高达50000个并发
热部署
7*24不间断软件升级
核心配置文件nginx.conf
1、全局块
worker_processes 1;
nginx并发处理值
2、event块
events {
worker_connections 1024;
}
worker_connections 1024;
}
nginx支持的最大连接数
3、http块
http块
全局块配置的指令包含文件引入、MIME-TYPE定义、日志自定义、连接超时时间、单链接请求数上限等
server块
与虚拟主机相关
server块
location块
常用命令
nginx -v:查看版本
nginx:启动nginx
nginx -s stop:停止nginx
nginx -s reload:重新加载nginx.conf配置文件,使修改生效
主要用途
动静分离
Nginx处理静态资源的能力很强,效率也很高
支持静态资源缓存,如图片、js、css等
正向代理
内网通过代理服务器访问外网,如vpn
例子:你要访问谷歌
你就需要一个VPN,所谓的VPN 就是让你先到达代理服务器,这个代理服务器是可以访问谷歌的,这个过程叫正向代理
你是A,谷歌是C, A ≠ C
A => B,B => C
A => B => C
B为代理服务器
反向代理
外网通过代理服务器访问外网,可以保证内网安全性
例子:你访问百度
1、百度为了支持高并发,高可靠,所以把搜索引擎部署了100台。
2、但是为了确保用户不用访问不同的IP,而统一访问www.baidu.com
3、需要设定一个服务器统一接受来自www.baidu.com的请求,而请求之后再分发给具体的服务器
4、该服务器为反向代理服务器
负载均衡
由于Nginx扛并发能力强,为了减轻Tomcat服务器承受的压力,通常用作Tomcat服务器的负载均衡器
upstream xxx {
server ip:端口;
server ip:端口
}
server ip:端口;
server ip:端口
}
策略
轮询(默认)
权重 weight
ip_hash
解决session问题
least_connection
url_hash
fair
根据响应时间分配
可定制化
可以通过编写Lua脚本进行功能扩展
Apache
应用服务器
Tomcat、Jetty
Servlet容器
底层原理:Socket通信(BIO/NIO)
JBoss、Weblogic、Websphere
开发框架
Spring
ContextLoaderListener监听器
是整个Spring应用启动的关键
Spring启动过程大致如下:
1、在Servlet容器启动后,会创建一个ServletContext(整个Web应用的上下文);
2、由于ContextLoaderListener实现了ServletContextListener,因此会在ServletContext创建完成后,其中的ContextInitialized方法会自动被调用;ContextInitialized方法中将会通过ServletContext实例的getParameter()方法找到Spring配置文件位置,然后根据其中的内容为Spring创建一个根上下文(WebApplicationContext,即通常所说的IOC容器);
3、将WebApplicationContext作为ServletContext的一个属性放进去,名称是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
1、在Servlet容器启动后,会创建一个ServletContext(整个Web应用的上下文);
2、由于ContextLoaderListener实现了ServletContextListener,因此会在ServletContext创建完成后,其中的ContextInitialized方法会自动被调用;ContextInitialized方法中将会通过ServletContext实例的getParameter()方法找到Spring配置文件位置,然后根据其中的内容为Spring创建一个根上下文(WebApplicationContext,即通常所说的IOC容器);
3、将WebApplicationContext作为ServletContext的一个属性放进去,名称是WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE
IOC
WebApplicationContext:即Spring IOC容器,由容器创建和管理Bean,使用时直接从容器中获取
配置方式
XML配置文件
@Resource/@Autowired注解配置
Bean的作用域
在Spring4中有以下几个作用域(见ConfigurableBeanFactory和WebApplicationContext接口源码)
1)singleton:默认的作用域,仅为每个Bean对象创建一个实例。
2)prototype:可以根据需要为每个Bean对象创建多个实例。
3)request:为每个HTTP请求创建它自有的一个Bean实例,仅在Web相关的ApplicationContext中生效。
4)session:为每个HTTP会话创建一个实例,仅在Web相关的ApplicationContext中生效。
5)global session:为每个全局的HTTP会话创建一个实例。一般仅在porlet上下文中使用生效。同时仅在Web相关的ApplicationContext中生效。
6)application:为每个ServletContext创建一个实例。仅在Web相关的ApplicationContext中生效。
1)singleton:默认的作用域,仅为每个Bean对象创建一个实例。
2)prototype:可以根据需要为每个Bean对象创建多个实例。
3)request:为每个HTTP请求创建它自有的一个Bean实例,仅在Web相关的ApplicationContext中生效。
4)session:为每个HTTP会话创建一个实例,仅在Web相关的ApplicationContext中生效。
5)global session:为每个全局的HTTP会话创建一个实例。一般仅在porlet上下文中使用生效。同时仅在Web相关的ApplicationContext中生效。
6)application:为每个ServletContext创建一个实例。仅在Web相关的ApplicationContext中生效。
Bean的生命周期
过程
扫描类
invokeBeanFactoryPostProcessors
封装beanDefinition对象 各种信息
放到map
放到map
验证
能不能实例化 需要实例化么 根据信息来
是否单例等等
判断是不是factory bean
单例池 只是一个ConcurrentHashMap而已
正在创建的 容器
得到 class
推断构造方法
根据注入模型
默认
得到构造方法
反射 实例化这个对象
后置处理器合并beanDefinition
判断是否允许 循环依赖
提前暴露bean工厂对象
填充属性
自动注入
执行部分 aware 接口
继续执行部分 aware 接口 生命周期回调方法
完成代理AOP
beanProstprocessor 的前置方法
实例化为bean
放到单例池
销毁
依赖注入的几种方法
构造注入
属性注入setter
接口注入
循环依赖
情况
属性注入可以破解
构造器不行
三级缓存没自己 因二级之后去加载B了
三级缓存
去单例池拿
判断是不是正在被创建的
判断是否 支持循环依赖
二级缓存 放到 三级缓存
干掉二级缓存
GC
下次再来直接 三级缓存拿 缓存
缓存 存放
一级缓存 存放已经完全创建好的单例 bean -》 singletonObjects
二级缓存 存放早期的 bean -》 earlySingletonObjects
三级缓存 存放单例 bean 的工厂 -》 singletonFactories
FactoryBean与BeanFactory
AOP
动态代理
JDK 动态代理(针对接口,代理类为其兄弟类)
目标对象实现了若干接口
java反射机制生成一个代理接口的匿名类
调用具体方法的时候调用invokeHandler
CGLIB 动态代理(针对类,代理类为其子类)
目标对象没有实现接口
asm字节码编辑技术动态创建类 基于classLoad装载
修改字节码生成子类去处理
静态代理
实现类
拦截器
事务管理
五大事务隔离级别
七大事务传播特性
事务管理器
核心接口是PlatformTransactionManager
org.springframework.jdbc.datasource.DataSourceTransactionManager:主要用于jdbc和mybatis数据源
org.springframework.orm.hibernate3.HibernateTransactionManager:主要用于Hibernate数据源
编程式事务
通过使用TransactionTemplate 或者 PlatformTransactionManager相关事务API来实现事务管理
声明式事务
XML配置标签
@Transactional注解
异常回滚
只会回滚RuntimeException异常
定时任务调度Spring Task
XML配置标签
@Scheduled注解配置
异步任务
XML配置标签
@Async注解配置
缓存支持Spring Cache
Spring 5 新特性
兼容 Java9
最低要求Java 8,因为使用了Java 8的一些新特性
响应式编程 WebFlux
即Spring-WebFlux模块,以 Reactor 库为基础,包含了对响应式 HTTP、服务器推送事件(Server-Sent Event)和WebSocket 的客户端和服务器的支持。
基于Java注解编程模型
使用方式与Spring MVC基本一样,只是使用的类型不是普通的对象,而是响应式编程中的Mono、Flux对象
Mono对象
表示单个对象,如User,用法与Optional类似
Flux对象
表示一系列的对象,类似于List
基于函数式编程模型
服务器端
HandlerFunction函数式接口
Mono handler(ServerRequest request)方法用于处理客户端请求
RouterFunction 路由接口
Mono > route(ServerRequest request) 方法用于选择处理对应请求的HandlerFunction对象并返回
只需要使用RouterFunctions.route 方法创建 RouterFunction 类型的 bean,就会被自动注册来处理请求并调用相应的 HandlerFunction
客户端
使用 WebClient.create 方法创建客户端发起HTTP请求调用REST API和 SSE (服务端推送) 服务
使用 WebSocketClient 类的API 访问 WebSocket
测试
使用 WebTestClient 类进行测试
Spring Boot
用于快速构建及开发Spring应用,可以看成是Spring框架的简化版
“约定优于配置”思想
使用约定的默认配置,减少配置文件编写
配置文件
properties文件
application.properties
yml文件
application.yml
基于注解配置
Spring原有的@Controller、@Service、@Component、@Bean、@Configuration等注解
properties配置文件读取
Spring原有的@Value
与@PropertySource配合使用读取指定配置属性值
缺点:1、只支持单个属性值读取;2、只支持简单数据类型,如String、Boolean及数值类型
Spring Boot新增的@ConfigurationProperties
可以指定配置属性前缀,自动绑定属性值
比@Value功能更强大。1、支持实体属性自动封装;2、支持复杂数据类型的解析,比如数组、列表List
starter简化Maven配置
预先定义好需要的依赖并打包,需要时直接引入即可
所有Spring Boot项目公共的父依赖
spring-boot-starter-parent模块
自动配置AutoConfigurations
为项目添加默认配置
application.properties/application.yml文件中定义的配置会覆盖默认配置
自带的spring-boot-autoconfigure模块
内置Servlet容器
Tomcat、Jetty、Undertow等
Spring Cloud
Eureka注册中心
Ribbon集成REST实现负载均衡
OpenFeign声明式服务调用
Hystrix实现服务限流熔断降级和数据监控
Zuul实现微服务网关
Config分布式统一配置中心
Sleuth分布式链路跟踪
Bus消息总线
基于Hystrix实现接口降级
ORM 框架
Hibernate
HQL
可以看成是面向对象的SQL,它将原生SQL中表名和列名分别用全类名和属性名替换了
对象的三种状态
transient(瞬时状态),persistent(持久化状态)以及detached(离线状态)
主要组成
Session:提供用户对数据库操作的API
SessionFactory:创建Session对象的工厂
Query:负责执行数据库查询操作,支持SQL、HQL两种方式
缓存机制
一级缓存
二级缓存
Criteria(QBC)
多表映射
注解
JPA 提供的注解
javax.persistence包下:@Id,@Column,@Entity,@Table,@OneToMany,@ManyToOne等
Hibernate增加的注解
数据库方言Dialect
它是Hibernate数据库可移植性强的关键所在,不同的数据库使用不用的方言类进行处理,通常需要我们自己指定。
比如:Oracle10gDialect(Oracle数据库方言)、MySQL5Dialect(MySQL数据库方言)等
比如:Oracle10gDialect(Oracle数据库方言)、MySQL5Dialect(MySQL数据库方言)等
在方言类中包含了对不同类型数据库差异的处理,比如分页、常用函数的语法
HibernateTemplate
Spring对Hibernate的集成和封装,使用它可以很方便的进行数据库操作
HibernateTemplate的作用是保证session能够正确的打开和关闭,避免手工管理session带来的问题。
使用 HibernateTemplate 时必须进行事务管理,否则将会报错
Mybatis
主要组成
Configuration Mybatis配置信息
配置方式
XML文件
注解
SqlSession 提供用户对数据库操作的API,完成增删改查
Executor 由SqlSession调用执行数据库操作
StatementHandler 对SQL语句进行操作
ParameterHandler将用户传递的参数转换成JDBC Statement 所需要的参数
ResultSetHandler 将JDBC返回的ResultSet结果集对象转换成List集合
TypeHandler 负责java数据类型和jdbc数据类型之间的映射和转换
动态SQL
通过标签的形式大大的减少了条件查询时拼接SQL的难度,提高了SQL的准确率
常用标签
if、where、foreach等
结果映射
resultMap
数据类型转换
插件机制
Interceptor接口
分页插件
缓存机制
一级缓存:Session级别的缓存,Executor对象会维护一个Cache缓存,默认开启
二级缓存:Application级别的缓存,可以看作是作用域整个应用的全局缓存。一般通过自定义缓存Redis、Memcached等实现
MVC 框架
Struts2
核心过滤器StrutsPrepareAndExecuteFilter
PrepareOperations
包括setEncodingAndLocale、createActionContext、findActionMapping等重要操作
ExecuteOperations
包括executeStaticResourceRequest、executeAction操作
ActionMapping
包含Action的基本信息,名称、命名空间、方法名、请求参数以及返回结果Result等信息
拦截器Interceptor
intercept(ActionInvocation invocation)方法用于在调用ActionInvocation.invoke方法前后执行其它操作
控制器Action
由ActionInvocation.invoke方法负责调用执行
值栈ValueStack
模型驱动ModelDriven
1、Action实现ModelDriven接口;2、在Action中定义实体类属性,并通过getModel方法返回
OGNL(Object-Graph Navigation Language)
OgnlValueStack类
其中的数据分成了两部分:1、root(栈结构,CompoundRoot,继承于ArrayList);2、context(map形式,OgnlContext)
OGNL表达式:#相当于调用ActionContext.getContext()方法、%用于、$引用OGNL表达式
ActionContext中的属性(和四大域对象类似):①parameters请求参数;②request请求对象;③session对象;④application对象;⑤attr依次按照request->session->application范围查找属性,与pageContext.findAttribute()类似
struts2标签库
struts2标签统一使用s作为标签前缀
分类
内置标签
自定义标签
国际化
文件上传
数据验证
Action中的input、validate方法
请求参数类型转换TypeConverter
Spring MVC
基本组成
DispatcherServlet
找到对应请求的HandlerMapping,将请求转发给对应的HandlerAdapter
处理器映射器HandlerMapping
保存请求的URL与Handler(可以是Controller或Servlet等)的对应关系
处理器适配器HandlerAdapter
调用对应的Handler进行处理,并返回ModelAndView对象给DispatcherServlet
控制器Controller
拦截器HandlerInterceptor
preHandle、postHandle、afterCompletion方法
HandlerExecutionChain
负责Handler执行前后的HandlerInterceptor的调用
模型视图ModelAndView、模型Model/ModelMap
视图解析器ViewResolver
将逻辑视图转换成物理视图
请求参数解析和封装
RequestMappingHandlerAdapter
HandlerMethodArgumentResolver接口
HandlerMethodArgumentResolverComposite类默认定义了26个不同的参数解析器
ServletModelAttributeMethodProcessor 两种情况:①使用功能@ModelAttribute注解的类型;②自定义实体POJO:通过特定的DataBinder将请求参数绑定到为实体中的属性上;
其他类型的参数处理:如Map、ServletRequest、ServletResponse、Model等使用内置转换器自动转换
类型转换
Converter接口
自定义类型转换器:实现Converter接口,并重写convert方法
ConversionService接口
方法返回值处理
HandlerMethodReturnValueHandler接口
文件上传
配置CommonsMultipartResolver文件上传解析器
MultipartFile对象作为方法参数接收
全局异常处理
实现HandlerExceptionResolver接口
使用@ControllerAdvice/@RestControllerAdvice注解
Spring + Struts + Hibernate 已停止维护
日志框架
作用
用作Java应用日志记录,通常保存到文件中,方便调试跟踪系统运行情况及排查问题
分类
日志门面
Apache的commons-logging
Spring等框架依赖其做日志记录
slf4j
slf4j-api-xxx.jar
jboss-logging
Hibernate依赖其做日志记录
桥接器(适配器)
slf4j-log4j:slf4j适配log4j
slf4j-logback:slf4j适配logback
slf4j-jdk14:slf4j适配JDK提供的日志框架(JUL)
具体实现
log4j
log4j2
logback
JUL(java.util.logging)
安全框架
Shiro
主要功能
权限控制
身份认证(登陆)Authentication
权限验证(授权)Authorization
会话管理
数据加密
常用的加密算法
API
当前用户(不一定是人,比如爬虫程序)Subject
安全管理器SecurityManager,shiro的核心
SecurityUtils工具类
Realm,域,从中获取用户的角色、权限信息进行身份认证
Spring Security
定时任务框架
Quartz
Spring Task
工作流引擎
JBPM(Java Business Process Management)
Activiti
模板引擎
freemarker、velocity、thymeleaf、beetl(国产)
全文搜索框架
Apache Lucene
主要功能
创建及维护索引,提供全文检索服务。支持结果排序及关键字高亮
主要组成
索引保存目录Directory
FSDirectory:索引存储在磁盘
RAMDirectory:索引存储在内存
索引文档Document
Field:StringField只索引不分词,TextField即索引又分词
分词器Analyzer
对于索引内容进行分词
常用分词器
简单分词器SimpleAnalyzer
标准分词器StandardAnalyzer
中文分词器
SmartChineseAnalyzer
IKAnalyzer
庖丁分词器PaodingAnalyzer
索引管理器IndexWriter
负责索引文档的创建、更新、删除
查询分析器QueryParser
构造搜索条件并分析
索引阅读器IndexReader
索引搜索器IndexSearcher
根据搜索条件返回匹配的结果
Compass
基于Lucene,ElasticSearch的前身
提供了Spring、Hibernate框架集成
ElasticSearch
基于Lucene,分布式的,适用于实时、大数据量的搜索场景
Apache Solr
基于Lucene,适用于常规搜索场景
利用Zookeeper进行分布式管理
Hibernate Search
集成了Hibernate、Lucene和Elasticsearch
网络编程框架
Http客户端
Apache HttpClient
OkHttp
网络IO框架
Netty
Mina
Hibernate-Validator 参数校验框架
Bean Validation规范的实现
项目构建工具
Maven
坐标
groupId、artifactId、version
仓库
依赖配置
引入依赖:dependencies、dependency节点
排除依赖:exclusions、exclusion节点
聚合与继承,分别是modules、parent节点
生命周期和命令
mvn clean、mvn test、mvn package、mvn install
Archetype
创建Maven项目基本骨架
自定义Archetype
Maven镜像
阿里云公有镜像
Maven私服
Nexus私服配置
Maven插件
Maven功能的扩展
自定义Maven插件
继承AbstractMojo类
Ant/Gradle
版本控制工具
SVN
Git
CI持续集成工具
jenkins
常用工具
Google Guava
Optional类
避免空指针
MoreObjects工具类
作为java.utils.Objects类的扩展
字符串操作,如split、join等操作
Spliter、Joiner类
函数式编程
Apache Commons
commons-beanutils包
用于处理JavaBean相关操作,最常见的就是属性复制
如 BeanUtils.copyProperties()、ProperUtils.copyProperties()
commons-lang包
如:StringUtils
commons-io包
简化IO操作
如:IOUtils
commons-collections包
简化集合操作
如:CollectionUtils
commons-fileupload包
处理文件上传相关操作
Spring 中的工具类
StringUtils
字符串操作
WebUtils
处理Web相关操作
FileCopyUtils(文件复制)、ResourceUtils(读取文件)等
ObjectUtils
ReflectionUtils
简化反射操作
其它常用工具
lombok
通过注解简化Java代码编写,使代码看起来更简洁。可以自动生成类的getter、setter、toString、hashCode、equals、构造器等
常用注解
@Getter、@Setter
为属性自动生成getter、setter方法
@NoArgsConstructor
生成无参构造器
@AllArgsConstructor
生成包含所有属性的构造器
@Data
生成getter、setter、hashcode、equals、toString方法
其它功能注解
@Slf4j 注入 log 日志对象
@NonNull 非空检查
Swagger
可以与Spring MVC集成为项目生成RESTful API文档,并且可以直接在页面测试
JVM
运行时数据区(JVM内存模型)
数据
堆
这是被所有线程共享的一块内存区域,其中存放的是对象实例本身以及数组(数组的引用在栈中)。
划分
年轻代(Young Generation)
年轻代用来存放新创建的Java对象。对年轻代的垃圾回收称为“Minor GC”,采用的是复制清除算法、并行收集器。为使JVM更好的管理堆内存中对象的分配及回收,年轻代又被分为三个区域:Eden、From Survivor、To Survivor。注意:年轻代可用内存空间是Eden区+一个Survivor区,另一个Survivor区则保持空闲状态,其中Eden区与一个Survivor区大小比例可以通过 -XX:SurvivorRatio参数进行设置,默认为8,表示Eden区与一个Survivor区大小比值是8:1.
老年代(Tenured Generation)
年轻代中经过多次垃圾回收没有回收掉的对象将被Copy到老年代,因此可以认为老年代中存放的都是生命周期较长的对象。对老年代中对象的垃圾回收称为“Full GC”,采用的是标记-清除算法。
永久代(Permanent Generation)
简称Perm Gen,位于方法区。用于存放Class、Interface的元数据,其大小跟项目的规模、类、方法的量有关。永久代的对象垃圾回收发生在Full GC过程中。
注:Java 8 已经去掉了永久代,用 MetaSpace 予以替代。
注:1)其中年轻代和老年代位于堆内存,堆内存会从JVM启动参数(如-Xmx:3G表示最大堆内存为3G)指定的内存中分配;2)Perm Gen不位于堆内存中,而是属于方法区,由虚拟机直接分配,但可以通过-XX:PermSize -XX:MaxPermSize 等参数调整其大小。
方法区
用于存储已经被虚拟机加载的类、常量、静态变量、编译器编译后的字节码等数据信息。在方法区中还包含有运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。当然并非Class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。
需要注意的是,虽然方法区逻辑上属于堆内存,但是在JVM规范中并没有强制要求对该区域进行垃圾回收。
运行时常量池
属于方法区。用于存储数值型常量。
指令
程序计数器 Program Counter
也称作PC寄存器。它跟汇编语言中的程序计数器的功能在逻辑上是等同的,用来标识执行的是哪条指令。每个线程都有自己独立的程序计数器,并且相互之间是独立的。
在JVM规范中规定:1、如果线程执行的是非native方法,则程序计数器中保存的是当前需要执行的指令的地址;2、如果线程执行的是native方法,则程序计数器中的值是undefined。
虚拟机栈
其中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法,在栈帧中包括局部变量表(Local Variables)、操作数栈(Operand Stack)、指向当前方法所属的类的运行时常量池(运行时常量池的概念在方法区部分会谈到)的引用(Reference to runtime constant pool)以及方法返回地址(Return Address)
本地方法栈
存放native方法信息,也就是由C/C++实现的方法
类加载机制
加载过程
包括以下几个步骤:①加载:类加载器将类的.class文件读取到内存,并为之创建java.lang.Class对象;②链接:把类的二进制数据合并到JRE中;③初始化:JVM对类的静态变量、静态代码块执行初始化操作。
加载
生成一个class对象
验证
文件格式验证
元数据验证
字节码验证
符号引用验证
准备
默认值
static会分配内存
解析
解析具体类的信息
引用等
初始化
父类没初始化 先初始化父类
使用
卸载
加载方式
main()
class.forName
ClassLoader.loadClass
类加载器
BootstrapClassLoader
启动类加载器:负责加载java基础类,主要是 %JAVA_HOME/jre/lib/rt.jar中的类。它是用C++语言写的。由JVM启动,然后初始化sun.misc.Launcher,sun.misc.Launcher初始化Extension ClassLoader、App ClassLoader。
ExtensionClassLoader
扩展类加载器:主要负责加载%JAVA_HOME%/jre/lib/ext/*.jar中的类
AppClassLoader
应用程序类加载器:主要负责加载应用中classpath目录下的类。
自定义ClassLoader
自定义ClassLoader需要继承ClassLoader抽象类,重写findClass方法,这个方法定义了ClassLoader查找class的方式。
双亲委派模型
当加载一个类的时候会先委托给父类加载器去加载,当父类加载器无法加载的时候再尝试自己去加载,因此类的加载顺序是“自上而下”的。采用这种方式的好处:
1、主要是保证了安全性,避免用户自己编写的类动态替换Java的一些核心类,比如java.lang.String;
2、避免了类的重复加载,因为在JVM中只有类名和加载类的ClassLoader都一样才认为是同一个类(即使是相同的class文件被不同的ClassLoader加载也被认为是不同的类)
1、主要是保证了安全性,避免用户自己编写的类动态替换Java的一些核心类,比如java.lang.String;
2、避免了类的重复加载,因为在JVM中只有类名和加载类的ClassLoader都一样才认为是同一个类(即使是相同的class文件被不同的ClassLoader加载也被认为是不同的类)
由于双亲委托机制不是万能的,在某些情况下无法使用,因此可以通过重写类加载器的loadClass方法类避免双亲委托机制。
分代回收
年轻代
Eden/s1/s2
老年代
永久代/元空间
晋升机制
根据存活时间
GC垃圾回收策略
垃圾回收的目标区域
堆内存
方法区
主要包括对废弃的常量和无用的类进行回收
垃圾判断方法
引用计数法
每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时表示可以回收。
优缺点:此方法简单,但无法解决对象相互循环引用的问题。因此Java虚拟机未采用该种方法
可达性分析法
从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。即为不可达对象,所以会被判定为是 可以回收的对象。
在Java中, GC Roots包括:
* 虚拟机栈(栈帧中的局部变量表)中引用的对象
* 方法区中类静态属性引用的对象
* 方法区中常量引用的对象
* 本地方法栈中JNI(即native方法)引用的对象
* 活跃线程的引用对象
* 虚拟机栈(栈帧中的局部变量表)中引用的对象
* 方法区中类静态属性引用的对象
* 方法区中常量引用的对象
* 本地方法栈中JNI(即native方法)引用的对象
* 活跃线程的引用对象
逃逸分析
垃圾回收算法
标记-清除算法
适用场景
对象存活比较多的时候适用
老年代
缺点
提前GC
碎片空间
扫描了两次
标记存活对象
清除没有标记的对象
复制算法
适合场景
存活对象少 比较高效
扫描了整个空间(标记存活对象并复制异动)
适合年轻代
缺点
需要空闲空间
需要复制移动对象
标记-整理算法
分代收集
指的是针对不同分代的内存区域,采用不同的垃圾回收算法
年轻代一般采用复制算法,老年代则一般采用标记-整理算法
垃圾收集器
Serial收集器
ParNew收集器
Parallel收集器
Parallel Old收集器
CMS收集器
分代
年轻
edan
s1
s2
minor gc
通过阈值晋升
老年
major gc 等价于 full gc
永久
缺点
对cpu资源敏感
无法处理浮动垃圾
基于标记清除算法 大量空间碎片
G1收集器
分区概念 弱化分代
标记整理算法 不会产生空间碎片 分配大对象不会提前full gc
可以设置预设停顿时间
充分利用cpu 多核条件下 缩短stw
收集步骤
初始标记 stw 从gc root 开始直接可达的对象
并发标记 gc root 对对象进行可达性分析 找出存活对象
可达性分析算法
最终标记
筛选回收
根据用户期待的gc停顿时间指定回收计划
回收模式
young gc
回收所有的eden s区
复制一些存活对象到old区s区
mixed gc
GC模式
区别
g1分区域 每个区域是有老年代概念的 但是收集器以整个区域为单位收集
g1回收后马上合并空闲内存 cms 在stw的时候做
内存区域设置
XX:G1HeapRegionSize
复制成活对象到一个区域 暂停所有线程
JVM调优
OOM
内存泄露
help dump
生产机 dump
mat
jmap
-helpdump
线程死锁
锁争用
Java进程消耗CPU过高
CPU100%
topc -c
top -Hp pid
jstack
进制转换
cat
full gc
老年代写满
system.gc
持久代空间不足
FullGC 内存泄露排查
jvisualvm
dump
监控配置 自动dump
实战
设置堆的最大最小值 -xms -xmx
调整老年和年轻代的比例
-XX:newSize设置绝对大小
防止年轻代堆收缩:老年代同理
主要看是否存在更多持久对象和临时对象
观察一段时间 看峰值老年代如何 不影响gc就加大年轻代
配置好的机器可以用 并发收集算法
每个线程默认会开启1M的堆栈 存放栈帧 调用参数 局部变量 太大了 500k够了
原则 就是减少gc stw
JVM性能检测工具
Jconsole
Jprofiler
jvisualvm
MAT
接口开发
RMI
主要组成
Naming类
LocateRegistry类
Remote接口:代表远程对象
UnicastRemoteObject类
使用步骤(HelloWorld程序): 1、声明远程接口(如IHelloService),并继承Remote接口;2、在远程接口中声明需要远程调用的方法,注:必须声明抛出RemoteException异常!3、编写远程对象接口的实现类(如HelloServiceImpl),必须继承UnicastRemoteObject类;4、编写服务端程序(即被远程调用的一方):① 使用LocateRegistry.createRegistry(port);绑定端口② 使用Naming.bind()方法将HelloServiceImpl对象进行绑定,如Naming.bind(\'rmi://localhost:8888/HelloService\', new HelloServiceImpl());5、编写客户端程序(调用方):① 使用Naming.lookup()方法根据服务端绑定的地址获取远程对象如IHelloService helloService = (IHelloService) Naming.lookup(\'rmi://localhost:8888/HelloService\');② 调用helloService对象的方法
RPC
即Remote Procedure Call,远程过程调用。客户机通过网络实现对服务器上的方法进行调用。
dubbo、grpc
Web Service
SOAP协议
Simple Object Access Protocol(简单对象访问协议),它是一种轻量的、简单的、基于XML和HTTP的Web数据交换协议。 它通过XML 来实现消息描述,然后再通过 HTTP 协议实现消息传输。
WSDL
Web Service Description Language(Web服务描述语言)。就是基于XML,用于描述Web 服务及其函数、参数和返回值的语言。
CXF框架
RESTful
即表述性状态传递(Representational State Transfer,简称REST),它是一种软件架构风格,可以完全使用HTTP协议实现。 适用于完全无状态的CRUD(Create、Retrieve、Update、Delete,即数据的增删改查)操作
对资源的操作有获取、创建、修改和删除,与HTTP协议提供的GET、POST、PUT、DELTE方法相对应
通过Spring MVC来实现
org.springframework.web.filter.HiddenHttpMethodFilter 过滤器 (由于浏览器form表单只支持GET与POST请求,而DELETE、PUT等method并不支持,此过滤器就可以将其转换成标准的HTTP方法,使得支持PUT、DELETE等请求)
统一异常处理
@ExceptionHandler注解
实现HandlerExceptionResolver接口
token身份验证
算法与数据结构
算法
分类
排序算法
排序算法
选择排序
冒泡排序
插入排序
快速排序
归并排序
希尔排序
堆排序
计数排序
桶排序
基数排序
分类
内排序
内部排序是指待排序列完全存放在内存中所进行的排序过程,适合不太大的元素序列。
分类
插入排序
直接插入排序
将一个记录插入到已排序好的有序表中,从而得到一个新的有序表。 即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。
希尔排序
先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
选择排序
简单选择排序
每次都找一个最大或者最小的排在开始即可。 1、首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置;2、再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾;3、重复第二步,直到所有元素均排序完毕
堆排序
堆排序(Heapsort) 是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。 可以利用数组的特点快速定位指定索引的元素。
大根堆(最大堆)
每个结点的值都不大于其父节点的值。从下往上,结点值越来越大,根结点值最大。
小根堆(最小堆)
每个结点的值都不小于其父节点的值。从下往上,结点值越来越小,根结点值最小。
交换排序
冒泡排序
冒泡排序可以算得上是最基础的排序算法了。算法的思想是: 依次比较相邻的两个元素,如果后一个小于前一个,则交换,这样从头到尾一次,就将最大的放到了末尾。
快速排序
基本思想: 1)选择一个基准元素,通常选择第一个元素或者最后一个元素;2)通过一趟排序讲待排序的记录分割成独立的两部分,其中一部分记录的元素值均比基准元素值小。另一部分记录的 元素值比基准值大;3)此时基准元素在其排好序后的正确位置;4)然后分别对这两部分记录用同样的方法继续进行排序,直到整个序列有序。
归并排序
归并排序是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。 然后再把有序子序列合并为新的有序序列。基本原理是分治法,包括递归和合并。
基数排序
外排序
指能够处理极大量数据的排序算法。通常来说,外排序处理的数据不能一次装入内存,只能放在读写较慢的外存储器(通常是硬盘)上。
应用:大文件拆分排序
评估标准
时间/空间复杂度O
“时间换空间,空间换时间”
稳定性
假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变, 即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍在rj之前,则称这种排序算法是稳定的;否则称为不稳定的。
查找算法
二分查找
分块查找
哈希查找
计算哈希值
贪心算法
求最小生成树的Prim算法和Kruskal算法
爬山问题
分治算法Divide and Conquer
算法思想: 1、划分:将原问题划分成多个子问题;2、求解:递归地解各子问题。若子问题足够小,则直接求解;3、合并:将子问题的解进行合并,得到原问题的解。
应用:归并排序
动态规划Dynamic Planning
基本思想
动态规划算法与分治算法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。 与分治法的区别:分治:各子问题间相互独立;动态规划:各子问题间存在重叠部分
最优子结构,状态转移方程(递推关系)的确定
应用
求最长公共子序列LCS
矩阵连乘问题
爬楼梯问题
找零问题
0-1背包问题
回溯算法
n 皇后问题
字符串比较
KMP 算法
深度优先、广度优先
剪枝算法
朴素贝叶斯
推荐算法
最小生成树算法
最短路径算法
其他
Rabin fingerprints 文件指纹算法
为每个文件生成唯一的hash值,可用于文件内容相似度比较及匹配
应用:百度识图等类似场景
BitMap 位图算法
算法思想:将大量数据经过hash映射保存到一个bit数据中,大大减少了存储空间
用于处理大量数据的排序、查询以及去重
BloomFilter 布隆过滤器
用于高效检测数据元素是否在给定集合中存在,适用于大数据量。它是BitMap的扩展
应用:鉴别垃圾邮件
数据结构
线性表
顺序表
数组(Array)
数组是在内存中存储相同数据类型的连续的空间,声明一个数组就是在内存空间中划出一串连续的空间。
数组下标从0开始,数组长度一旦声明,不可改变不可追加。
栈(Stack)
栈是一种特殊的线性表,仅能在线性表的一端操作,栈顶允许操作,栈底不允许操作。
栈的特点:先进后出(FILO),或者说是后进先出,从栈顶放入元素的操作叫入栈,取出元素叫出栈。
队列(Queue)
一种线性数据结构,先进先出 的结果(FIFO)。只能从一端(队尾)添加元素,只能从另一端(队首)取出元素。
链队列
循环队列
双端队列
Java中的Deque接口
链表(Linked List)
最简单的动态数据结构,优点:真正的动态,不需要处理固定的容量。缺点:丧失了随机访问的能力。
链表在进行循环遍历时效率不高,但是插入和删除时优势明显。
单向链表
循环链表
双向链表
树(Tree)
二叉树
每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)
分类
二叉查找树(Binary Search Tree,BST),也称有序二叉树(ordered binary tree),排序二叉树(sorted binary tree)
完全二叉树
叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树
堆
堆总是满足下列性质:
1、是一棵完全二叉树;
2、任意结点的值总是不大于或不小于其父结点的值。将根结点值最大的堆叫做最大堆或大根堆,根结点值最小的堆叫做最小堆或小根堆。
1、是一棵完全二叉树;
2、任意结点的值总是不大于或不小于其父结点的值。将根结点值最大的堆叫做最大堆或大根堆,根结点值最小的堆叫做最小堆或小根堆。
满二叉树
深度为k且有2^k-1个节点的二叉树称为满二叉树
完全二叉树和满二叉树的区别
哈夫曼树
哈夫曼编码
用于二进制表示字符串
二叉搜索树
平衡二叉树(AVL)
任一节点对应的两棵子树的最大高度差为1
平衡二叉树的高度和节点数量之间关系:O(log n)
红黑树
红黑树本质上就是一棵二叉查找树
增加了着色和相关的性质使得红黑树相对平衡,从而保证了红黑树的查找、插入、删除的时间复杂度最坏为O(log n)
添加阶段后,左旋或者右旋从而再次达到平衡
红黑树(一)之 原理和算法详细介绍
遍历
先序遍历(根->左->右)
中序遍历(左->根->右)
后序遍历(左->右->根)
层序遍历
多叉树
B树
B树也称为B-树,它是一棵多路平衡查找树。
所有关键字在整颗树中出现,且只出现一次,非叶子节点可以命中;
所有关键字在整颗树中出现,且只出现一次,非叶子节点可以命中;
查找节点、插入节点、删除节点(左旋)
B+ 树
在B-树基础上,为叶子结点增加链表指针,所有关键字都在叶子结点中出现,非叶子结点作为叶子结点的索引;
B+树总是到叶子结点才命中;
B+树总是到叶子结点才命中;
查找节点、插入节点、删除节点
B*树
B*数是B+树的变体,在B+树的非根和非叶子节点在增加指向兄弟的指针
B-树,B+树,B*树详解
B-树,B+树与B*树的优缺点比较
LSM 树
日志结构合并树(Log-Structured Merge Tree)
通过传统索引组织有序文件或内存块的一种方式
[HBase] LSM树 VS B+树
LSM树(Log-Structured Merge Tree)存储引擎
堆(Heap)
用数组实现的二叉树,所以它没有使用父指针或者子指针。堆根据“堆属性”来排序,“堆属性”决定了树中节点的位置。
图(Graph)
一种非线性的数据结构,用来表示多对多的关系
分类
有向图
无向图
表示方法
邻接矩阵
邻接表
遍历
深度优先搜索
广度优先搜索
哈希表(即散列表,Hash Table)
基于数组实现的,可以说,没有数组就没有散列表
哈希函数
直接定址法
数字分析法
平方取中法
折叠法
除留余数法
随机数法
处理哈希冲突
开放定址法
再哈希法
链地址法
建立一个公共溢出区
其他
集合(Set)
一个不包含“重复元素”的集合
关联数组(字典)
Java不支持关联数组,但这可以使用Map轻松实现。
BitSet
Java中的一种数据结构。主要存储的是二进制位,做的也是位运算,每一位只用来存储0,1值,主要用于对数据的标记。经常用于大规模数据的排重检查。
设计模式
高内聚低耦合
内聚是描述模块内的功能联系,一个好的内聚模块应当恰好做好一件事
耦合描述的是各个模块间的联系,耦合度是指模块间的依赖关系(调用关系、控制关系、数据传递关系)
模块间关系越多,耦合程度就越强,在面对对象思想领域,要求低耦合
模块间关系越多,耦合程度就越强,在面对对象思想领域,要求低耦合
创建型6种
单例模式(Singleton)
目的
确保该类只能创建一次对象,即确保对象的唯一性
单例模式出现动机
1、如果需要创建的很多个对象他们的内容都一样,那就没必要创建很多个,只用一个就好,可以避免系统资源浪费
2、如果一个系统需要的某一个类的对象每次的内容都是相等的,那每次实例化这个类不可能保证每次都相等,
为了使某个类每次创建的对象都完全一样,就需要单例模式
为了使某个类每次创建的对象都完全一样,就需要单例模式
设计方式
将该类构造器设为私有
在该类中定义并保存该类的唯一实例
定义静态方法,供外部访问该类的唯一静态实例
分类
饿汉式单例
在定义静态变量的时候实例化该类
在定义静态变量的时候实例化该类
这样不会出现并发问题
懒汉式单例
在调用静态工厂方法时判断单例是否为空,如果为空创建,不为空则直接返回
但在多线程环境中还是会出现多个实例的情况
在静态工厂方法上加synchronized关键字,使其每次只能被一个线程访问
静态内部类
线程安全、线程不安全
线程安全
枚举
双重检验锁
工厂模式(Factory)
简单工厂模式
通过传入不同的类型名称来生产不同的产品。 包括工厂(静态工厂方法)、抽象产品、具体产品三个角色
设计思想
将需要创建的各个对象的代码封装成各个类,将这些类共同的代码封装成抽象类做他们的父类
再提供一个工厂类并提供用于创建所需要的各个对象的方法
客户端只需要调用工厂类的方法并传入相应参数便可以得到想要的对象
简单工厂模式的定义
定义一个工厂类,它可以根据参数的不同返回不同的实例,这些实例通常有一个共同父类:
内置静态方法,专门用于获取实例,因此又叫静态工厂方法模式
内置静态方法,专门用于获取实例,因此又叫静态工厂方法模式
简化
将工厂类和抽象父类合并,也就是在抽象父类中定义用于创建各个对象的静态方法
优点
实现了对象的创建与使用分离
通过改变参数就可以获取不同对象,比较灵活
缺点
工厂类职责过于繁重
引入工厂类,增加了类的个数,并提高代码理解难度和复杂度
引入工厂类,增加了类的个数,并提高代码理解难度和复杂度
适用场景
工厂类负责创建的对象较少
客户端只知道创建对象所需参数,对如何创建对象并不关心
工厂方法模式
具体工厂生产具体产品。 在简单工厂基础上增加了“抽象工厂”角色
设计思想
针对不对的具体产品类,提供不同的工厂类
工厂模式的定义
定义一个用于创建对象的接口,让子类决定将哪一个类实例化
工厂模式让一个类的实例化延迟到其子类,由创建对象的工厂的各个子类决定创建哪个实例
角色
Product(抽象产品)
ConcreteProduct(具体产品)
Factory(抽象工厂)
ConcreteFactory(具体工厂)
优点
客户端无需知道具体对象的创建细节
基于工厂角色和产品角色的多态性设计是工厂模式的关键
完全符合开闭原则
缺点
在出现新的需要创建的对象时,系统中的类会成对增加
适用场景
客户端不需要知道要创建的对象类,只需要知道该类对应的工厂类即可
抽象工厂类通过其子类来指定创建哪个对象
抽象工厂模式
包含创建一族产品的工厂方法,每一个方法对应一个产品族
抽象工厂的定义
提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类
包含角色
AbstractFactory(抽象工厂)
它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
ConcreteFactory(具体工厂)
它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品
这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。
AbstractProduct(抽象产品)
它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
ConcreteProduct(具体产品)
它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
开闭原则倾斜
增加产品族完全符合开闭原则
产品族指的是一组产品例如海尔公司的冰箱空调洗衣机
增加产品等级结构
产品等级结构指的是一个公司,例如增加一个电视
优点
增加新的产品族很方便,无须修改已有系统,符合“开闭原则”。
当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
缺点
增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,
这显然会带来较大的不便,违背了“开闭原则”。
这显然会带来较大的不便,违背了“开闭原则”。
建造者模式
复杂对象的组装与创建,包括抽象建造者、具体建造者、指挥者和复杂产品角色。 由指挥者决定产品组装的顺序
原型模式(Prototype)
目的
为了解决每次需要创建与之前对象内容基本相同但又不是同一个对象的问题,
Sunny公司针对员工写重复的工作周报问题提出了原型设计模式,即对象的克隆
Sunny公司针对员工写重复的工作周报问题提出了原型设计模式,即对象的克隆
定义
先创建一个原型对象,再通过复制创建出更多同类型的对象
对象克隆
深克隆
1、实现序列化接口Serializable 2、通过字节数组流和对象流进行克隆
浅克隆
Object的clone方法
结构型7种
适配器模式(Adapter)
对象适配器
适配器与适配者之间是关联关系。
类适配器
适配器与适配者之间是继承(或实现)关系。
双向适配器
在适配器中同时包含对目标类和适配者类的引用,适配者可以通过它调用目标类中的方法,目标类也可以通过它调用适配者类中的方法
缺省适配器
当不需要实现接口中所有方法时,可以使用一个抽象类去实现该接口,并提供其中方法的默认实现(空实现)。 使用时只需要继承抽象类,然后选择性的重写其中的方法即可。
在一些开源框架中应用广泛:如Spring MVC中典型的HandlerInterceptor接口和HandlerInterceptorAdapter抽象类
代理模式(Proxy)
1、给某个对象提供一个代理对象,并由代理对象来控制对目标对象的访问,外部客户端不直接对目标对象进行操作;
2、代理对象和原对象需要实现相同的接口,这样一来在任何使用目标对象的地方都可以使用代理对象来替代(里氏代换原则)
3、代理类中维护一个目标接口的引用
2、代理对象和原对象需要实现相同的接口,这样一来在任何使用目标对象的地方都可以使用代理对象来替代(里氏代换原则)
3、代理类中维护一个目标接口的引用
应用分类
JDK代理
静态代理
让代理类和目标类实现一样的接口;同时代理类中维护一个目标类对象的引用。 如Thread类(代理)和Runnable接口(目标),在Thread类中包含一个Runnable接口类型的引用
缺点: 1、目标类必须实现接口(因为生成的代理类会默认继承Proxy类,就不能再继承其他类了)2、当改变目标类后,相应的代理类不能随之改变,必须自己修改代理类代码
动态代理
它是静态代理的改进:当代理的接口发生改变时相应的代理对象也随之改变。 让代理类实现InvocationHandler接口,动态为目标接口生成代理类
缺点:目标类必须实现接口(因为生成的代理类会默认继承Proxy类,Java不支持多继承,因此就不能再继承其他类了)
cglib代理
使用字节码技术(asm框架)动态创建目标类的子类做为代理类,突破了JDK代理中目标类必须实现接口的限制
缺点:无法为final修饰的类或方法创建代理
装饰模式(Decorator)
1、通过创建一个包装类来扩展一个类的功能(比如添加新的方法),是对继承的一种替代方案,但能达到与继承一样的效果;
2、装饰类和原有类需要实现相同的接口,这样一来在任何使用原始对象的地方都可以使用装饰对象来替代;
3、装饰类中维护一个原有类型接口的引用
2、装饰类和原有类需要实现相同的接口,这样一来在任何使用原始对象的地方都可以使用装饰对象来替代;
3、装饰类中维护一个原有类型接口的引用
特点:被装饰的对象一般会作为构造方法的参数传入装饰器类
与代理模式的区别: 装饰模式可以在不改变原有类的情况下对原有类进行功能扩展(增加方法);而代理模式不会扩展原有类的功能(方法),只能控制在调用原有类的访问操作前后增加额外的操作,比如记录操作日志。
外观模式
通过引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口, 使子系统与客户端的耦合度降低,且客户端调用非常方便。
外观模式并不会给系统增加任何新功能,它仅仅是简化调用接口
桥接模式
组合模式
组合多个对象形成树形结构,以表示具有“整体—部分”关系的层次结构。 组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。
主要角色:抽象构件Component、叶子构件Leaf(单个对象)、容器构件Composite(组合对象)
典型应用:Spring MVC中的HandlerMethodArgumentResolver(单个对象)与HandlerMethodArgumentResolverComposite(组合对象)
享元模式
行为型11种
模板方法模式(Template)
定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
典型应用:HttpServlet中的service方法
观察者模式(Observer)
组成:抽象目标(包含一个观察者对象集合)、具体目标、抽象观察者、具体观察者
应用:MVC(Model-View-Controller,当模型M(目标)中的数据改变时,通知相应视图V(观察者)做出改变)、Event Listener事件监听机制
策略模式(Strategy)
避免多个if...else分支判断语句
应用:SpringMVC中的HandlerMethodArgumentResolver,根据不同的参数或注解类型选择不同的参数解析器进行解析(即参数绑定)
迭代器模式
Java集合框架Iterator,包括抽象集合、具体集合、抽象迭代器、具体迭代器
责任链模式
请假审批流程
工作流
实际应用
Java EE中的Filter/FilterChain 过滤器/过滤器链
Spring MVC HandlerInterceptor拦截器
Struts2 拦截器/拦截器栈
命令模式
关灯
状态模式
访问者模式
中介者模式
备忘录模式
撤销操作
解释器模式
数据库
关系型数据库
SQL语法
数据查询语言DQL
数据查询语言,顾名思义就是从数据库中查询数据。包括select、where、order by、group by、having等动词。
数据定义语言DDL
数据定义语言,用于数据库表结构的相关操作,如创建表CREATE、删除表DROP、添加表索引等。
数据操作语言DML
通过GRANT或REVOKE获得许可,确定单个用户和用户组对数据库对象的访问。某些RDBMS可用GRANT或REVOKE控制对表单个列的访问。
数据操纵语言DCL
实现对数据库表数据的查询、增加、删除和修改操作,包括insert、update、delete
SQL执行顺序
SQL语句的语法书写顺序与其执行顺序有区别
语法顺序:SELECT -> DISTINCT -> FROM -> JOIN ON -> WHERE -> GROUP BY -> HAVING -> UNION -> ORDER BY 执行顺序:FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> DISTINCT -> UNION -> ORDER BY
常见关系型数据库
SQL Server、MySQL、Oracle等
数据库设计
三大范式
第一范式1NF:列的原子性
第二范式2NF:满足第一范式,必须要有主键列
第三范式3NF:满足第二范式,主外键引用
完整性约束
域(列)完整性:包括取值范围、类型、默认值、非空等
实体(行)完整性:主关键字既不能重复,也不能为空值
参照完整性:外键约束
用户自定义完整性:范围约束等
数据库模型
概念模型
E-R图,即Entity Relationship,实体关系。可以通过PowerDesigner进行建模
逻辑模型
关系:二维表
物理模型
表结构,包括字段类型、长度、主外键、是否非空等信息
JDBC
Java DataBase Connectivity,即Java数据库连接,是用Java语言定义的统一的数据库操作规范,具体实现由各个数据库厂商完成。 位于java.sql包中,包含对数据库的各种操作相关接口和类
操作步骤
加载数据库驱动
导入对应数据库的驱动jar包
Class.forName(数据库驱动全类名) 加载驱动
获取连接对象
DriverManager.getConnection(url, userName, password)
获取语句对象Statement/PreparedStatement
进行数据操作(增、删、改、查)
释放资源:关闭结果集ResultSet、语句对象Statement、连接对象Connection
API
DriverManager类
用于获取数据库连接对象
DriverManager.getConnection(url, userName, password)
Connection接口
完成数据库操作的主要对象,其中包括了数据操作相关的方法
事务相关
设置手动提交事务: connection.setAutoCommit(false);
提交事务:connection.commit();
Statement接口
执行SQL语句
PreparedStatement接口
Statement的子接口
执行预编译SQL语句,防止SQL注入,及提高SQL执行效率
ResultSet接口
代表查询结果集
CallableStatement接口
PreparedStatement的子接口
处理存储过程的调用
DatabaseMetaData接口
包含对数据源的元数据(比如表结构、字段类型、函数、触发器、存储过程等)信息进行获取的API
通过Connection对象的getMetaData()方法获取
ResultSetMetadata接口
包含对查询结果集中的元数据(比如字段类型、字段值)等信息进行获取的API
通过ResultSet对象的getMetadata()方法获取
数据库连接池
C3P0
DBCP
Druid
带有监控功能的数据库连接池
事务
ACID四大特性
原子性Atomicity
事务是原子性操作,要么都执行,要么都不执行
一致性Consistency
事务在执行前后数据完整性必须保持一致
隔离性Isolation
并发的事务之间是相互隔离的,事务内部的操作对于其他事务而言都是互不可见的。 如果不考虑隔离性,就可能发生脏读、不可重复读、幻读的问题
1)脏读:一个事务读取了另一个事务改写但还未提交的数据,如果这些数据被回滚,则读到的数据无效。
2)不可重复读:在同一事务中,多次读取同一数据返回的结果不同。
3)幻读:一个事务读取了几行记录后,另一个事务插入一些记录。后来的查询中,前一个事务就会发现有些原来没有的记录。
2)不可重复读:在同一事务中,多次读取同一数据返回的结果不同。
3)幻读:一个事务读取了几行记录后,另一个事务插入一些记录。后来的查询中,前一个事务就会发现有些原来没有的记录。
持久性Durability
事务一旦完成提交,引起的数据改变将是永久性的,即使数据库发生故障也不应该对其有任何影响
游标
相当于一个指针,用于对数据库中数据进行遍历操作,通常以行为单位进行遍历
函数
CREATE FUNCTION func_name(@[参数名] [类型],@[参数名] [类型], ......) RETURNS [返回值类型1], [返回值类型2]......ASBEGIN.....END
有返回值,可以在select语句中使用
存储过程
CREATE PROCEDURE/PROC sp_name@[参数名] [类型],@[参数名] [类型], ...... ASBEGIN.....END
无返回值,通过 exec sp_name [参数名] 形式进行调用
触发器
类似于存储过程,唯一区别是触发器不能执行EXECUTE语句调用,而是在用户执行T-SQL语句时自动触发执行。
视图
基于 SQL 语句的结果集构成的表(虚拟表)
索引
普通索引
最基本的索引类型,没有唯一性之类的限制
唯一索引
不允许其中任何两行具有相同索引值的索引
主键索引
主键索引是唯一索引的特定类型,索引字段为主键
全文索引
按包含的字段数量
单一索引
单个字段作为索引
组合索引
多个字段一起作为一个索引
按数据结构
Btree索引
以B/B+树的数据结构存储,应用范围广
Hash索引
通过Hash算法计算索引位置,效率高,一次定位。但需要解决Hash冲突。不支持范围检索
按物理存储结构
聚集索引(覆盖索引)
数据和索引存放在同一文件中,以主键为索引存储数据
表中行的物理顺序与键值的逻辑(索引)顺序相同。一个表只能包含一个聚集索引。
非聚集索引
数据和索引分开单独存放在不同的文件中,索引文件不存储数据,而是存储数据的地址
数据库表中记录的物理顺序与索引顺序可以不相同。一个表中可以包含多个非聚集索引
注意事项
1、适合索引的列是出现在where子句中的列,或者连接子句中指定的列
2、选择基数大的列作为索引,基数计算方式:COUNT(DISTINCT columnName) / COUNT(*)
3、组合索引遵循最左前缀原则
如 对于索引 index(a,b,c),当查询条件包含列a时会使用索引
4、如果列类型是字符串,那一定要在查询条件中给数据加上引号,否则会进行隐式类型转换,不会使用索引
5、前导模糊查询不能命中索引,如 like '%abc'
SQL执行计划
MySQL
explain 命令,如 explain select * from tb_user
Oracle
explain plan 命令,如 explain plan for select * from tb_user
MYSQL
分库分表
唯一主键
事务隔离级别
读未提交
没视图概念 都是返回最新的
读已提交
不同的read view
可重复读
用一个read view
回滚日志
没更早的read view删除
5.5之前回滚段删了文件也不会变小
索引结构
B+树
Hash
等值查询
MVCC
版本链 在聚集索引中 有两个隐藏列 trx_id roll_pointer
读未提交
直接读取最新版本
序列化
加锁
Read View
读已提交
每次读取前生成一个
可重复度
第一次生成一个
锁
全局锁
全库逻辑备份
表锁
lock table read/write
MDL(metadata lock)
MySQL5.5引入 自动添加 读锁不互斥 写锁互斥
多个事务之前操作,如果查询的时候修改字段容易让线程池饱满
MySQL的information_schema 库的 innodb_trx 表 找到对应长事务 kill掉
alter table里面设定等待时间
Myisam是不支持表锁的
行锁
需要的时候才加上 并不是马上释放 等事务结束才释放 两阶段锁协议
死锁
超时时间
innodb_lock_wait_timeout
默认是50s太久 但是如果设置太短会误判 一般采用死锁监测
死锁机制 事务回滚
innodb_deadlock_detect = on
热点行
死锁消耗CPU
临时关闭
关掉死锁会出现大量重试
控制并发度
更多的机器 开启比较少的线程 消耗就少了
分治
间隙锁
读写锁
读
lock in share mode
for update
行锁
写
innodb如何加锁
Record lock: 对索引项加锁。
Gap lock:对索引项之间的‘间隙’,第一条记录前的间隙,或最后一条记录后的间隙 加锁
Next-Key:前两种的组合,对记录及前面的间隙加锁
Gap lock:对索引项之间的‘间隙’,第一条记录前的间隙,或最后一条记录后的间隙 加锁
Next-Key:前两种的组合,对记录及前面的间隙加锁
日志Log
undo log
回滚 mvcc
redo log
物理日志 内存操作记录
sync_binlog 可以优化日志写入时机
binlog
组提交机制,可以大幅度降低磁盘的IOPS消耗。
两段式提交 redo 准备 binglog 提交
mysql io性能瓶颈
设置 binlog_group_commit_sync_delay 和 binlog_group_commit_sync_no_delay_count参数,减少binlog的写盘次数。这个方法是基于“额外的故意等待”来实现的,因此可能会增加语句的响应时间,但没有丢失数据的风险。
将sync_binlog 设置为大于1的值(比较常见是100~1000)。这样做的风险是,主机掉电时会丢binlog日志。
将innodb_flush_log_at_trx_commit设置为2。这样做的风险是,主机掉电的时候会丢数据。
将sync_binlog 设置为大于1的值(比较常见是100~1000)。这样做的风险是,主机掉电时会丢binlog日志。
将innodb_flush_log_at_trx_commit设置为2。这样做的风险是,主机掉电的时候会丢数据。
常见命令
show processlist
查看空闲忙碌链接
wait_timeout
客户端空闲时间
定时断开链接
mysql_reset_connection 恢复链接状态
innodb_flush_log_at_trx_commit
redolog事务持久化
sync_binlog
binlog事务持久化
真实故障
数据库挂了 show processlist 一千个查询在等待 有个超长sql kill 但是不会引起flush table 周末 优化脚本 analyze 会导致 MySQL 监测到对应的table 做了修改 必须flush close reopen 就不会释放表的占用了
优化流程
预发跑sql explain
排除 缓存 sql nocache
看一下行数对不对 不对可以用analyze table t 矫正
添加索引 索引不一定是最优的 force index 强制走索引 不建议用
存在回表的情况
覆盖索引避免回表,不要*
联合索引 不能无限建 高频场景
最左前缀原则 按照索引定义的字段顺序写sql
合理安排联合索引的顺序
5.6之后 索引下推 减少回表次数
给字符串加索引
前缀索引
倒序存储
Hash
数据库的flush的时机
redo log满了 修改checkpoint flush到磁盘
系统内存不足淘汰数据页
buffer pool
要知道磁盘的io能力 设置innodb_io_capacity 设置为磁盘的IOPS fio测试
要知道磁盘的io能力 设置innodb_io_capacity 设置为磁盘的IOPS fio测试
系统空闲的时候 找间隙刷脏页
MySQL正常关闭,会把内存脏页flush到磁盘
innodb刷盘速度
脏页比例
redolog 写盘速度
innodb_flush_neighbors 0
机械磁盘的随机io不太行 减少随机io性能大幅提升 设置为 1最好
现在都是ssd了 设置为0就够了 8.0之后默认是0
索引字段不要做函数操作,会破坏索引值的有序性,优化器会放弃走树结构
如果触发隐式转换 那也会走cast函数 会放弃走索引
字符集不同可能走不上索引
convert 也是函数所以走不上
索引维护
页满了 页分裂 页利用率下降
数据删除 页合并
自增 只追加可以不考虑 也分页
索引长度
索引更新
change buffer
更新操作来了 如果数据页不在内存 就缓存下来 下次来了 更新 在就直接更新
唯一索引 需要判断 所以 用不到change buffer
innodb的处理流程
记录在页内存
唯一索引 判断没冲突插入
普通索引 插入
记录不再页中
数据页读入内存 判断 插入
change buffer
数据读是随机IO 成本高
机械硬盘 change buffer 收益大 写多读少 marge
非关系型数据
Redis
数据结构
String
Hash
set
zset
score
随机层数
只需要调整前后节点指针
不止比较score
还会比较value
场景
成绩
积分
排行榜
List
HyperLogLog
Geo
Pub/Sub
BitMap
底层
SDS
键值的底层都是SDS
AOF缓存区
记录本身长度 C需要遍历
修改字符减少内存重新分配
空间预支配
惰性空间释放
二进制安全
C只能保存文本数据 无法保存图片等二进制数据
sds是使用长度去判断
杜绝缓冲区溢出
兼容部分C字符串函数
链表
保存多个客户端的状态信息
列表订阅发布 慢查询 监视器
字典
数据库 哈希键
Hash表节点
hash冲突用单向链表解决
渐进式 rehash
会逐渐rehash 新的键值对全部放到新的hash表
每个字典带 两个hash表
一个平时用 一个rehash时候用
压缩列表
整数集合
常见命令
Keys
setnx
exprie
高可用
持久化
RDB
冷备
恢复的时候比较快
快照文件生成时间久,消耗cpu
AOF
appendOnly
数据齐全
恢复慢文件大
数据初始化
从节点发送命令主节点做bgsave同时开启buffer
数据同步机制
主从同步
指令流
offset
快照同步
RDB
缓冲区
哨兵
集群监控
消息通知
故障转移
配置中心
脑裂
集群
链表
多主
横向扩容
分片
常见问题
缓存雪崩
加随机值
集群部署
缓存击穿
互斥锁
热点数据不失效
缓存穿透
布隆过滤器
双写一致性
延时双删
并发竞争
分布式锁
大Key
bigkey命令 找到干掉
Redis 4.0引入了memory usage命令和lazyfree机制
热点key
缓存时间不失效
多级缓存
布隆过滤器
读写分离
过期策略
定时删除
消耗内存
创建一个定时器
惰性删除
可能存在大量key
定期删除
检查 删除 但是是随机的
淘汰机制
LUR
最少使用
备用方案
主从+哨兵+cluster
ecache+Hystrix+降级+熔断+隔离
持久化
限流
setnx ex
zset
窗口滑动
zset会越来越大
令牌
定时push
然后leftpop
问题
空轮训
blpop
空连接异常
重试
漏桶 funnel
make_space 灌水之前调用漏水 腾出空间 取决于流水速率
Hash
原子性有问题
Redis-Cell
MongoDB
高并发
概念
大量用户同时访问请求网站或系统,造成请求不能及时响应的现象
解决方案
负载均衡Load Balance,简称LB
硬件
F5
软件
nginx
Linux服务器集群系统LVS(Linux Virtual Server)
HaProxy
服务器集群
服务器集群就是指将很多服务器集中起来一起进行同一种服务,在客户端看来就像是只有一个服务器。
常见集群
Tomcat服务器集群
Apache + Tomcat:一台Apache服务器进行反向代理与请求分发,多台Tomcat服务器处理请求
Nginx + Tomcat:一台Nginx服务器进行反向代理与请求分发,多台Tomcat服务器处理请求
Weblogic服务器集群
数据库服务器集群
锁机制
分布式锁
基于数据库实现
锁表
创建一张锁表,当需要锁住某个方法或资源时,我们就在该表中增加一条相应的记录,想要释放锁的时候就删除该条记录
排他锁
在查询语句后面增加for update,数据库会在查询过程中给数据库表增加排他锁,直到事务提交后才会释放锁
基于缓存实现
如redis、memcached等
基于zookeeper实现
Java中的锁
用于保证线程同步
同步锁synchronized关键字
Lock
CAS
数据库锁
已由数据库本身实现,只需调用相关语句即可
乐观锁
通常通过在表结构中增加一个版本号字段来解决,查询数据时将版本号一起查出来,需要更新数据时就将原有版本号加一
给数据库操作加个版本号判断,满足条件的才会执行,这就相当于给数据库操作加了一把锁
如 update user set name='Tom', version=2 where id=1 and version=1
悲观锁
共享锁
对于MySQL数据库,在查询语句后面加上lock in share mode,数据库就会在查询过程中给数据库表增加共享锁
排他锁
也称独占锁。排他锁与共享锁相对应,就是指对于多个不同的事务,对同一个资源只能有一把锁。
在查询语句后面增加for update,数据库会在查询过程中给数据库表指定行增加排他锁,直到事务提交后才会释放锁
如 select * from user where name='张三' for update
缓存技术
要解决的问题
缓存一致性
缓存与数据库中的数据需要保证一致
缓存雪崩
缓存在同一时间大面积失效
缓存穿透
指缓存和数据库中都没有的数据。
缓存击穿
缓存中没有,但数据库中有(一般为缓存时间到期)
好处
减轻数据库如MySQL、Oracle等的压力
提高数据访问的速度
常用缓存中间件
Redis
Redis的安装及配置(Linux环境下)
下载源码
wget http://download.redis.io/releases/redis-2.8.13.tar.gz
解压后编译并安装
tar vxzf 下载的安装包名
cd 进入解压后的文件夹中
make 编译
make install 安装
redis.conf文件配置
后台启动配置参数
daemonize yes (no-不后台启动 yes-后台启动)
端口配置参数
port 6379 (可以更改自己的端口号,客户端登陆时,如改变默认端口,则需指定设置的端口进行登陆)
信息查看命令
查看redis客户端 which redis-cli 登录:redis-cli(默认登录本机6379端口)info命令查看redis信息
过期时间expire
数据类型
String
最基本的存储结构
命令
get key set key valuemget key1 key2...、mset key1 key2...setnx key valueincr/decr key
Hash
key-value结构
命令
hget key field hset key field valuehmset key field1 value1 field2 value2...hmget key field1 field2 ...
List
双向链表结构,数据按从左到右的顺序存储
命令
lpush、rpush、lpop、rpop、lset key index value
Set
Set集合,不能有相同的值
命令
sadd key member1 member2... scard keyset key index valuesismember key membersmembers key
zset(sorted set)
有序集合,按照score排序
命令
zadd key score1 member1 score2 member2 ... zcard keyzrange key start stop [withscores]
存储
内存、磁盘、日志文件
持久化
RDB快照
Append-only file(缩写为AOF)日志
发布/订阅
管道pipeline
可以一次性发送多条命令并在执行完后一次性将结果返回
通过减少客户端与redis的通信次数来实现降低往返延时时间,而且其实现原理是队列,先进先出,因此可以保证数据的顺序性。
事务
事务中的多条命令要么都执行成功,要么都失败
Memcached
特点: 1、只支持key-value数据结构存储;2、缓存数据全部在内存中,不支持数据持久化
EhCache
服务降级
网页HTML静态化
CDN(Content Delivery Network,内容分发网络)加速
数据库读写分离、分表分库
图片服务器分离
负载测试工具
Jmeter
Tsung
分布式
分布式一致
CAP理论
指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼
1、一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
2、可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
3、分区容错性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
2、可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
3、分区容错性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
BASE理论
幂等性
幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。
分布式锁
分布式一致性算法
PAXOS
Zab
Raft
Gossip
两阶段提交、三阶段提交
分布式计算
大运算量计算场景
MapReduce、Hadoop、Spark
分布式存储
大数据量存储场景
分布式数据库
Redis、MongoDB、HBase等
分布式文件系统Distributed File System,HDFS
一致性哈希Consist Hashing算法
用于分布式数据存储,使数据在各个存储节点上均匀分布
广泛应用于分布式缓存
分布式消息服务(消息队列)
ActiveMQ、RabbitMQ、RocketMQ、Kafka
可应用于高并发场景
分布式系统需要解决的问题
分布式事务
分布式事务是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。
Session共享
ip hash负载均衡
使用缓存如redis保存Session
通过编写自己的HttpServletRequest实现替代Tomcat的Session管理,然后在Filter中使用
已有的解决方案:Spring Session + Redis
1、引入Spring Session相关jar包
2、在web.xml增加SpringSessionRepositoryFilter配置
3、引入Redis相关jar包,并增加相应的Spring Bean配置
服务器Session复制
1、修改conf/server.xml文件,打开注释:
2、在web.xml文件中加入配置:
扩展性设计
稳定性 & 高可用
硬件负载均衡
软件负载均衡
限流
应用层容灾
跨机房容灾
容灾演练流程
平滑启动
数据库扩展
读写分离模式
分片模式
服务治理
服务注册与发现
服务路由控制
性能优化
性能指标
硬件层面
软件层面
响应时间
指系统对请求作出响应的时间,通常包括客户端响应时间、网络响应时间和服务端响应时间。
吞吐量
并发用户数
性能测试
Jmeter
硬件优化
CPU、内存、磁盘
数据库SQL优化
分析SQL执行计划
MySQL 使用 explain 命令
如 explain select ...
Oracle 使用 explain plan for 命令
如 explain plan for select ...
SQL语句优化
建立及优化索引
JVM参数调优
内存泄露
内存使用后未得到及时释放,而且不能被GC回收,导致虚拟机不能再次使用该内存,此时这段内存就泄露了
内存溢出OOM
即OutOfMemoryError,当没有足够的空闲内存可供程序使用时出现
常见类型
Java Heap Space : Java堆内存溢出
此种情况最常见,一般由于内存泄露或者堆的大小设置不当引起。 对于内存泄露,需要通过内存监控软件(如heapdump)查找程序中的泄露代码;而堆大小可通过设置JVM的参数-Xms、-Xmx来解决。
PermGen Space:永久代内存溢出
即方法区内存溢出,如果程序加载的类过多,或者使用反射、gclib等这种动态代理生成类的技术,就可能导致该区发生内存溢出。 此种情况可以通过更改方法区的大小来解决,设置-XX:PermSize=64m -XX:MaxPermSize=256m参数。另外,过多的常量尤其是字符串也会导致方法区溢出,因为常量池也位于方法区中。
注:从Java8开始移除了Permgen Space,取而代之的是MetaSpace
StackOverFlowError:栈溢出
即虚拟机栈或本地方法栈区域内存溢出
出现原因:程序中出现死循环或递归次数过多;也可能是栈大小设置过小导致,可通过设置-Xss参数来调整栈大小。
监控工具
jps:查看Java进程
jmap:查看JVM当前的堆内存快照(heapdump)
jstack:查看JVM当前的线程快照,又称threaddump文件,它是JVM当前每一条线程正在执行的堆栈信息的集合
jinfo:实时查看JVM的参数信息
jstat:用于监控JVM的各种运行状态信息,如类的装载、内存、垃圾回收、JIT编译器等
jconsole:用于监控内存,线程、堆栈等信息
jprofile:类似于jconsole,比jconsole监控的信息更全面
程序优化
代码优化
遵循好的编码规范
《阿里巴巴Java开发手册》
《Google编码规范》
运用好的编码技巧
提高代码可重用性、可扩展性
JNI(Java Native Interface,Java本地接口)
将底层的一些操作使用更接近操作系统的语言(如C/C++)进行实现,可以提高程序执行效率
JDK中使用了很多的native方法,如System类中的arraycopy、currentTimeMillis方法等
CDN网络
Linux基础
目录结构
常用命令
帮助命令(man、help、info)
命令终端xshell/SecureCRT/putty
vi/vim编辑器
:w (保存)、:q(退出)、:wq(保存并退出),加!号表示强制命令,如:q!表示强制退出;:set nu(显示行号)
文件和目录操作
cd(切换目录)、ls(查看目录)、pwd(查看当前工作目录)、cp(拷贝文件或目录)、mv(移动、重命名文件或目录)、chmod(改变文件或目录访问权限) rm(删除文件或目录)、rmdir(删除空目录)、touch(创建文件)、mkdir(创建目录)、查看文件(cat、more、less、tail)、tar(压缩、解压文件)等
用户和用户组
useradd(添加一个普通用户)、passwd(修改用户登录密码)、chown(更改文件拥有者)
其它
wget(文件下载,用法:wget [参数] URL)
top(性能监控)、ps(查看进程)
文件搜索:find(支持正则)、whereis、which
文本搜索:grep(Global Regular Expression Print,支持正则表达式的全局文本搜索工具)
ifconfig(类似于Windows的ipconfig,获取及修改网络接口配置信息)
操作系统
进程管理和调度
进程调度算法
先来先服务调度算法FCFS
最高优先数优先算法
短作业优先调度算法
基于时间片的轮转调度算法
同步机制
信号量
P、V原语操作
死锁
产生原因
竞争资源
竞争不可剥夺资源
竞争临时资源
进程推进顺序不当
四个必要条件
互斥条件
资源不能被共享,同一时间只能由一个进程使用
请求与保持条件
已经得到资源的进程可以再次申请新的资源
非剥夺条件
已经分配的资源不能从相应的进程中被强制地剥夺
循环等待条件
系统中若干进程组成环路,该环路中每个进程都在等待相邻进程正占用的资源。
预防和避免方法(破坏四个必要条件)
银行家算法
内存管理
物理内存
虚拟内存
页面置换算法
LRU算法
文件系统
为用户提供操作文件的功能,包括创建、修改、删除等操作
用户界面
提供用户操作的界面
驱动程序
CPU
多级缓存
从Java视角理解CPU缓存和伪共享
进程
线程
协程
计算机网络
分类
按网络范围
局域网LAN
定义:网络为一个单位所拥有,且地理范围和站点数目均有限。 特点:距离短、延迟小、数据速率高、传输可靠。LAN一般都属于广播性网络。目前常用的LAN类型为Ethernet(以太网)。
广域网WAN
在大范围区域内提供数据通信服务,主要用于互连局域网。
按网络使用者
公用网
专用网
计算机网络交换类型
电路交换
通信前需要预先在通信双方间建立一条传输通道,通信双方在通信过程中将一直该通道,直到通信结束。
具有实时性强,时延小等特点
报文交换
以报文为数据交换的单位,报文中携带有目标地址、源地址、数据等信息,由交换结点采用存储转发的方式进行数据传输。 不需要为通信双方预先建立一条专用的通信线路。
分组交换
在发送端将较长的报文分割成较短、固定长度的数据段,在每个数据段前加上首部构成分组。 以分组作为数据传输的基本单元,通过存储转发的方式进行传输。
网络组件
终端设备
在以人为本的网络和通信网络间提供接口。
包括手机、台式电脑、笔记本电脑、平板电脑、打印机、IP电话、网真端点等
中间设备
为主机提供网络连接并连接多个网络形成网际网络。
包括路由器、无线路由器、多层交换机、LAN交换机、防火墙设备
网络介质
为消息提供从源传输到目标的通道。
包括LAN媒体、WAN媒体、无线介质
分层模型
OSI七层模型
从上到下依次是:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
TCP/IP四层模型
应用层
提供应用程序网络接口
DNS、FTP、HTTP、POP3、SMTP、Telnet、RPC等
传输层
提供端到端的通信
TCP
传输数据前需要先建立连接。三次握手,四次挥手
UDP
不需要建立连接,不能保证数据传输可靠性
网络层
寻址和路由
IP、ICMP(ping命令)、ARP(地址解析协议,IP地址解析为物理地址)、RARP(逆地址解析协议,将物理地址解析IP地址)等
网络接口层
提供与底层网络的接口
IP地址
是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址(MAC地址)的差异
IPv4和IPv6
IPv4:32位
IPv6:128位
子网划分
将一个网络划分为更小的网络,比如将公司的网络根据不同部门进行划分
IP划分
A类
A类地址第1字节为网络地址,其它3个字节为主机地址。它的第1个字节的第一位固定为0。
A类地址范围:1.0.0.1—126.255.255.254。0XXX XXXX 1-126 网络掩码为255.0.0.0 2^24-2
A类地址中的私有地址和保留地址:
① 10.X.X.X是私有地址(所谓的私有地址就是在互联网上不使用,而被用在局域网络中的地址)。
范围(10.0.0.1—10.255.255.254)
② 127.X.X.X是保留地址,用做循环测试用的。
① 10.X.X.X是私有地址(所谓的私有地址就是在互联网上不使用,而被用在局域网络中的地址)。
范围(10.0.0.1—10.255.255.254)
② 127.X.X.X是保留地址,用做循环测试用的。
B类
B类地址第1字节和第2字节为网络地址,其它2个字节为主机地址。它的第1个字节的前两位固定为10.
B类地址范围:128.0.0.1—191.255.255.254。10XX XXXX 128-191 网络掩码为255.255.0.0 2^16-2
B类地址的私有地址和保留地址:
① 172.16.0.0—172.31.255.254是私有地址
② 169.254.X.X是保留地址。如果你的IP地址是自动获取IP地址,而你在网络上又没有找到可用的DHCP服务器。就会得到其中一个IP。
191.255.255.255是广播地址,不能分配。
① 172.16.0.0—172.31.255.254是私有地址
② 169.254.X.X是保留地址。如果你的IP地址是自动获取IP地址,而你在网络上又没有找到可用的DHCP服务器。就会得到其中一个IP。
191.255.255.255是广播地址,不能分配。
C类
C类地址第1字节、第2字节和第3个字节为网络地址,第4个字节为主机地址。另外第1个字节的前三位固定为110。
C类地址范围:192.0.0.1—223.255.255.254。110X XXXX 192-223 网络掩码为255.255.255.0 2^8-2
C类地址中的私有地址:
192.168.X.X是私有地址。(192.168.0.1—192.168.255.255)
192.168.X.X是私有地址。(192.168.0.1—192.168.255.255)
D类
D类地址不分网络地址和主机地址,它的第1个字节的前四位固定为1110。
D类地址范围:224.0.0.1—239.255.255.254。1110 XXXX 224-239 组播地址 无掩码
E类
E类地址不分网络地址和主机地址,它的第1个字节的前四位固定为1111。
E类地址范围:240.0.0.1—255.255.255.254。
子网掩码
A类:255.0.0.0
B类:255.255.0.0
C类:255.255.255.0
子网数
子网中的主机数
TCP的几种通信方式
单工通信
通信双方中发送方与接收方分工明确,只能在由发送方向接收方的单一固定方向上传送数据
半双工通信
通信双方都既可以是发送方,也可以是接收方,它们之间可以相互传送数据,但某一时刻则只能向一个方向传送数据,如HTTP
全双工通信
通信双方都既可以是发送方,也可以是接收方,且双方可以同时在两个方向上传送数据,如WebSocket
协议
TCP
三次握手
syn seq
syn ack seq
ack seq
为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
四次挥手
fin ack seq
ack seq
fin ack seq
fin ack seq
ack seq
场景
网络会话
文件传输
发送接收邮件
远程登录
UDP
语音
视频
直播
HTTP1.1
HTTP2.0
HTTPS
长连接和短连接
零拷贝(Zero-copy)
粘包/拆包
在报文末尾增加换行符表明一条完整的消息,这样在接收端可以根据这个换行符来判断消息是否完整。
将消息分为消息头、消息体。可以在消息头中声明消息的长度,根据这个长度来获取报文(比如 808 协议)。
规定好报文长度,不足的空位补齐,取的时候按照长度截取即可。
将消息分为消息头、消息体。可以在消息头中声明消息的长度,根据这个长度来获取报文(比如 808 协议)。
规定好报文长度,不足的空位补齐,取的时候按照长度截取即可。
多路复用
select
单个进程可监视的fd数量被限制,即能监听端口的大小有限。
对socket进行扫描时是线性扫描,即采用轮询的方法,效率较低:
需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大
poll
大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义
poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。
epoll
没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口);
效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。
内存拷贝,利用mmap()文件映射内存加速与内核空间的消息传递;即epoll使用mmap减少复制开销。
计算机组成原理
组成部分
存储器
内存(主存)
RAM、ROM
外存(辅存)
硬盘、软盘、U盘等
高速缓存
运算器
算术运算
逻辑运算
与、或、非、异或
控制器
输入输出(IO)设备
鼠标、键盘、打印机等
数据表示
进制
二进制
原码、反码、补码
定点数与浮点数
八进制
十进制
十六进制
大数据
以云计算技术为基础,高效处理海量的数据分析
云计算
\'云\' 隐喻互联网,“云计算”其实就是使用互联网来接入存储或者运行在远程服务器端的应用、数据、或者服务,比如云服务器、云数据库等。
三种服务模式: IaaS:Infrastructure as a Service,基础设施即服务;PaaS:Platform as a Service,平台即服务;SaaS:Software as a Service,软件即服务
四种部署模式:私有云、公有云、混合云、社区云
云服务供应商:阿里云、腾讯云、谷歌云、亚马逊云等
开发平台
Hadoop、Spark、zookeeper
流式计算
Storm
Flink
KafKa Stream
Hadoop
HDFS
MapReduce
Yarn
BI商业智能
Superset
CBoard
Redash
安全
WEB安全
XSS
CSRF
SQL注入
Hash Dos
脚本注入
漏洞扫描工具
验证码
DDoS防范
用户隐私信息保护
序列化漏洞
加密解密
对称加密
哈希算法
非对称加密
服务器安全
数据安全
数据备份
网络隔离
内外网分离
登陆跳板机
授权、认证
RBAC
OAuth 2.0
双因素认证(2FA)
单点登录(SSO)
xxl-sso
中间件
Web Server
Nginx
OpenResty
Tengine
Apache Httpd
Tomcat
Jetty
缓存
本地缓存
客户端缓存
服务端缓存
Web 缓存
Memcached
Redis
Tair
消息队列
消息总线
消息的顺序
RabbitMQ
RocketMQ
一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时、高可靠的消息发布与订阅服务
基础组成
NameServer
无状态模式
broker向发心跳顺便带上所有的Topic信息
早期是zk后来改了
Broker
中转消息,消息持久化
底层通信基于Netty
Producer
同步
异步
单向
Consumer
pull
push
支持集群模式
多master
多master多slave异步复制
多master多slave双写
消费保证
发送成功后返回consume_success
回溯消费
高可用
集群
NameService 集群
Broker 主从 双主 双从
Consumer 自动切换
producer 链接两个Broker
刷盘
同步 超时会返回错误
异步 不返回
消息的主从复制
同步复制
异步复制
主从同步 异步刷盘
顺序消息
Hash取模
RocketMQ提供了MessageQueueSelector队列选择机制
顺序发送 顺序消费由 消费者保证
消费者是多线程
消息去重
幂等
去重
消息表主键冲突
分布式事务
最大努力
消息表 不断轮询 人工干预
半消息
发送半消息 发送成功 本地事务 觉得是否提交还是回滚 服务端没收到回查 检查本地事务 根据本地事务决定 提交
2/3pc
最终一致
预发 持久化 返回状态 发送处理结果 判断是否干掉持久化的 发送
完整的一个调用链路
producer 和NameService 节点建立一个长连接
定期从NameService获取Topic信息
并且向Broker Master 建立链接 发送心跳
发送消息给 Broker Master
consumer 从 Mater 和 Slave 一起订阅消息
消息重试
顺序消息重试
无序消息重试
死信队列
消息丢失
消息积压
决定是否丢弃
判断吞吐量
停止消费 加机器 加topic
ActiveMQ
KafKa
一种高吞吐量的分布式发布订阅消息系统
Redis消息推送
ZeroMQ
定时调度
单机定时调度
分布式定时调度
Netty
零拷贝
BIO
阻塞IO 读写都阻塞
问题 带宽 资源等
每个请求过来 开一个线程阻塞
NIO
不阻塞来着不拒,但是可能等待时间太久,响应延迟大了;太短了,会重试
IO多路复用
便捷的通知机制
程序注册一组socket文件描述符给操作系统,表示“我要监视这些fd是否有IO事件发生,有了就告诉程序处理”
select
轮询,数组,判断事件是否可达,然后继续
poll
轮询 链表
epoll
回调 链表 有转态 会创建 文件描述符指向的表 监听增删改查
执行链路
初始化channel
注册 channel到selector
任务队列
轮训accept事件 处理这些建立 channel的链接
注册 channel到selector 接收方
轮训写 事件 开线程去处理
任务队列
线程组
boss
监听端口所有准备就绪的时间
work
监听准备工作
RPC
Dubbo
Dubbo 注册中心
Dubbo 核心配置
Dubbo 底层协议
Dubbo 负载均衡、过滤器、容错、异步调用分析
Dubbo 路由功能详解
Dubbo在分布式项目中的角色
服务暴露过程
IOC 启动加载dubbo配置的标签
解析标签 ServiceBean 会生成一个Bean
实现了 initializingBean
afterpropertiesSet
get provider
set provider
各种信息 保存在 ServiceBean
IOC完成 还实现了一个 ApplicationListener监听器
回调onapplicationEvent
是否暴露 不是延迟暴露
暴露
信息校验 doexport
检查
doexportURL 暴露URL
加载注册中心信息
循环协议 端口
代理工厂获取invoke 封装
暴露invoke
根据spi来
本地暴露
打开 服务器 exchangeServer
启动服务器netty 监听端口
注册中心 注册服务
注册表
执行器
暴露 p 和 s 两个invoker的map保存了地址
spi
服务引用
factoryBean ->getObject ->get
init
信息检查
创建代理对象 createProxy
远程引用 获取到zk 获取到信息 订阅
dubbo 执行远程引用
创建 netty客户端
返回invoke
注册到注册表进去
成功
SPI
java spi
Java 没ioc aop
具体的spi kv形式
静态代理
容错机制
failover
直接切换
failfast
快速失败
failsafe
failback
forking cluster
broadcast cluster
整合 hystrix
失败回调
返回默认
降级
return null
失败返回空
负载均衡
随机 加权
轮询
最少活跃数
hash一致
选举算法
协议
dubbo
默认 nio 单一长连接
二进制系列化 小数据量 100k
数据量中等 不适合文件传输
memcached
redis
webService
http
Thrift
gRPC
数据库中间件
Sharding JDBC
MyCat
MyCat读写分离
MyCat水平切分
MyCat垂直切分
基于MyCat分库分表策略剖析
MyCat全局序列号
MyCat全局表、ER表、分片策略分析
API网关
权限管理
搜索引擎
Lucene
Elasticsearch
Solr
日志系统
0 条评论
下一页