java后端学习路线
2024-04-28 21:11:21 0 举报
AI智能生成
Java后端学习路线是一个系统性的学习计划,旨在帮助开发者掌握Java服务器端开发技能。学习路线包括核心内容:Java基础语法、面向对象编程、集合框架、多线程、I/O流、网络编程、JDBC数据库编程等;通过这条学习路线,你将能够掌握Java后端开发的核心技能,为成为一名专业的后端开发者打下坚实的基础。
作者其他创作
大纲/内容
JavaEE
JavaEE基础
Servlet
生命周期
init方法,初始化调用
service方法,处理客户端请求
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
request
resoponse
seesion
application
exception
out
page
config
request
resoponse
seesion
application
exception
out
page
config
四大作用域
page:表示页面范围
request:表示请求范围
session:表示当前会话范围
application:表示当前Web应用范围
request:表示请求范围
session:表示当前会话范围
application:表示当前Web应用范围
JSTL
使用步骤
1、导入stardard.jar和jstl.jar包中到项目中
2、在jsp页面上使用taglib标签引入,指定前缀和uri
2、在jsp页面上使用taglib标签引入,指定前缀和uri
分类
核心标签库
格式化标签库
SQL标签库
JSTL函数
自定义标签
EL表达式
监听器Listener
分类
ServletRequestListener
ServletRequestAttributeListener
HttpSessionListener
HttpSessionAttributeListener
ServletContextListenser
ServletContestAttibuteListener
配置
web.xml配置listener
@WebListener注解
过滤器Filter
生命周期
init()
初始化,由Servlet容器(如tomcat)创建
doFilter()
处理请求过滤
destory()
销毁,由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对象
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总是采用操作系统默认编码,而firefix总是采用UTF-8编码
XML
XML基础语法
文档声明
约束
DTD约束
Schema约束
XML解析
DOM
JDOM
Dom4J
SAX
websocket
基于TCP,全双工通信协议。可实现服务端消息主动推送,支持各种消息格式
主要API
注解
表示Websocket服务端
@ServerEndpoint
事件处理
@OnOpen,@OnMessage,@OnClose,@OnError
类
扩展配置
javax.websocket.server.ServerEbdpointConfig.Configurator
接口
会话
javax.websocket.Session
消息编码
javax.websocket.Encoder
消息解码
Javax.websocket.Decoder
应用场景
Web聊天室
服务端消息通知
消息服务JMS
API
Message
消息是消息服务器在客户端之间发送的一条条信息。
消息类型
StreamMessage:Java原始值的数据流对象
MapMessage:一套名称-值对
TextMessage:一个字符串对象
ObjectMessage:一个序列化的Java对象
By特殊Message:一个字节数据流
MapMessage:一套名称-值对
TextMessage:一个字符串对象
ObjectMessage:一个序列化的Java对象
By特殊Message:一个字节数据流
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开始传递消息
2)用ConnectionFactory创建Connection;
3)用Connection对象创建一个或多个JMS Session:
4)用JNDI得到目标队列或主题对象,即Destination对象:
5)用Session和Destination创建MessageProducer和MessageConsumer;
6)通知Connection开始传递消息
两种消息传递方式
PERSISTENT:持久化消息,将使用暂存后再转送的机理投递。
NON_PERSISTENT:非持久化消息,最多只能被投递一次。(默认)
NON_PERSISTENT:非持久化消息,最多只能被投递一次。(默认)
分类
点对点模型(P2P)
消息队列Queue
消息生产者(发送者)MessageProducer
消息消费者(接受者)MessageConsumer
同步、异步(通过监听器MessageListener实现)
发布订阅模式(Pub/Sub)
主题Topic
主题发布者TopicPublisher
主题订阅者TopicSubscriber
框架
ActiveMQ
RocketMQ
RabbitMQ
Kafka
命名服务JNDI
事务API JTA
Java Transaction API
用于处理分布式事务
持久化API JPA
邮件服务
JavaMail
Spring JavaMailSender
服务中间件
web服务器
Nginx
核心配置文件nginx.conf
常用命令
nginx -v:查看版本
nginx:启动nginx
nginx -s stop:停止nginx
主要用途
处理静态资源
Nginx处理静态资源的能力很强,效率很高
支持静态资源缓存,如图片、js、css等
反向代理
与正向代理相对
正向代理:内网通过代理服务器访问外网,如VPN
反向代理:外网通过代理服务器访问内网,可以保证内网安全性
反向代理:外网通过代理服务器访问内网,可以保证内网安全性
负载均衡
由于Nginx抗并发能力强,为了减轻Tomcat服务器承受的压力,通常用作Tomcat服务器的负载均衡
可定制化
可以通过编写Lua脚本进行功能扩展
nginx_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_APPLICATION_CONTEXT_ATTRIBUTE
1、在Servlet容器启动后,会创建一个ServletContext(整个Web应用的上下文);
2、由于ContextLoaderListener实现了ServletContextListener,因此会在ServletContext创建完成后,其中的contextInitialized方法会自定被调用,contextInitialized方法中会通过ServletContext实例的getParameter()方法找到Spring配置文件位置,然后根据其中的内容为Spring创建一个根上下文(WebApplicationContext,即通常所说的IOC容器 )
3、将WebApplicationContext作为ServletContext的一个属性放进去,名称是WebApplicationContext.ROOT_APPLICATION_CONTEXT_ATTRIBUTE
IOC
WebApplicationContext:即Spring IOC容器,由容器创建和管理Bean,使用时直接从容器中获取
配置方式
XML配置文件
@Resource/@Autowired注解配置
Bean的作用域
在Spring4中有一下几个作用域:
(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的生命周期
依赖注入的几种fangs
构造注入
属性注入setter
接口注入
FactoryBean和BeanFactory
AOP
动态代理
JDK动态代理(针对接口,代理类为其兄弟类)
目标对象实现了若干接口
CGLIB动态代理(针对类,代理类为其子类)
目标对象没有实现接口
拦截器
事务管理
五大事务隔离级别
七大事务传播特性
事务管理器
核心接口是PlatformTransactionManager
DataSourceTransactionManager:主要用于jdbc和mybatis数据源
HibernateTransactionManager:主要用于Hibernate数据源
编程式事务
通过使用TransactionTemplate或者PlatformTransactionManager相关事务API俩实现事务管理
声明式事务
XML配置<tx:advice>标签
@Transactional注解
异常回滚
只会回滚RuntimeException异常
定时任务调度Spring Task
XML配置<task:scheduler>标签
@Scheduled注解配置
异步任务
XML配置<task:executor>标签
@Async注解配置
缓存支持Spring Cache
Spring 5 新特性
兼容 Java9,最低要求Java 8
响应式编程WebFlux
即Spring-WebFlux,以Reactor库为基础,包含了对响应式HTTP,服务推送时间(Server-Sent Event)和WebSocket客户端和服务器端的支持
基于Java注解编程模型
基于函数式编程模型
Spring Boot
用于快速构建及开发Spring应用,可以看成是Spring框架的简化版
“约定优于配置”思想
配置文件
properties文件
application.properties
yml文件
application.yml
基于注解配置
Spring原有的@controller、@Service、@Component、@Bean、@Configuration等注解、
@SpringBootApplication注解的类
表示整个应用的入口,通常位于项目的顶层包
properties配置文件读取
Spring原有的@Value
与@PropertySource配合使用读取指定配置属性值
缺点:
1、只支持单个属性值读取
2、只支持简单数据类型,如String、Boolean及数值类型
1、只支持单个属性值读取
2、只支持简单数据类型,如String、Boolean及数值类型
Spring Boot新增的@ConfigurationProperties
可以指定配置属性前缀,自动绑定属性值
比@Value功能更强大
1、支持实体属性自动封装;
2、支持复杂数据类型的解析,比如数组、列表List
1、支持实体属性自动封装;
2、支持复杂数据类型的解析,比如数组、列表List
starter简化Maven配置
预先定义好需要的依赖并打包,需要时直接引入即可
所有Spring Boot项目公共的父依赖
spring-boot-starter-parent模块
自动配置AutoConfiguer
为项目添加默认配置
application.propertest/application.yml文件中定义的配置会覆盖默认配置
自带的spring-boot-auto-autoconfigure模块
内置Servlet容器
Tomcat、Jettty、Undertow等
ORM框架
Hibernate
Mybatis
主要组成
Configuration MyBatis配置信息
配置方式
XML文件
注解
SQLSession提供用户对数据库操作的API,完成增删改查
Excutor由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等实现
一般通过自定义缓存Redis,Memcached等实现
MVC框架
Struts2
SpringMVC
基本组成
DispatcherServlet
找到对应请求的HandlerMapping,将请求转发给对应的HandlerAdapter
处理器映射器HandlerMapping
保存请求的URL与Handler(可以使Controller或Servlet等)的对等关系
处理器适配器HandlerAdapter
调用对应的Handler进行处理,并返回ModelAndView对象给DispatcherServlet
拦截器Controller
拦截器HandlerInterceptor
preHandler、postHandler、afterCompletion
HandlerExecutionChain
负责Handler执行前后的HandlerInterceptor的调用
模型视图ModelAndView、模型Model/ModelMap
视图解析器ViewResolver
将逻辑视图转换成物理视图
请求参数解析和封装
RequestMappingHandlerAdapter
HandlerMethodArgumentResolver接口
类型转换
方法返回值处理
HandlerMethodReturnValueHandler接口
文件上传
配置CommonsMultipartResovlver文件上传解析器
MultipartFile对象作为参数接收
全局异常处理
实现HandlerExceptionResolver接口
其他框架
日志框架
作用
用于Java应用日志记录,通常保存到文件中,方便调试跟踪系统运行情况及排查情况
分类
日志门面
Apache的commons-logging
Spring等框架依赖其做日志记录
slf4j
jboss-logging
桥接器(适配器)
slf4j-log4j:slf4j适配log4j
slf4j-logback
slf4j-jdk14
具体实现
log4j
log4j2
logback
JUL
安全框架
Shiro
主要功能
权限控制
身份认证(登录)Authentication
权限验证(授权)Authentication
会话管理
数据加密
常用加密算法
API
当前用户(不一定是人,比如爬虫程序)Subject
安全管理器SecurityManager,shiro的核心
Realm,域,从中获取用户角色,权限信息进行身份认证
Spring Security
定时任务框架
Quartz
Spring Task
工作流引擎
JBPM(Java Business Process Management)
模板引擎
freemarker、velocity、thymeleaf、beetl(国产)
全文搜索框架
Apache Lucene
主要功能
创建及维护索引,提供全文检索服务。支持结果排序及关键字高亮
主要组成
索引保存目录Directory
RAMDirectory:索引存储在内存
FSDirectory:索引存储在磁盘
索引文档Document
Field:StringField只索引不分词,TextField既索引又分词
分词器Analyzer
对于索引内容进行分词
常用分词器
简单分词器SimpleAnalyzer
标准分词器StandardAnalyzer
中文分词器
SmartChineseAnalyser
IKAnalyzer
庖丁分词器PaodingAnalyzer
索引管理器IndexWriter
负责索引文档的创建、更新、删除
查询分析器QueryParser
构造搜索条件并分析
索引阅读器IndexReader
索引搜索器IndexSerarcher
根据搜索条件返回匹配结果
Compass
基于Lucene,ElasticSearch的前身
提供Spring、Hibernate框架继承
ElasticSearch
基于Lucene,分布式的,适用于实时,大数据量的搜索场景
Apache Solr
基于Lucene,适用于常规搜索场景
利用Z噢keeper进行分布式管理
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项目的基本骨架
Maven镜像
阿里云公有镜像http://maven.aliyun.com/nexus/content/groups/public
Maven私服
Maven插件
Ant/Gradle
版本控制工具
SVN
Git
CI持续集成工具
jenkins
常用工具
Google Guava
Apache Commons
Spring 中的工具类
其他常用工具类
Linux基础
目录结构
常用操作命令
帮助命令(man,info,help)
指定运行级别
init切换运行级别
命令终端xshell/putty
vi/vim编辑器
:w(保存)、:q(退出)、:wq(保存并退出),加!号表示强制命令,如:q!表示强制退出;:set nu(显示行号)
文件和目录操作
用户和用户组
useradd(添加一个普通用户)、passwd(修改用户登录密码)、chown(更改文件拥有者)
其他
wget(文件下载,用法:wget[参数]URL
top(性能监控)、ps(查看进程)
文件搜索:find(支持正则)、whereis、which
文本搜索:grep(Global Regular Expression Print,支持正则表达式的全局文本搜索工具)
ifconfig(类似于Windows的ipconfig,获取及修改网路接口配置信息)
时间日期
locate快速定位
压缩解压类
文件编辑器
vi/vim
文件传输
sftp命令
常用命令
sftp<-oPort=port><user>@<host>:链接sftp服务器,其中port默认22,user默认当前用户
put::将本地文件上传到远程服务器
get:将文件从远程服务器下载到本地
cd、pwd、ls、mkdir:远程服务器操作,与Linux系统命令一致;
建立sftp连接后可通过在终端输入help命令查看它操作命令
ftp/sftp客户端软件xftp
软件安装
自己下载安装包
yum install
任务调度和磁盘分区
crontab
分区
分区方式
mbr分区
最多支持四个主分区
系统只能安装在主分区
扩展分区要占一个主分区
MBR最大只支持2TB,但拥有最好的兼容性
gtp分区
支持无线多个主分区(但操作系统可能限制,比如windows下最多128个分区)
最大支持18EB的大容量
windows7 64位以后支持gtp
磁盘使用情况
网路配置
进程管理和服务管理
ps
kill和killall
pstree
service/systemctl(centos7.0后)
chkconfig
动态监控进程
shell语法
数据结构与算法
设计模式
计算机网路
分类
按网络范围
局域网
定义:网络为一个单位所拥有,且地理范围和站点数目均有限。
特点:距离短、延迟小、数据速率高、传输可靠
LAN一班都属于广播性网络
目前常用的LAN类型为Ethernet(以太网)
特点:距离短、延迟小、数据速率高、传输可靠
LAN一班都属于广播性网络
目前常用的LAN类型为Ethernet(以太网)
广域网
在大范围区域内提供数据通信服务,主要用于互连局域网
按网路使用者
公用网
专用网
计算机网络交换类型
电路交换
通信前需要预先在通信双方间建立一条传输通道,通信双方在通信过程中将存在该通道,直到通信结束
实时性强,时延小
报文交换
以报文为数据交换的单位,报文中携带有目标地址、源地址、数据等信息,由交换节点采用存储转发的方式进行数据传输。
不需要为通信双方预先建立一条专用的通信线路
不需要为通信双方预先建立一条专用的通信线路
分组交换
在发送端将较长的报文分割成较短、固定长度的数据段,在每个数据段前加上首部构成分组。
以分组作为数据传输的基本单元,通过存储转发的方式进行传输
以分组作为数据传输的基本单元,通过存储转发的方式进行传输
网络组建
终端设备
在以人为本的网络和通信网络间提供接口
包括手机、台式电脑、笔记本电脑、平板等
中间设备
为主机提供网络连接并连接多个网络形成网际网络
包括路由器、无线路由器、多层交换际、LAN交换机、防火墙设备
网络介质
为消息提供从源传输到目标的通道
包括LAN媒体、WAN媒体、无线介质
分层模型
OSI七层模型
从上到下依次是:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
TCP/IP四层模型
在OSI模型基础上将表示层、会话层合并到了应用层
TCP/IP协议
应用层
提供应用程序网络接口
DNS、FTP、HTTP、POP3、SMTP、Telnet、RPC等
传输层
提供端到端的通信
TCP
传输数据前需要先建立连接。三次握手,四次挥手
TCP建连时为什么是3次握手,而不是2次或4次?
相关概念
SYN
ACK
UDP
不需要建立连接,不能保证数据传输可靠性
常见问题
网络层
寻址和路由
IP、ICMP(ping命令)、ARP(地址解析协议、IP地址解析为物理地址)、RARP(逆地址解析协议、将物理地址解析IP地址)等
网络接口层
提供与底层网络的接口
IP地址
是IP协议提供的的一种统一的地址格式,它为互联网上的每一个网路和每一台主机分配一个逻辑地址,以此来屏蔽物理地址(MAC地址)的差异
IPV4和IPV6
IPV4:32位
IPV6:128位
子网划分
将一个网络划分为更小的网路
IP划分
A类
B类
C类
D类
E类
子网中的主机数
几种简单的协议介绍
ARP(网络层协议)
ICMP协议
TFTP协议
HTTP协议
NAT协议
DHCP协议
其他
单工通信
通信双方中发送发方与接收方分工明确,只能在由发送方向接收方单一固定方向上传送数据
半双工通信
通信双方都既可以是发送方,也可以是接收方,它们之间可以互传数据,但某一时刻只能向一个方向传送数据,如HTTP
全双工通信
通信双方既可以是发送方,也可以是接收方,且双方可以同时在两个方向上传送数据,如WebSocket
计算机操作系统
计算机组成原理
jvm
java及jvm的发展历史
自动内存管理机制
Java内存区域与内存溢出异常
运行时数据区域
程序计数器(Program Counter Register)
也称作PC寄存器。它跟汇编语言中的程序计数器的功能在逻辑上是等同的,用来标识执行的是哪条指令。每个线程都有自己独立的程序计数器,并且相互之间是独立的额。
在JVM规范中规定:
1、如果线程执行的是非native方法,则程序计数器中保存的是当前需要执行的指令的地址;
2、如果线程执行是native方法,则程序计数器中的值是undefined。
1、如果线程执行的是非native方法,则程序计数器中保存的是当前需要执行的指令的地址;
2、如果线程执行是native方法,则程序计数器中的值是undefined。
虚拟机栈(VM Statck)
其中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法,在栈帧中包括局部变量表(Local Variables)、操作数栈(Operand stack)、指向当前方法所属的类的运行时常量池(运行时常量池的概念在方法区部分会谈到)的引用(Reference to runtime constant pool)一级方法返回地址(Return Address)
本地方法栈(Native Method Stack)
存放native方法信息,也就是由C/C++实现的方法
堆(Heap)
这是被所有线程共享的内存区域,其中存放的是对象实例本身以及数组(数组的引用在栈中)
划分
年轻代(Young Generation)
年轻代是用来存放新创建的Java对象。对年轻代的垃圾回收称为“Minor GC”,采用的是复制清除算法、并行收集器。
为使JVM更好的管理堆内存中对象的分配及回收,年轻代又被分为三个区域:Eden、From Survivor、To Survivor。
注意:年轻代可用内存时Eden区+一个Survivor区,另一个Survivor区则保持空闲状态,其中Eden区与一个Survivor区大小比例可以通过-XX:SurvivorRatio参数进行设置,默认为8,标识Eden去与另一个Survivor区大小比值是8:1
为使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等参数调整其大小
1.其中年轻代和年老带位于堆内存,堆内存会从JVM启动参数(如-Xmx:3G表示最大堆内存为3G)指定的内存中分配;
2.Perm Gen 部位与堆内存中,而是属于方法区,由虚拟机直接分配,但可以通过-XX:PermSize -XX:MaxPermSize等参数调整其大小
方法区(Method Area)
用于存储已经被虚拟机加载的类、常量、静态变量、编译器编译后的字节码等数据信息。
在方法区中还包括含有运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。当然并非Class文件常量池中的内容才能进入运行常量池,在运行期间也可以将新的常量放入运行时常量池中,比如String的intern
在方法区中还包括含有运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。当然并非Class文件常量池中的内容才能进入运行常量池,在运行期间也可以将新的常量放入运行时常量池中,比如String的intern
需要注意的是,虽然方法区逻辑上属于堆内存,但是在JVM规范中并没有强制要求对该区域进行垃圾回收
运行时长常量池
属于方法区。用于存储数值型常量
直接内存
对象的创建
指针碰撞
Serial、ParNew等带Compact
空闲列表
CMS基于Mark-Sweep
对象内存布局
对象头
Mard Work
HashCode、GC分代年龄、线程持有的锁、偏向线程ID、偏向时间戳等
类元数据
实例数
对齐填充
对象的访问定位
句柄
直接指针
OutOfMemoryError
java堆溢出
虚拟机栈和本地方法栈溢出
StackOverflowError
OutOfMemoryError
方法区和运行时常量池溢出
本机直接内存溢出
垃圾收集器与内存分配策略
对象已死
引用计数算法
可达性分析算法
作为GC Roots的对象
虚拟机栈中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中JNI(即一般说的Native方法)引用的对象
引用
强引用(Strong Reference)
强引用就是指在程序代码中普通存在的,类似于“Object obj = new Object()”这类的引用,只要强引用还存在,垃圾收集器永远不会回收被引用的对象。
软引用(Soft Reference)
软引用是用来描述一些还有用但并非必需的对象。对于软引用关联的对象,在系统将要发生内存溢出异常之前,将会把这些对象列表进回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。
弱引用(Weak Reference)
弱引用也是用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象
虚引用(Phantom Reference )
虚引用也称幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对齐生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是能在这个对象收集器回收时收到一个系统通知。
垃圾回收算法
标记-清除算法
复制算法
标记-整理算法
分代收集算法
垃圾收集器
Serial
ParNew
Parallerl Scavenge
-XX:MaxGCPauseMillis(最大垃圾收集停顿时间)
-XX:GCTimeRatio(直接设置吞吐量大小)
-XX:+UseAdaptiveSizePolicy
CMS
初始标记
并发标记
重新标记
并发清除
G1
初始标记
并发标记
最终标记
筛选回收
内存分配与回收策略
优先在Eden分配
Minor GC
Major GC/Full GC
大对象直接进入老年代
长期存活的对象将进入老年代
空间分配担保
虚拟机性能监控与故障处理工具
JDK命令行工具
jps
jstat:虚拟机统计信息监视工具
jinfo:java配置信息工具
jmap:java内存映像工具
jhat:虚拟机堆转储快照分析工具
jstack:Java堆栈跟踪工具
JConsole:Java监控与管理控制台
VisualVM:多合一故障处理工具
虚拟机执行子系统
类文件格式
类加载机制
加载过程
步骤:
1、加载:类加载器从类的.class文件读取二进制流到内存,并为之创建java.lang.Class对象,作为访问Class文件中的各种数据的入口,如反射机制。
2、连接:把类的二进制数据存储到虚拟机各个内存区域中。
1)验证:目的是确保当前Class文件中内容符合JVM规范的要求,并且不会危害虚拟机自身安全。主要包括文件格式验证、元数据验证、字节码验证、符号引用验证。
2)准备:为静态变量分配内存并设置类变量的默认值(如int、float的默认值是0,引用类型的默认值是null。特别地,对于final修饰静态变量,rufinal static int a = 20则在此阶段结束a的值为20)
3)解析:将常量池中符号引用替换为直接引用
3、初始化:为静态变量赋予正确的初始值。如对于代码static int i = 20,准备阶段结束后i的值是0,此阶段结束后i的值才变为20.
4、使用
5、卸载
1、加载:类加载器从类的.class文件读取二进制流到内存,并为之创建java.lang.Class对象,作为访问Class文件中的各种数据的入口,如反射机制。
2、连接:把类的二进制数据存储到虚拟机各个内存区域中。
1)验证:目的是确保当前Class文件中内容符合JVM规范的要求,并且不会危害虚拟机自身安全。主要包括文件格式验证、元数据验证、字节码验证、符号引用验证。
2)准备:为静态变量分配内存并设置类变量的默认值(如int、float的默认值是0,引用类型的默认值是null。特别地,对于final修饰静态变量,rufinal static int a = 20则在此阶段结束a的值为20)
3)解析:将常量池中符号引用替换为直接引用
3、初始化:为静态变量赋予正确的初始值。如对于代码static int i = 20,准备阶段结束后i的值是0,此阶段结束后i的值才变为20.
4、使用
5、卸载
类加载器
BootStatrpClassLoader
启动类加载器:负责加载java基础类,主要%JAVA_HOME/jre/lib/rt.jar中的类。它是用C++语言写的。
由JVM启动,然后初始化sun.misc.Launcher,sun.misc.Launcher初始化Extension ClassLoader、App ClassLoader。
由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方法来避免双亲委托机制
基础语法
基础语法
数据类型
8中基本数据类型
数值型
整型
byte
short
int
long
浮点型
float
double
字符型char
布尔型boolean
引用类型
类
接口
数组
枚举类型enum
类型转换
基本类型转引用类型
运算符与表达式
算术运算符
关系运算符
赋值运算符
位运算符
移位运算符
流程控制结构
顺序结构
选择结构
循环结构
方法重载Overload
针对同一个类或接口而言
同一个类中多个同名方法之间参数列表必须不同。与返回值是否形同无关
方法重写/覆盖Override
以继承为基础,子类可以覆盖父类实现的方法,实现自己的功能
1、要保证子类中重写的方法签名要和父类一致,即返回值,方法名,参数列表必须完全一致;
2、子类抛出的异常不能超过父类相应方法抛出的异常(子类异常不能大于父类异常);
3、子类中重写的方法访问控制权限不能低于父类
2、子类抛出的异常不能超过父类相应方法抛出的异常(子类异常不能大于父类异常);
3、子类中重写的方法访问控制权限不能低于父类
不允许方法重写的两种特殊情况
private关键字修饰的方法
final关键字修饰的方法
面向对象
对象
在软件系统中视一切事物皆为对象,不仅包括现实中客观存在的事物,还包括抽象的东西
类
对于同一类型对象的抽象表达
接口
对行为的抽象表达,可以看作是一种协议
其中仅包括对行为的定义,不包含具体实现
三大特性
封装
对内将对象具有的特征与行为进行统一管理;
对外隐藏实现细节,仅提供公开接口
对外隐藏实现细节,仅提供公开接口
属性
用于表达对象具有的某些特征,如大小、颜色等
方法
定义一系列对属性进行操作的行为
继承/派生
用于子类对父类的功能的扩展
表现形式
子类继承父类
子类实现接口
多态
即多种形式,通常表现与接口或抽象类中抽象方法的不同实现
表现形式就是方法重写
七大设计原则
单一职责原则
简单而言,就是使类所具有的功能尽量单一
开闭原则
对扩展开放,对修改关闭
依赖倒转原则
抽象不应该依赖细节,细节应该依赖于抽象
针对抽象(抽象类或接口)编程,而不是针对实现编程。
里氏替换原则
所有引用基类(父类)的地方必须能透明地使用其子类对象
接口隔离原则
使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
接口隔离原则与单一职责原则区别:
其一,单一职责原则注重的是职责;而接口隔离原则注重对接口依赖的隔离。
其二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;
而接口隔离原则则主要约束接口,主要针对抽象,针对程序整体框架的构建。
其一,单一职责原则注重的是职责;而接口隔离原则注重对接口依赖的隔离。
其二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;
而接口隔离原则则主要约束接口,主要针对抽象,针对程序整体框架的构建。
合成复用原则
复用时要尽量使用组合/聚合关系(关联关系),少用继承
迪米特法则
一个软件实体应当尽可能少地与其他实体发生相互作用,低耦合。(不要和“陌生人”说话)
UML建模(visio工具)
常用几类图:包括类图、用例图、时序图、状态图
常用包
java.lang、java.io、java.util
java.lang.reflect、java.net、java.nio、java.util.concurrent
AWT
Abstract Window Toolkit,抽象窗口工具包,该包提供了一套与本地图形界面进行交互的接口,是java提供的用来建立和设置java的图形用户界面的基本工具
Swing
对AWT的扩展,更好的实现java图形化编程
IO
区分阻塞、非阻塞、同步、异步
阻塞:等待结果返回,当前线程被挂起,后续操作被阻断
非阻塞:不等待返回结果,直接执行后续操作
非阻塞:不等待返回结果,直接执行后续操作
同步:轮询模式
异步:监听模式
异步:监听模式
序列化与反序列化
序列化
序列化类型
JDK Serializeable 对象序列化
ObjectInputStream、ObjectOutputStream
JSON序列化
Fastjson、Jackson、Gson、等库
XML序列化
XStream、JAXB等
序列化协议
反序列化
IO(同步阻塞IO)
字节流/字符流
对象序列化
实现Serializable接口
readObject(ObjectInputStream ois)、writeObject(ObjectOutStream oss)方法
文件操作(磁盘读写)
创建/删除文件
读/写文件
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、非线程安全
比如ByteBuffer就是对byte数组进行的分装,是的操作起来方便。
1、使用的是堆外内存,不受GC管理(GC主要是堆内存)
2、非线程安全
Netty/Mina框架
基于NIO的高性能网路框架,通常用于分布式应用开发中进行网路数据传输
AIO(异步非阻塞IO)
输入流/输入流
字节流/字符流
网路编程
Socket
基于TCP/UDP,他是为进行TCP/UDP编程提供的API
URL、URLConnection、HttpURLConnection
InetAddress
反射机制
涉及到的类或接口
Class(表示一个类或接口)、Constructor(构造方法)、Method(方法)、Field(对应接口或类中的属性)。
Modifier(修饰符private、protected、public、static、final等)、ParameterizedType(泛型参数类型)等
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)
1、CONSTRUCTOR:用于描述构造器
2、FIELD:用于描述字段
3、LOCAL_VARIABLE:用于描述局部变量
4、METHOD:用于描述方法
5、PACKAGE:用于描述包
6、PARAMETER:用于描述参数
7、TYPE:用于描述类、接口(包括注解类型)或enum声明
如:@Target(ElementType.TYPE)
@Retention
用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
取值(RetentionPoicy)有:
1、SOURCE:在源文件中有效(即源文件保留)
2、CLASS:在class文件中有效(即class保留)
3、RUNTIME:在运行时有效(即运行时保留)
如:@Retention(RetentionPolicy.RUNTIME)
1、SOURCE:在源文件中有效(即源文件保留)
2、CLASS:在class文件中有效(即class保留)
3、RUNTIME:在运行时有效(即运行时保留)
如:@Retention(RetentionPolicy.RUNTIME)
@Documented
将此注解包含在javadoc中,它代表着此注解会被javadoc工具提取成文档
@Inherited
允许子类继承父类的注解
@Repeatable(java8新增)
允许注解使用多次
内建注解
@Override
供编译器检查、保证方法重写正确
@Deprecated
标记过时的方法或类型,并建议在javadoc指明替代方法或类型
@SuppressWarning
使编译器忽略警告
@FunctionInterface(Java8新增)
供编译器检查,接口是否满足函数式接口条件
自定义注解
区别于接口定义,使用@interface进行声明
泛型
?通配符
只读型容器
定界符super、extends
多线程、并发编程
线程与进程
线程是程序最小执行单元
进程是操作系统进行资源分配和调度的一个基本单位
关联:一个程序至少有一个进程,一个进程又至少包括一个线程。进程中的多个线程共享的资源
引入线程的目的:充分利用CPU资源,使其可以并行处理多个任务,减少时间消耗、提高效率
线程分类
用户线程User Thread
一般是程序中创建的线程
守护线程Demon Thread
为用户线程服务的线程,当所有用户线程结束时才会被终止。如JVM的垃圾回收
通过Thread的setDeamon(true)方法将一个用户线程变成守护线程
线程的周期
新建状态NEW
Thread类
实现了Runnable接口
run方法,无返回值
Runnable接口
run方法,无返回值,通过Thread类或线程池来使用
Callable接口
作为FutureTask构造方法参数使用
call方法,有返回值,且可以抛出异常
call方法实际是在Runnable的run方法中被执行的
就绪状态(Runnable)
调用新建线程的start()方法
不一定会运行,可能需要等待CPU分配时间片
阻塞状态(Blocked)
调用Object的wait的方法后等待同步锁的状态
等待Waiting
发生在调用一下几个方法时:
不带参数的Object.wait()
不带参数的Thread.join()
LockSupport.park()
不带参数的Object.wait()
不带参数的Thread.join()
LockSupport.park()
超时等待Timed-Waiting
与Waiting状态不同在于不会一直等待,而是等待指定的时间
发生在调用以下几个方法时:
Thread.sleep(long millis)
Object.wait(long timeout)
Thread.join(long timeout)
LockSupport.parkNanos()
LockSupport.parkUtil()
Thread.sleep(long millis)
Object.wait(long timeout)
Thread.join(long timeout)
LockSupport.parkNanos()
LockSupport.parkUtil()
终结状态Terminated
当线程运行完毕,即死亡
Thread类常用的方法
Thread.sleep(long millseconds)方法
1、sleep方法是Thread类的静态方法,是为了保证该操作只对当前线程有效,避免线程安全问题,其他几个常用静态方法类似。
2、让当前正在运行的线程暂时停止运行,一段时间后会继续执行。
2、让当前正在运行的线程暂时停止运行,一段时间后会继续执行。
Thread.yield()方法
当前处于运行状态的线程主动放弃占用的CPU资源,转变为就绪状态,让其他线程执行(让步)
join方法
在当前线程执行过程中引入另一个线程,并且当前线程需要等待另一个线程执行完毕后才能继续执行
可用于实现多个线程执行。如t.join()表示当前线程阻塞,直到线程t执行完成当前线程才能继续执行
Thread.currentThread()方法
获取当前正在运行的线程
线程间通信
共享变量
等待/通知机制
Object的对象监视器方法
这三个方法依赖于对象监视器,所以必须在synchronized语句块内使用,否则会抛出IllegalMonitorStateException
wait方法
使得当前线程必须要等待(阻塞状态),等待另外一个线程调用notify()或者notifyAll()方法
notify方法
唤醒一个等待当前对象的锁的线程(一般是高优先级的线程)开始排队
notifyAll方法
方法会唤醒其他所有等待当前对象的线程
Lock、Condition
Lock的lock、tryLock、unlock、getCondition等方法
Condition的await、signal、signalAll方法
使用volatile关键字
数据传递
PipedInputStream/PipedOutputStream管道流
BlockingQueue阻塞队列
Exchanger交换器
停止线程的方法
Thread.stop方法:已废弃
使用一个标识来表示线程的状态,通过更改它的值来控制线程的运行和停止
interrupt中断方法
同步关键字
synchronized
在JVM层面实现了对临界资源的同步互斥访问,锁的释放不用人工干预,由虚拟机自定完成。
在volatile基础上增加了互斥锁,所谓“互斥”就是同一时间只能一个线程操作该资源;
在JDK1.5版本以后,为了弥补synchronized的不足,引入了Lock来代替他,将同步锁对象换成了Condition对象,并且对象可以有多个
在JDK1.5版本以后,为了弥补synchronized的不足,引入了Lock来代替他,将同步锁对象换成了Condition对象,并且对象可以有多个
用法
同步代码块
通常将外界资源作为锁的对象
用于保护外界资源不被多个线程并发修改
与同步方法比较而言,使用同步代码块的好处在于其他线程仍可以访问同步代码块以外的代码
同步方法
锁的对象是当前对象的this
用于保护对象属性值不会被多个线程并发修改
同步静态方法
锁的对象是类的Class对象
用于保护类的静态属性值不会被多个线程并发修改
缺点
1、无法知道是否成功获取锁
2、如果是多个线程需要同时进行读操作,一个线程读操作时其他线程只有等待
2、如果是多个线程需要同时进行读操作,一个线程读操作时其他线程只有等待
注:为了确保所有线程都能看到共享变量的最新值,因此所有执行读操作或写操作的线程都必须在同一个锁上同步
volatile
线程每次都从主内存中读取变量,改变后再写回到主内存。其作用如下:
1、使变量在多个线程间具有可见性(volatile变量不会被缓存到寄存器或其他对处理器不可见的地方)
2、禁止JVM对该变量的操作进行指令重排序(保证有序性)
1、使变量在多个线程间具有可见性(volatile变量不会被缓存到寄存器或其他对处理器不可见的地方)
2、禁止JVM对该变量的操作进行指令重排序(保证有序性)
使用条件
1、对变量的写操作不依赖于变量的当前值,或者保证仅有一个线程对变量进行写操作;
2、该变量不会和其他状态变量一起被纳入不变性条件中;
3、访问变量不需要加锁。
2、该变量不会和其他状态变量一起被纳入不变性条件中;
3、访问变量不需要加锁。
应用场景
一写多读,保证变量可见性
开销较低的读写锁策略
将变量使用volatile关键字修饰,只在多个线程同时需要进行写操作时加锁,读操作不需要
加锁方式
synchronized关键字
使用Lock
volatile VS synchronized
访问volatile变量是不需要枷锁,因此不会阻塞线程,因此它是比synchronized更轻量的同步机制。
但是volatile不能完全替代synchronized,因为它不能保证原子性,非线程安全,而加锁机制既可以确保可见性,又可以确保原子性。
但是volatile不能完全替代synchronized,因为它不能保证原子性,非线程安全,而加锁机制既可以确保可见性,又可以确保原子性。
线程死锁
死锁产生的四个必要条件
互斥条件:资源不能被共享。即任一时刻一个资源只能给一个进程使用,其他进程只能等待,直到资源被占有者释放。
不可剥夺条件:已经分配的资源不能从相应的进程中被强制地剥夺,而只能由获得该资源的进程自愿释放
请求和保持条件:已经得到资源的京城可以再次申请新的资源
循环等待条件:系统中若干进程组成环路,该环路中每个进程都在等待相邻进程正占用的资源
不可剥夺条件:已经分配的资源不能从相应的进程中被强制地剥夺,而只能由获得该资源的进程自愿释放
请求和保持条件:已经得到资源的京城可以再次申请新的资源
循环等待条件:系统中若干进程组成环路,该环路中每个进程都在等待相邻进程正占用的资源
预防死锁的方法
合理对资源进行动态分配,以避免死锁
破坏死锁产生的四个必要条件
定时任务
Timer & TimerTask 类
Timer:任务调度器,通过schedule(TImerTask task,long delay)等方法进行调度。
TimerTask:实现了Runnable接口。表示需要调度的任务,里面有一个run方法定义具体的任务。
TimerTask:实现了Runnable接口。表示需要调度的任务,里面有一个run方法定义具体的任务。
Timer缺点:内部是单线程,因此如果有异常产生,线程将退出,整个定时任务就会失败。
线程池
ScheduledExecutorService,它是ExecutorService的子接口。弥补了Timer的缺陷
线程池
ScheduledExecutorService,它是ExecutorService的子接口,弥补了Timer的缺陷
通过
scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)
和
scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)
等方法来实现定时任务
scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)
和
scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)
等方法来实现定时任务
异步任务
只需创建并启动一个线程执行该任务即可,如果需要获取执行结果,则用Callable。也可以使用线程池
Callable<V>接口
表示一个带有返回结果的任务
通常通过ExecutorService来使用
Future<V>接口
包装异步任务的返回结果
常用方法
boolean isDone():用于判断任务是否执行完成
V get();获取执行结果
FutureTask
实现了Future和Runnable接口,表示一个异步任务
CompletableFuture
并发编程
相关理论
重排序
为了提高程序执行性能,编译器(编译期)和CPU(运行期)会对指令进行重排序
三大特性
原子性
线程对共享变量的操作是原子性操作,就是说该操作或多个操作,要么都成功要么都失败
对于复合操作而言,synchronized关键字可以保证原子性,而volatile关键字不能
可见性
线程对共享变量的修改对其他线程立即可见
synchronized和volatile关键字都能保证可见性
有序性
程序代码执行的结果不受JVM指令重排序的影响
由于volatitle关键字可以禁止指令重排序,因此能保证有序性
Lock锁机制可以同时保证以上三个特性
java内存模型(JMM)
关键概念
共享内存
即主存,所有线程共享
本地内存(线程)
也称为“工作内存”。JVM给每个线程都分配了一块内存区域,该块内存时线程独有的。
从架构上看,类似于计算机硬件架构中CPU与内存建的高速缓存
JMM规定:线程不能直接操作主存,而是只操作属于自己的那部分内存。如果多个线程间需要进行变量共享,必须经过主存
由于JMM的限制,线程操作变量需要经过以下几个基本步骤:
1、从主存中读取变量放入工作内存;
2、在工作内存中对变量进行修改操作;
3、将操作后的结果同步回主存
1、从主存中读取变量放入工作内存;
2、在工作内存中对变量进行修改操作;
3、将操作后的结果同步回主存
Happens-Before原则
如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在Happens-Before关系。
线程安全问题
衡量标准:如果一段程序在多线程环境下多次执行的结果总是与预期一致,就是线程安全,反之则是线程不安全
所谓线程安全问题,其本质在于线程对共享变量操作的原子性,可见性、有序性不能同时满足、因此解决线程安全问题的关键就在于使其同时满足该三个特性
Unsafe类
该类提供了在Java中能够像C/C++语言使用指针直接操作内存的功能,由于直接操作内存可能会发生风险,因此Java官方不建议直接使用该类,也没有提供关于该类的文档。但是在JDK源码中为了提高运行效率在很多地方都使用了该类
包含的功能
内存管理
包括分配内存,释放内存,获取变量内存地址偏移量,通过变量地址偏移量获取和修改变量值等
线程挂起与恢复
park、unpark方法
CAS无锁技术
CAS即Compare And Swap,比较并交换。属于乐观锁的一种实现方式
通过JNI调用CPU的CAS指令实现,在硬件层间实现了原子性
它是并发包中锁机制和原子操作类实现的底层基础
实现原理
CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。
当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
若操作成功则返回结果,否则会进行重式直到成功为止。
当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
若操作成功则返回结果,否则会进行重式直到成功为止。
缺点
只能保证对一个共享变量进行原子操作
如果要多个共享变量的原子操作,需要用到锁机制
解决方法
并发包中引入了针对引用类型的原子操作类(如AtomicReference,AtomicReferenceArray)。
因此我们可以将多个变量放到同一个对象中,然后用引用类型的原子操作类来操作也可以保证原子性
因此我们可以将多个变量放到同一个对象中,然后用引用类型的原子操作类来操作也可以保证原子性
ABA问题
当一个值从A变成B,又从B变成A,这种情况下,CAS会认为值没有发生过变化,但实际上是变化的。
解决办法
并发包中的AtomicStampedReference类
高并发时效率降低
由于存在自旋锁(spin lock)机制,会导致CAS的失败次数会增多,从而引起更多线程的重试
解决办法
在高并发情况下,使用Java8中新增的四个类:DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder
ThreadLocal(线程本地变量)
它为每个线程都提供一个独立的变量副本,各个线程都可以改变自己的变量副本,各个线程间互不影响。
实现的思路:
1)在ThreadLocal类中有一个静态内部类ThreadLocalMap,用于存储每一个线程的变量副本,键为当前ThreadLocal对象,而值则是对应线程的变量副本;
2)每个ThreadLocal实例都有一个唯一的threadLocalHashCode(这个值将会用于在ThreadLocalMap中找到ThreadLocal对应的value)。
1)在ThreadLocal类中有一个静态内部类ThreadLocalMap,用于存储每一个线程的变量副本,键为当前ThreadLocal对象,而值则是对应线程的变量副本;
2)每个ThreadLocal实例都有一个唯一的threadLocalHashCode(这个值将会用于在ThreadLocalMap中找到ThreadLocal对应的value)。
工作原理
注:
1、ThreadLocal的目的不是解决线程共享变量问题,而是隔离线程。每个线程访问都是属于自己的变量,因此避免了线程安全问题。
2、ThreadLocal使用于变量需要在线程间隔离而在方法间需要共享的场景。
1、ThreadLocal的目的不是解决线程共享变量问题,而是隔离线程。每个线程访问都是属于自己的变量,因此避免了线程安全问题。
2、ThreadLocal使用于变量需要在线程间隔离而在方法间需要共享的场景。
内存泄漏问题
原因
解决办法
当我们使用完ThreadLocal变量的时候,记得调用其remove()方法,以避免内存泄漏
JUC
线程池(Executor)
线程池的作用
1、减少资源消耗。通过重复利用池中已创建的线程,减少频繁创建、销毁线程带来的资源消耗。
2、提高响应速度。当线程池中有空闲线程,任务到来时无需创建线程就能立即被执行。
3、提高线程的可管理性。由线程池对池中的线程进行统一的管理和监控,可以防止无限制创建线程造成资源浪费。
2、提高响应速度。当线程池中有空闲线程,任务到来时无需创建线程就能立即被执行。
3、提高线程的可管理性。由线程池对池中的线程进行统一的管理和监控,可以防止无限制创建线程造成资源浪费。
Executor接口
其中只有一个void execute(Runnable task)方法,用于执行任务
ExecutorService接口
Executor接口的子接口
扩展了Executor的功能,提供了管理线程的方法,并且提供了一系列能返回Future对象的异步任务创建方法
常用方法
shutdown(),shutdownNow()
通过关闭线程池来拒绝处理新任务
shutdown与shutdownNow的区别在于后者会立即关闭,不会等待正在执行的任务执行玩不
isShutdown()、isTerminated()
获取线程池是否被关闭的状态
<T> Future<T> submit(Callable<T> task)
<T> Future<?> submit(Runnable task)
<T> Future<T> submit(Runnable task,T result)
<T> Future<?> submit(Runnable task)
<T> Future<T> submit(Runnable task,T result)
向线程池提交一个任务,并返回一个Future对象用于回去执行结果
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
向线程池提交一个任务集合,执行结合中一个或多个Future
ThreadPoolExecutor
是线程池的真正实现,通过在构造方法传入不同的配置参数来创建不同的线程池
核心配置参数
corePoolSize
核心线程数
线程池中存活的最少线程数量,除非allowCoreThreadTimeOut属性值被设成true那么最少就是0
maximumPoolSize
最大线程数
线程池中最多能容纳的线程数量
keepAliveTime
指定空闲线程的存活时间,目的是为了减少资源消耗
在一下两种情况下生效:
1、当线程池中线程数大于corePoolSize,多余的空闲线程达到keepAliveTime指定的时间会被停掉;
2、当allowCoreThreadTimeOut值为true,核心线程空闲时间达到keepAliveTime指定的时间也会被停掉
1、当线程池中线程数大于corePoolSize,多余的空闲线程达到keepAliveTime指定的时间会被停掉;
2、当allowCoreThreadTimeOut值为true,核心线程空闲时间达到keepAliveTime指定的时间也会被停掉
workQueque
任务队列,BlockingQueue类型
用于存放待执行的任务,可以是有界队列或无界队列
handler
任务拒绝策略,RejectedExecutionHandler类型
用于处理线程池无法执行的任务
4中实现
AbortPolicy 默认策略,直接抛出RejectExecutionException异常
CallerRunsPolicy 使用调用线程去处理任务
DiscardPolicy 什么事都不干,相当于丢弃任务
DiscardOldestPolicy 移除队列头部的任务,然后再次尝试执行当前任务
当发生以下两种情况,就会执行任务拒绝策略:
1、任务队列满,同时达到最大线程数maximuPooSize;
2、线程池已经被shutdown,无法执行新任务。
1、任务队列满,同时达到最大线程数maximuPooSize;
2、线程池已经被shutdown,无法执行新任务。
工作原理
线程池被创建的时候里面是没有线程的,除非调用了prestartAllCoreThreads()方法。
1、当有任务需要执行并且线程池中线程数量小于corePoolSize时,新创建一个线程去执行这个任务。
2、当线程数量达到corePoolSize,并且小于MaximumPoolSize时,分两种情况:
(1)、若任务队列未满,则将后续任务放入任务队列;
(2)、若任务对列已满,则新创建一个线程去执行任务,直到达到最大线程数maximumPoolSize;
3、达到最大线程数maximumPoolSize后,后续来的任务将会被执行拒绝任务策略
1、当有任务需要执行并且线程池中线程数量小于corePoolSize时,新创建一个线程去执行这个任务。
2、当线程数量达到corePoolSize,并且小于MaximumPoolSize时,分两种情况:
(1)、若任务队列未满,则将后续任务放入任务队列;
(2)、若任务对列已满,则新创建一个线程去执行任务,直到达到最大线程数maximumPoolSize;
3、达到最大线程数maximumPoolSize后,后续来的任务将会被执行拒绝任务策略
Fork/Join(多线程并行框架)
JDK7.7引入的支持多核CPU的多线程并行框架,以充分利用多核CPU的优势。
通过它可以实现多线程在多个CPU核心中并行处理任务。
通过它可以实现多线程在多个CPU核心中并行处理任务。
利用分而治之的思想,将大任务分成小任务执行,然后合并结果;分别对应fork、join两个操作。
Fork/Join框架的核心是ForkJoinPool类,它是对AbstractExecutorService类的扩展。
ForkJoinPool实现了工作窃取(work-stealing)算法,并可以执行ForkJoinTask任务。
ForkJoinPool实现了工作窃取(work-stealing)算法,并可以执行ForkJoinTask任务。
Executors工具类
包含一系列创建线程池的工厂(静态)方法,简化线程池的创建
常用方法
Callable<Object> callable(Runnable task)
<T> Callable<T> callable(RUnnable task,T task)
<T> Callable<T> callable(RUnnable task,T task)
包装Runnable类型的线程为Callable类型
newSingThreadExecutor()
创建一个只有单个工作线程的线程池,使用的队列是无界队列
newFixedThreadPool(int nThreads)
创建固定大小的线程池
newCachedThreadPool()
创建一个可根据需要创建线程的线程池,但是可以重用已经创建好的线程。
注:它使用的是SynchronousQueue作为任务队列
注:它使用的是SynchronousQueue作为任务队列
newScheduleThreadPool(int corePoolSize)
创建一个指定大小的线程池,用于定时或周期性的执行任务
newSingleScheduledThreadExecutor()
创建一个单线程化的线程池,用于定时或周期性的执行任务
newWorkStealingPool()
newWorkStealingPool(int parallelism)
newWorkStealingPool(int parallelism)
Java 8新增,创建使用Fork/Join框架执行任务的线程池
线程池大小配置
一般需要根据任务类型来配置线程池大小:
1、如果是CPU密集型任务,就需要尽量压榨CPU,参考值可以设为Ncpu + 1
2、如果是IO密集型任务,参考值可以设置为2*Ncpu
1、如果是CPU密集型任务,就需要尽量压榨CPU,参考值可以设为Ncpu + 1
2、如果是IO密集型任务,参考值可以设置为2*Ncpu
通过Runtime.getRuntime().availableProcessors()获得当前CPU个数
并发容器
ConcurrentHashMap
由于HashMap在多线程并发put操作情况下的rehash会导致死循环,Java7引入了分段锁技术segment来保证一定的线程安全,Segment继承于ReentrantLock
为了进一步提高并发性及访问效率,Java8采用CAS 替代了segment,同时加入了红黑树(当链表中节点数达到临界值8时就将其转成红黑树)
BlockingQueue
阻塞队列:
1、当队列为空时,获取元素的线程会等待,直到队列中有元素;
2、当队列满时,存储元素的线程会等待,直到队列可以存储元素。
通常用于生产者-消费者场景
1、当队列为空时,获取元素的线程会等待,直到队列中有元素;
2、当队列满时,存储元素的线程会等待,直到队列可以存储元素。
通常用于生产者-消费者场景
ArrayBlockingQueue
有界队列,即队列容器有限,内部是数组结构
LinkedBlockingQueue
既可以是有界队列,又可以是无界队列,内部是单向链表结构。若创建时不指定容量,则默认是Integer.MAX_VALUE
SynchrousQueue(同步队列)
不保存元素,仅仅作为两个线程进行单向数据通信(如生产者/消费者场景)的临时通道
PriorityBlockingQueue(优先级阻塞队列)
属于无界队列,队列中的元素按优先级排列
使用了和PriorityQueue一样的排序规则,同时具备BlockingQueue的特性
通过在构造方法传入Comparator比较器来决定元素排序;
如果不提供比较器,则采用自然排序(即通过Comparable的compareTo方法,因此插入队列中的元素必须实现Comparable接口)
如果不提供比较器,则采用自然排序(即通过Comparable的compareTo方法,因此插入队列中的元素必须实现Comparable接口)
CopyOnWriteArrayList
从字面上看就是“写时复制”。原理是当需要对集合中元素进行增删改操作时先复制一个副本,对副本进行操作。
适用于“读多写少”的并发场景
并发工具
CountDownLatch(倒计数器)
利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他几个任务执行完毕之后才能执行,就可以使用CountDownLatch来实现。
内部使用了AQS的共享锁机制
两个关键方法:
1.await()当前线程等待其他线程执行完毕(即计数器减到0),当前线程恢复执行;
2.countDown()当有一个线程执行完毕就将计数器减1,直到减到0.
1.await()当前线程等待其他线程执行完毕(即计数器减到0),当前线程恢复执行;
2.countDown()当有一个线程执行完毕就将计数器减1,直到减到0.
应用场景:模拟多个线程并发
CyclicBarrier(会换栅栏)
通过它可以实现让一组线程等待至某个状态之后再全部同时执行。
叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用(通过调用reset()方法)。
叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用(通过调用reset()方法)。
await()方法,此方法作用是等待其他线程都到同一状态时开始同时执行。
Semaphore(信号量)
用于限制访问的最大线程数
维护一个访问许可集,其大小由初始化时的构造器参数指定
主要方法
通过acquire和release方法获取和释放访问许可。其获取的方式有公平和非公平两种,默认是非公平
acquire(int permits)、tryAcquire(int permits) 获取指定数量的访问许可,相当于在可用的数量上减去
release(int permits),tryRelease(int permits) 释放指定数量的访问许可,相当于在可用数量上增加
ExChanger(交换器)
用于成对的线程间进行数据交换,可以看成是一个双向的SynchronousQueue
V exchange(V x)方法
V exchange(V x,long time,TimeUnit unit)方法
原子操作类(atomic子包)
位于java.util.concurrent.atomic包,使用CAS实现的原子操作
基本类型 如AtomicInteger、AtomicLong、AtomicDouble的等
数组类型 如AtomicIntegerArray、AutomicDoubleArray等
引用类型 如AtomicReference、AtomicReferenceFieldUpdater等
比synchronized控制的粒度更细、量级更轻(所采用的自旋锁是一种轻量级锁),并且在多核处理器具有高性能
Java8又增加了四个类
DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder
弥补原有的Atomic系列类的不足:
虽然通过CAS保证了并发时操作的原子性,但是在高并发情况下,由于存在自旋锁(spin lock)机制,会导致CAS的失败次数会增多,从而引起更多线程的重试,最后导致效率降低
虽然通过CAS保证了并发时操作的原子性,但是在高并发情况下,由于存在自旋锁(spin lock)机制,会导致CAS的失败次数会增多,从而引起更多线程的重试,最后导致效率降低
LongAdder VS AtomicLong 较低并发时两个类效果差不多,而高并发时使用LongAdder更有效,但也会消耗更多的空间
显示锁(locks子包)
Condition/ConditionObject
提供了类似Object类中wait、notify、notifyAll的方法,主要包括await、singal、singalAll方法
与synchronized和wait、notify、notifyAll的搭配类似,这些方法与Lock锁配合使用也可以实现等待/通知机制
LockSupport工具类
用于操作线程,是锁和同步类的基础。基于Unsafe中park、unpark实现
用来代替wait、notify、notifyAll。
因为LockSupport对park方法和unpark方法的调用没有先后限制,而wait方法必须保证在notify/notifyAll之间被调用
因为LockSupport对park方法和unpark方法的调用没有先后限制,而wait方法必须保证在notify/notifyAll之间被调用
park()、parkNaos(long timeout)、parkUntil(long deadLine)方法表示将当前线程挂起,后两个表示挂起一段时间
unpark(Thread Thread)方法取消指定线程thread挂起
AQS同步器
AbstractQueuedSynchronizeizer类的简称
实现了线程同步的语义,是Java中Lock锁机制的基础。
通过它可以实现同步器
通过它可以实现同步器
核心思想:
1、基于volatitle类型的state变量,配合Unsafe类的CAS操作来实现对当前锁状态state进行修改:
2、内部依赖一个双向队列来完成资源获取线程的排队工作。
1、基于volatitle类型的state变量,配合Unsafe类的CAS操作来实现对当前锁状态state进行修改:
2、内部依赖一个双向队列来完成资源获取线程的排队工作。
其中定义了两种获取锁的方式
共享方式SHARED
同一时间可以有多个线程获得锁,多个线程共享一把锁
采用共享方式得到的锁即为共享锁
适用于多个线程同时进行读操作场景
排他方式EXCLUSIVE
同一时间只能有一个线程获取到锁
采用排他方式得到锁即为排他锁,也称为独占锁
使用于多个线程同时进行写操作时同步
Lock体系
JDK层面实现,比起synchronized可控性更强,弥补了synchronized的不足。使用后必须手动释放锁,否则会导致死锁
lock:如果没获取到,会一直阻塞直到成功获取到锁;
tryLock:藏尸获取锁,获取到则返回true;如果没获取到怎返回false,不会一直阻塞,可以指定等待时间;
unlock:释放锁。
都需要显示调用
tryLock:藏尸获取锁,获取到则返回true;如果没获取到怎返回false,不会一直阻塞,可以指定等待时间;
unlock:释放锁。
都需要显示调用
典型用法:
lock.lock();
try{
}finally{
lock.unlock();
}
lock.lock();
try{
}finally{
lock.unlock();
}
ReentrantLock可重入锁
包括公平锁FairSync、非公平锁NofairSync两种实现,默认是非gongp
可重入锁:是指当线程在获取锁之后,再次获取该所而不会被阻塞
公平锁:是指线程按请求获取锁的先后顺序获取锁(排队);
非公平锁:则允许在线程发生请求后立即尝试获取锁(抢占),如果尝试失败才进行排队等待
公平锁:是指线程按请求获取锁的先后顺序获取锁(排队);
非公平锁:则允许在线程发生请求后立即尝试获取锁(抢占),如果尝试失败才进行排队等待
可重入实现原理:
1、其中包含一个Thread类型的成员变量exclusiveOwnerThread,表示已经获取到该锁的线程,以及一个计数器;
2、当线程获取锁成功后,该成员变量即赋值为该线程,同时计数器加一;
3、下一次在获取锁的时候,会先判断已经获取到锁的线程是否当前线程,如果是则直接过去,同时计数器加一;
4、每一次释放锁时都讲计数器减一,直到减为0,将exclusiveOwnerThread置为null,表示当前没有线程持有该锁。
1、其中包含一个Thread类型的成员变量exclusiveOwnerThread,表示已经获取到该锁的线程,以及一个计数器;
2、当线程获取锁成功后,该成员变量即赋值为该线程,同时计数器加一;
3、下一次在获取锁的时候,会先判断已经获取到锁的线程是否当前线程,如果是则直接过去,同时计数器加一;
4、每一次释放锁时都讲计数器减一,直到减为0,将exclusiveOwnerThread置为null,表示当前没有线程持有该锁。
ReadWriteLock
允许多个线程对资源同时进行读操作,或一个线程写操作,但读和写操作二者不能同时发生
ReadLock读锁 属于共享锁实现
WriteLock写锁 属于排他锁实现
StampedLock
是Java 8引入的锁,用于解决原有ReadLock的读操作阻塞写操作的问题
支持三种模式的锁操作。分别是:写(Writing)、读(Reading)、乐观锁(Optimistic Reading)。
其中写模式获取的是互斥锁,而读模式不是。
其中写模式获取的是互斥锁,而读模式不是。
由于它支持多种锁模式协调使用,因此并没有直接实现Lock或ReadWriteLock接口
主要方法
锁的获取和释放
写锁:writeLock()/tryWriteLock()/tryWriteLock(time,unit)、unlockWrite(stamp)
(悲观)读锁:readLock()/tryReadLcok()/tryReadLock(time,unit)、unlockRead(stamp)
乐观读锁:tryOPtimisticRead()
unlock(stamp)
锁模式切换
tryConvertToWriteLock(stamp)
tryConvertReadLock(stamp)
tryConvertToOptimisticRead(Stamp)
集合框架
Collection接口
Set接口
HashSet
LinkedHashSet
SortedSet接口
TreeSet
List接口
ArrayList
linkedList
Vetor
stack
Map接口
HashMap
LinkedHashMap
LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的。
Hashtable
与HashMap的主要区别:
HashMap(key,value)均可以为null,而Hashtable则不允许。
方法加了sychronized关键字,线程安全
其中的对象必须实现equals和hashCode方法
java.util.Properties是其子类
HashMap(key,value)均可以为null,而Hashtable则不允许。
方法加了sychronized关键字,线程安全
其中的对象必须实现equals和hashCode方法
java.util.Properties是其子类
SortedMap接口
Map接口的有序子接口,按照键自然顺序或指定排序规则Comparator进行排序
TreeMap
实现了SortedMap接口
底层就是红黑树算法的实现
线程不安全
底层就是红黑树算法的实现
线程不安全
WeakHashMap
其中的键是弱键,当它不被使用时会自动被GC给回收,同时其所在的entry节点会删除
Collections
提供了常用的集合操作方法,如排序sort等方法;同时还提供常用集合的同步实现,以适应多线程环境
异常处理
分类
预定义异常
运行时异常:RunTimeException类的子类
不需要显示在程序中的进行try...catch处理
如:NullPotionerException、IllegalArgumentException、ArrayIndexOutOfBoundException等
受检异常CheckedException:非RuntimeException子类
必须在程序中显示进行异常捕获处理
如:IOException、SQLException、FileNotFoundException等
自定义异常
继承Exception或RuntimeException
语法
try...catch、try...catch...finally\try...finally
throw、throws
Java7易忽略的新特性
try-with-resources语句:监护资源测关闭操作,会自动在语句结束后将每个资源正确关闭。
注:该资源必须要直接或间接实现java.lang.AutoCloseable接口,该接口只包含一个close方法
注:该资源必须要直接或间接实现java.lang.AutoCloseable接口,该接口只包含一个close方法
Swicth语句支持String类型
单个catch捕获多个异常,如catch(IOException | SQLException|FileNotFoundException ex)
泛型实例化类型自动推断,如List<Integer> list = new ArrayList<>()
数值可以使用下划线分隔,如int n = 1_000_000表示1000000
多核并行计算支持:fork/join框架
数据库
关系型数据库
SQL语法
数据查询语言DQL
数据查询语言,顾名思义就是从数据库中查询数据。包括select、where、order by、group by、having等动词
数据定义语言DDL
数据定义语言,用于数据库表结构的相关操作,如创建表CREAYE、删除表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
执行顺序:FROM->WHERE->GROUP BY->HAVING->SELECT->DISTINCT->UNION->ORDER BY
常见的关系型数据库
SQL Server、MySQL、Orcale等
数据库设计
三大范式
第一方式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/PreparedSatement
进行数据操作(增、删、改、查)
释放资源:关闭结果集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
带有监控功能的数据库连接池,由阿里巴巴开源
HikariCP
“光”,号称是性能最好的数据库连接池
事务
ACID四大特性
原子性Atomicity
事务是原子性操作,要么都执行,要么都不执行
一致性Consistency
事务在执行前后数据完整性必须保持一致
隔离性Isolation
并发的事务之间是相互隔离的,事务内部的操作对于其他事务而言都是互不可见的。
如果不考虑隔离性,就可能发生脏读、不可重复读、幻读的问题。
如果不考虑隔离性,就可能发生脏读、不可重复读、幻读的问题。
1)脏读:一个事务读取另一个事务改写但还未提交的数据,入果这些数据被回滚,则读到的数据无效。
2)不可重复读:在同一事务中,多次读取同一数据返回的结果不同。
3)幻读:一个事务读取了几行记录,另一个事务插入一些记录。后来的查询中,另一个事务就会发现有些原来没有的记录。
2)不可重复读:在同一事务中,多次读取同一数据返回的结果不同。
3)幻读:一个事务读取了几行记录,另一个事务插入一些记录。后来的查询中,另一个事务就会发现有些原来没有的记录。
持久性Durability
事务一旦提交完成,引起的数据改变将是永久性的,即使数据库发生故障也不应该对其有任何影响
游标
相当于一个指针,用于对数据库中数据进行遍历操作,通常以行为单位进行遍历
函数
CREATE FUNCTION func_name
(@[参数名][类型],@[参数名][类型],....)
RETURNS [返回值类型1],[返回值类型1].......
AS
BEGIN
.....
END
(@[参数名][类型],@[参数名][类型],....)
RETURNS [返回值类型1],[返回值类型1].......
AS
BEGIN
.....
END
有返回值,可以在select语句中使用
存储过程
CREATE PROCEDURE/PROC sp_name
@[参数名][类型],@[参数名][类型],......
AS
BEGIN
.....
END
@[参数名][类型],@[参数名][类型],......
AS
BEGIN
.....
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
Orcale
explain plan命令,如explain plan for select * from tb_user
非关系型数据库
Redis、MongoDB等
分布式数据库
Apache HBase
Alibaba OceanBase
ElasticSearch
接口服务
RPC
即Remote Procedure Call,远程过程调用。客户即通过网络实现对服务器上的方法调用。
常见框架
Alibaba dubbo
Google grpc
Facebook Thrift
RMI
可以看成是RPC的Java实现,同时它也是JNDI(即Java Naming and Directory Interface,Java命名和目录接口)规范的一种实现。
主要组成
Naming类
LocateRegister类
Remote接口:代表远程对象
UnicastRemoteObject类
Web Service
SOAP协议
Simple Object Assess Protocol(简单对象访问协议)。它是一种轻量的,简单的,基于XML和HTTP的Web数据交换协议。它通过XML来实现消息描述,然后通过HTTP协议实现消息传输。
WSDL
即Web Service Description Language,Web服务描述语言。就是基于XML,用于描述Web服务及函数、参数和返回值的语言。
WSDD
即Web Service Deployment Descriptor,Web服务部署描述符。用于服务端Web Service的发布
常见框架
Apache Axis
Apache CXF
RESTful
即表述性状态传递(Representational State Transfer,简称REST),它是一种软件架构风格,可以完全使用HTTP协议实现。使用于完全无状态的CRUD(Create、Retrieve、Update、Delete,即数据的增删改差)操作
对资源的操作有获取、创建、修改和删除,与HTTP协议提供的GET、POST、PUT、DELETE等方法相对应
通过Spring MVC来实现
org.springframework.filter.HiddenHttpMethodFilter过滤器
(由于浏览器form表单只支持GET与POST请求,而DELETE、PUT等method并不支持,此过滤器就可以将其转换标准的HTTP方法,使得支持PUT、DELETE等请求)
(由于浏览器form表单只支持GET与POST请求,而DELETE、PUT等method并不支持,此过滤器就可以将其转换标准的HTTP方法,使得支持PUT、DELETE等请求)
统一异常处理
@ExceptionHandler注解
实现HandlerExceptionResolver接口
token身份验证
大数据
以云计算为基础,高效处理海量的数据分析
云计算
使用互联网来接入存储或者运行在远程服务器端的应用、数据、或者服服务,比如云服务,云数据库
三种服务模式:
IaaS:Infrastructure as aService,基础设施即服务;
Paas:Platform as a Service,平台即服务;
SaaS:Software as a Service,软件即服务
IaaS:Infrastructure as aService,基础设施即服务;
Paas:Platform as a Service,平台即服务;
SaaS:Software as a Service,软件即服务
IaaS:一台服务器(硬件,一般可以带操作系统),其他软件需要自己安装;
PaaS:Java应用开发环境(JDK、Tomcat、MySQL等);
Saas:一个已经开发完成可立即投入使用的网站或系统
PaaS:Java应用开发环境(JDK、Tomcat、MySQL等);
Saas:一个已经开发完成可立即投入使用的网站或系统
OpenStack:Iaas层面的云计算平台
四种部署模式:私有云、公有云、混合云、云社区
开发平台
Hadoop、Spark、zookeeper
高并发
概念
大量用户同时访问请求网站或系统,造成请求不能及时响应的现象
解决思路
负载均衡Load Balance,简称LB
硬件
F5
软件
nginx
Linux服务器集群系统LVS(Linux Virtual Server)
HaProxy
Nginx、HAProxy、LVS三者的优缺点
服务器集群
服务器集群就是指将多个服务集中起来的同一种服务
常见集群
Tomcat服务器集群
Apache + Tomcat:一台Apache服务器进行反向代理与请求分发,多台Tomcat服务器处理请求
Nginx + Tomcat:一台Nginx服务器进行反向代理与请求分发,多台Tomcat服务器处理请求
Weblogic服务器集群
数据库服务器集群
锁机制
分布式锁
基于数据库实现
锁表
创建一张锁表,当需要锁住某个方法或资源时,我们就在该表中增加一条响应的记录,想要释放锁的时候就删除该条记录
排他锁
在查询语句后面增加for update,数据库会在查询过程中给数据库表增加排他锁,直到事物提交后才会释放锁
基于缓存实现
如redis、memcached等
基于zookeeper实现
java中的锁
用于保证线程同步
同步锁synchronized关键字
Lock
CAS(voliate)
数据库锁
已由数据库本身实现,只需调用相关语句即可
乐观锁
通常通过在表结构中增加一个版本号字段来解决,查询数据时将版本号一起查出来,需要更新数据时就将原有的版本号加一
给数据操作价格版本号判断,满足条件才会执行,这就相当于给数据库操作加了一把锁
如 update user set name ='Tom',version=2 where id = 1 and version=1
悲观锁
共享锁
对于MySQL数据库,在查询语句后面加上lock in share mode ,数据库就会在查询过程中给数据库表增加共享锁
排他锁
也称独占锁。排他锁与共享锁相对应,就是指对于多个不同的事物,对同一个资源只能有一把锁
在查询语句后增加for update,数据库会在查询过程中给数据库表指定行增加排他锁,增到事务提交后才会释放
缓存技术
要解决的问题
缓存一致性
缓存与数据库中的数据需要保证一致
缓存雪崩
缓存在同一时间大面积失效
缓存穿透
同一时间大量请求查询不存在的缓存,造成后端数据库压力增加
好处
减轻数据库如MySQL、Orcale等压力
提高数据访问数据
常用缓存中间件
Redis
Redis的安装及配置(Linux环境下)
下载源码
wget
解压
tar -zxvf
redis.conf文件配置
后台启动配置参数
daemonize yes(no-不后台启动 yes-后台启动)
port 6379(可以更改自己的端口号,客户端登录时,如改变默认端口,则需指定设置端口进行登录)
信息查看命令
查看redis客户端which redis-cli
登录:redis-cli(默认登录本机6379端口)
info命令查看redis信息
登录:redis-cli(默认登录本机6379端口)
info命令查看redis信息
过期时间expire
数据类型
String
最基本的存储结构
命令
get key
set key value
mget key1 key2...
mset key1 key2...
setnx key value
incr/decr key
set key value
mget key1 key2...
mset key1 key2...
setnx key value
incr/decr key
Hash
key-value结构
命令
hget key field
hset key field value
hmset key field1 value1 field2 value2...
hmget key field1 field2
hset key field value
hmset key field1 value1 field2 value2...
hmget key field1 field2
List
双向链表结构,数据从左到右的顺序存储
命令
lpush、rpush、lpop、rpop、lset key index value
Set
Set集合,不能有相同的值
命令
sadd key mermber1 member2...
scard key
set jey index value
sismember key member
smembers key
scard key
set jey index value
sismember key member
smembers key
zset(sorted set)
有序集合,按照score排序
命令
zadd key score1 member1 score2 mermber2...
zcard key
zrange key start start stop 【withscores】
zcard key
zrange key start start stop 【withscores】
存储
内存、磁盘、日志文件
持久化
RDB快照
Append-only file(缩写为AOF)日志
发布/订阅
管道pipeline
可以一次性发送多条命令并在执行完成后一次性将结果返回
通过减少客户端与redis的通信次数来实现降低往返延时时间,而且其实现原理是队列,而且其实现原理是队列,先进先出,因此可以保证数据的顺序性
事务
事务中多条命令要么都执行成功,要么都失败
应用场景
缓存、分布式会话、聊天室的在线好友队列、任务队列、应用排行榜、访问统计、数据过期处理
memcached
特点:
只支持key-value数据结果存储
缓存数据全部在内存中,不支持数据持久化
只支持key-value数据结果存储
缓存数据全部在内存中,不支持数据持久化
EhCache
CDN(Content Delivery Network,内容分发网路)缓存
服务降级
网页HTML静态化
数据库读写分离、分表分库
图片服务器分离
负载测试工具
Jmeter
Tsung
高并发实战
高并发必备的技术
Netty
redis
zookeeper
高并发底层原理
IO读写的基础原理
内核缓冲区和进程缓冲区
上层应用使用read系统调用时,仅仅把数据从内核缓冲区复制到上应用的缓冲区(进程缓冲区)
上层应用使用write系统调用时,仅仅是把数据从进程缓冲区复制到内核缓冲区
用户程序的IO读写操作,大多数情况下是在进程缓冲区和内核缓冲区之间直接进行数据的交换
系统调用流程
1、等待数据从网络到达网卡。在所等待的分组到达时,它被复制到内核中的某个缓冲区。这个工作由操作系统自动完成,用户程序无感知。
2、把数据从内核缓冲区复制到应用进程缓冲区。
2、把数据从内核缓冲区复制到应用进程缓冲区。
四种主要的IO模型
同步阻塞IO(BlockingQueue IO)
阻塞IO
需要内核IO操作彻底完成后,才可以返回到用户空间执行用户的操作
同步IO
同步IO是指用户空间的线程是主动发起IO请求的一方,内核空间是被动接受方。反之亦然。
同步非阻塞IO(Non-blocking IO)
指用户控件程序不需要等待内核IO操作彻底完成,可以立即返回用户控件执行用户的操作,即处于非阻塞状态,与此同时内核会立即返回给用户一个状态值。
非阻塞IO要求socket被设置为NONBLOCK
注意:这里所说的NIO(同步非阻塞IO)模型,并非Java的NIO(New IO)库
IO多路复用(IO Multiplexing)
即经典的Reactor反应器设计模式,有时也称异步阻塞IO,Java中的选择器和Linux中的epoll都是这种模式
流程
选择器注册。在这种模式中,首先,将需要read操作的目标socket网络连接,提前注册到select/epoll选择器中,Java中对应的选择器类是Selector类。然后,才可以开启整个IO多路复用模型的轮询流程。
就绪状态的轮询。通过选择器的查询方法,查询注册过的所有socket连接的就绪状态。桶过查询的系统调用,内核会返回一个就绪的socket列表。当任何一个注册过的socket中的数据准备好了,内核缓冲区有数据(就绪)了,内核就将该socket加入到就绪的列表中。
当用户进程调用了select查询方法,那么整个线程会被阻塞掉
当用户进程调用了select查询方法,那么整个线程会被阻塞掉
当用户线程获得了就绪状态的列表后,根据其中的socket连接,发起read系统调用,用户线程阻塞。内核开始复制数据,将数据从内核缓冲区复制到用户缓冲区。
复制完成后,内核返回结果,用户线程才会解除阻塞的状态,用户线程读取到了数据,继续执行。
特点
1、IO多路复用模型的IO涉及两种系统调用(System Call),另一种是select/epoll(就绪查询),一种是IO操作。IO多路复用模型建立在操作系统的基础设施上,即操作系统内核必须能够提供多路分离的系统调用select/epoll
2、和NIO模型相似,多路复用IO也需要轮询。负责select/epoll状态查询调用的线程,需要不断地进行select/epoll轮询,查找出达到IO操作就绪的socket链接
Java语言的NIO(New IO)技术,使用的就是IO多路复用模型。在Linux系统上,使用的是epoll系统调用。
异步IO(Asynchronous IO)
指的是用户空间与内核空间的调用方式反过来。用户空间的线程变成被动接受者,而内核空间变成主动调用者。这有点类似于Java中回调模式。
基本流程
用户线程通过系统调用,向内核注册某个IO操作。内核在整个IO操作(包括数据准备、数据复制)完成后,通知用户程序,用户执行后续业务操作。
特点
在内核等待数据和复制数据的两个节点,用户线程都不是阻塞的。用户线程需要接收内核IO操作完成的时间,或者用户线程需要注册一个IO操作完成的回调函数。正因为如此,异步IO有时候也被称为信号驱动IO
缺点
应用程序不仅需要进行事件的注册与接收,其余工作都留给了操作系统,也就是说,需要底层内核提供支持
理论上来说,异步IO是真正的异步输入输出,它的吞吐量高于IO多路复用模型的吞吐量,但目前不完善,因此类似高并发网路应用程序,还是采用多路复用IO,大名鼎鼎的Netty使用的就是多路复用IO
ulimit
显示和修改当前用户进程一些基础限制的命令
Java NIO通信基础详解
Java NIO简介
三个核心组件
Channel(通道)
在OIO中,统一个网络连接会关联两个流:一个输入流(Input Stream),另一个输出流(Output Stream)。通过两个流不断进行输入输出操作》
在NIO中,统一个网络连接使用一个通道表示,所有的NIO的IO操作都是从通道开始的。一个通道类似于OIO中的两个流的结合体,既可以从通道读取,也可以向通道写入。
在NIO中,统一个网络连接使用一个通道表示,所有的NIO的IO操作都是从通道开始的。一个通道类似于OIO中的两个流的结合体,既可以从通道读取,也可以向通道写入。
Selector(选择器)
指一个进程/线程可以同时监视多个文件描述符(一个网络连接,操作系统底层使用一个文件描述符来表示),一旦其中的一个或者多个文件描述符可读或者可写,系统内核就通知该进程/线程。在Java应用层面,如何实现对多个文件描述符的监视呢?需要用到一个非常重要的Java NIO组件---Selector选择器。
Buffer(缓冲区)
应用程序与通道(Channel)主要交互操作,就是进行数据的read读取和write写入。为了完成如此大人,NIO准备第一个重要组件-NIO Buffer。通道的读取,就是讲数据从通道读取到缓冲区中;通道写入,就是讲数据从缓冲区中写入到通道中。
NIO和OIO对比
OIO是面向流(Stream Oriented),NIO是面向缓冲区(Buffer Oriented)
OIO的操作时阻塞的,NIO的操作时非阻塞的
OIO没有选择器(Selector)概念,而NIO有选择器的概念
子主题
NIO Buffer(缓冲)类
NIO Buffer类及其属性
NIO的Buffer(缓冲区)本质上是一个内存块,既可以写入数据,也可以从中读取数据。
Buffer类
8中缓冲区类
ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
MappedByteBuffer
MappedByteBuffer是专门用于内存映射的一种ByteBuffer类型
重要属性
capacity(容量)
表示内部容量的大小。一旦写入的对象数量超过capacity容量,缓冲区就满了,不能再写入了
position(读写位置)
表示当前的位置。position属性与缓冲区的读写模式有关。在不同的模式下,position属性的值是不同的。当缓冲区进行读写的模式
limit(读写的限制)
表示读写的最大上限
mark(标记)
NIO Buffer的重要方法
allocate()创建缓冲区
put()写入到缓冲区
flip()翻转
get()从缓冲区读取
rewind()倒带
position重置为0,所以可以重读缓冲区的所有数据
limit保持不变,数据量还是一样的,仍然表示能从缓冲区中读取多少个元素
mark标记被清理,表示之前的临时位置不能再用了
mark()和reset()
clear()清空缓冲区
实验Buffer类基本步骤
使用创建子类实例对象的allocate(),创建一个Buffer类的实例对象
调用put方法,将数据写入到缓冲区中
写入完成后,在开始读取数据前,调用Buffer.flie()方法,将缓冲区转换为读模式
调用get方法,从缓冲区中读取数据
读取完成后,调用Buffer.clear()或Buffer.compact()方法,将缓冲区转换为写模式。
NIO Channel(通道)类
主要类型
FileChannel
用于文件的数据读写
FileChannel为阻塞模式,不能设置为非阻塞模式
SocketChannel
用于Socket套接字TCP连接的数据读写
ServerSocketChannel
服务器监听通道,允许我们监听TCP连接请求,为每个监听的请求,创建一个SocketChannel套接字通道
DatagramChannel
用于UDP协议的数据读写
NIO Selector选择器
简单地说:选择器的使命是完成IO的多路复用。一个通道代表一条连接通路,通过选择器可以同时监控多个通道的IO(输入输出)状况。选择器和通道的关系,是监控和被监控的关系。
IO事件类型
可读:SelectionKey.OP_READ
可写:SelectionKey.OP_WRITE
连接:SelectionKey.OP_CONNECT
接收:SelectionKey.OP_ACCEPT
SelectableChannel可选择通道
SelectionKey选择键
通道和选择器的监控关系注册成功后,就可以选择就绪事件。
选择器使用流程
(1)获取选择器实例
(2)将通道注册到选择器中
(3)轮询感兴趣的IO就绪事件(选择键集合)
(2)将通道注册到选择器中
(3)轮询感兴趣的IO就绪事件(选择键集合)
Java OIO与Java NIO对比
在NIO中,服务器接收新连接的工作,是异步进行的。不像Java的OIO那样,服务器监听连接,是同步的,阻塞的。NIO可以通过选择器(也可以说成:多路复用器),后续不断地轮询选择器的选择键集合,选择新到来的连接。
在NIO中,SocketChannel传输通道的读写操作都是异步的。如果没有可读写的数据,负责IO通信的线程不会同步等待。这样,线程就可以处理其他连接的通道;不需要像OIO那样,线程一直阻塞,等待所负责的连接可用为止。
在NIO中,一个选择器线程可以同时处理成千上万个客户端连接,性能不会随着客户端的增减而线性下降。
Reactor反应器模式
Reactor反应器模式为何如此重要
到目前为止,高性能网路编程都绕不开反应器模式,例如Nginx,Redis,Netty
Reactor反应器模式简介
反应器模式由Reactor反应器线程,Handler处理器两大角色组成:
(1)Reactor反应器线程的职责:负责响应IO事件,并且分发到Handler处理器。
(2)Handlers处理器的职责:非阻塞的执行业务处理逻辑。
(1)Reactor反应器线程的职责:负责响应IO事件,并且分发到Handler处理器。
(2)Handlers处理器的职责:非阻塞的执行业务处理逻辑。
单线程Reactor反应器模式
多线程Reactor反应器模式
多线程池Reactor反应器演进
首先是升级Handler处理器。既要使用多线程,又要尽可能的高效率,则可以考虑使用线程池
其次是升级Reactor反应器。可以考虑引入多个Selector选择器,提升选择大量通道的能力
多线程池反应模式
(1)将负责输入输出处理的IOHandler处理器的执行,放入独立的线程池中。这样,业务处理线程与负责服务监听和IO时间查询的反应器线程相隔离,避免服务器的连接监听受到阻塞。
(2)如果服务器为多核的CPU,可以将反应器线程拆分为多个子反应器(SubReactor)线程;同时,引入多个选择器,每个SubReactor子线程负责一个选择器。这样,充分释放系统资源的能力;也提高了反应器管理大量连接,提升选择大量通道的能力
(2)如果服务器为多核的CPU,可以将反应器线程拆分为多个子反应器(SubReactor)线程;同时,引入多个选择器,每个SubReactor子线程负责一个选择器。这样,充分释放系统资源的能力;也提高了反应器管理大量连接,提升选择大量通道的能力
Reactor反应器模式小结
反应器模式和生产者消费者模式对比
相似之处:在一定程度上,反应器模式有点类似于生产者消费者模式。在生产者消费者模式中,一个或多个生产者将事件加入到一个队列中,一个或多个消费者主动地从这个队列中提取(Pull)事件来处理。
不同之处在于:反应器模式是基于查询的,没有专门的队列去缓冲存储IO事件,查询到IO事件之后,反应器会根据不同IO选择键(事件)将其分发给对应的Handler处理器来处理。
不同之处在于:反应器模式是基于查询的,没有专门的队列去缓冲存储IO事件,查询到IO事件之后,反应器会根据不同IO选择键(事件)将其分发给对应的Handler处理器来处理。
反应器模式和观察者模式对比
相似之处在于:在反应器模式中,当查询到IO事件后,服务处理程序使用单路/多路分发(Dispatch)策略,同步地分发这些IO事件。观察者模式也被称作发布/订阅模式,它定义了一种依赖关系,让多个观察者同时监听某一个主题。这个主题对象在状态发生变化时,会通知所有观察者,它们能够执行响应的处理。
不同之处在于:在反应器模式,Handler处理实例和IO事件(选择键)的订阅关系,基本上是一个事件绑定到一个Handler处理器;每一个IO事件(选择键)被查询后,反应器会将事件分发给所绑定的Handler处理器;而在观察者模式中,同一个时刻,同一个主题可以被订阅过的多个观察者处理
不同之处在于:在反应器模式,Handler处理实例和IO事件(选择键)的订阅关系,基本上是一个事件绑定到一个Handler处理器;每一个IO事件(选择键)被查询后,反应器会将事件分发给所绑定的Handler处理器;而在观察者模式中,同一个时刻,同一个主题可以被订阅过的多个观察者处理
优点和缺点
优点:
响应快,虽然同一反应器线程本身是同步的,但是不会被单个连接的同步IO所zuse。
编程响应简单,最大程度避免了复杂的多线程同步,也避免了多线程的各个进程之间切换的开销
可扩展,可以方便地通过增加反应器线程的个数来充分利用CPU资源。
响应快,虽然同一反应器线程本身是同步的,但是不会被单个连接的同步IO所zuse。
编程响应简单,最大程度避免了复杂的多线程同步,也避免了多线程的各个进程之间切换的开销
可扩展,可以方便地通过增加反应器线程的个数来充分利用CPU资源。
缺点:
反应器模式增加了一定的复杂性,因而有一定的门槛,并且不易于调试。
反应器模式需要操作系统底层的IO多路复用的支持,如Linux中的epoll。如果操作系统的底层不支持IO多路复用,反应器模式不会有那么搞笑
同一个Handler业务线程中,如果出现一个长时间的数据读写,会影响这个反应器中其他通道的IO处理。例如大文件传输时,IO操作就会影响其他客户端的响应时间。因而对于这种操作,还需要进一步对反应器模式进行改进。
反应器模式增加了一定的复杂性,因而有一定的门槛,并且不易于调试。
反应器模式需要操作系统底层的IO多路复用的支持,如Linux中的epoll。如果操作系统的底层不支持IO多路复用,反应器模式不会有那么搞笑
同一个Handler业务线程中,如果出现一个长时间的数据读写,会影响这个反应器中其他通道的IO处理。例如大文件传输时,IO操作就会影响其他客户端的响应时间。因而对于这种操作,还需要进一步对反应器模式进行改进。
Future异步回调模式
Join异步阻塞
A线程调用B线程的join方法,等待B线程执行完成;在B线程没有完成前,A线程阻塞。
FutureTask异步回调之重武器
FutureTask
Future接口
Guava的异步回调
Netty的异步回调模式
Netty原理与基础
Netty中的Reactor反应器模式
Reactor反应器模式中IO时间的处理流程
通道注册。IO源于通道(Channel)。IO是和通道强相关的。一个IO事件,一定属于某个通道。但是,如果要查询通道的时间,首先要将通道注册到选择器。
查询选择。在反应器模式中,一个反应器(或者SubReactor子反应器)会负责一个线程;不断地轮询,查询选择器中的IO事件(选择键)
事件分发。如果查询到IO事件,则分发给与IO事件有绑定关系的Handler业务处理器
完成真正的IO操作和业务处理,这一步由Handler业务处理器负责
Netty中Channel通道组件
Netty通道类型
NioSocketChannel:一步非阻塞TCP Socket传输通道
NioServerSocketChannel:异步非阻塞TCP Socket服务器监听通道
NIODatagramChannel:异步非阻塞的UDP传输通道
NioSctpChannel:异步非阻塞Sctp传输通道
OIoSocketChannel:同步阻塞式TCP Socket传输通道
OioServerSocketChannel:同步阻塞式TCP Socket服务端监听通道。
OioDatagramChannel:同步阻塞式UDP传输通道
OioSctpChannel:同步阻塞式sctp传输通道
OioStcpServerChannel:同步阻塞式Sctp服务端监听通道
NioEventLoop
Netty中的Handler处理器
ChannelInboundHandler通道入站处理器
ChannelInboundHandlerAdapter:通道入站处理适配器
ChannelOutboundHandler通道出站处理器
ChannelOutBoundHandlerAdapter通道出站处理适配器
Netty的流水线(Pipeline)
Netty的反应器模式中各个组件之间的关系
(1)反应器(或者SubReactor)和通道之间是一对多的关系:一个反应器可以查询很多个通道的IO时间
(2)通道和Handler处理器实例之间,是多对多的关系:一个通道的IO时间被多个的Handler实例处理;一个Handler处理器实例也能绑定很多的通道,处理多个通道的IO时间。
(2)通道和Handler处理器实例之间,是多对多的关系:一个通道的IO时间被多个的Handler实例处理;一个Handler处理器实例也能绑定很多的通道,处理多个通道的IO时间。
BootStrap启动类型
父子通道
连接监听类型。连接监听类型的socket描述符,放在服务端,它负责接收客户端的套接字连接;在服务器端,一个“连接监听类型”的socket描述符可以接收(Accept)成千上万的传输类的socket描述符。
传输数据类型。数据传输类的socket描述符负责传输数据。同一条TCP的Socket传输链路,在服务器和客户端,都分别会有一个与之相对应的传输类型的socket描述符。
将有接收关系的NioServerSocketChannel和NioSocketChannel,叫父子通道
EventLoopGroup线程组(事件循环线程组)
为了及时接收(Accept)到新连接,在服务器端,一般有两个独立的反应器,一个反应器负责新连接的监听和接收,另一个反应器负责IO事件处理。对应到Netty服务器程序中,则是设置两个EventLoopGroup线程组,一个EventLoopGroup负责新连接的监听和接受,一个EventLoopGroup负责IO事件处理。
Bootstrap启动流程
ChannelOption通道选项
SO_RCVBUF,SO_SNDBUF:用来设置TCP连接的两个缓冲区大小。
TCP_NODELAY:立即发送数据
SO_KEEPALIVE:表示底层TCP协议的心跳机制。
SO_REUSEADDR:设置为true表示地址复用
SO_LINGER:表示关闭socket延迟时间,-1表示禁用该功能。
SO_BACKLOG:表示服务器接收连接的队列长度。
SO_BROADCAST:表示设置广播模式
Channel通道
AbstractChannel抽象类
ChannelFuture connect(SocketAddress address):连接远程服务器。
ChannelFuture bind(SocketAddress address):绑定监听地址
ChannelFuture close():关闭通道连接
Channel read():读取通道数据
ChannelFuture write(Object o):启用出站流水处理
Channel flush()将缓冲区中的数据立即写出到对端。
EmbeddedChannel嵌入式通道
writeInbound入站数据写到通道
readOutbound读取通道的出站数据
Handler业务处理器
整个IO处理操作环节包括:从通道读数据包、数据包解码、业务处理、目标数据编码、把数据包写到通道、由通道发送到对端。
ChannelInboundHandler通道入站处理器
channelRegistered
channelActive
channelRead
channelReadComplete
channelInactive
exceptionCaught
ChannelOutboundHandler通道出站处理器
bind
connect
write
flush
disConnect
close
ChannelInitializer通道初始化处理器
Pipeline流水线
Pipeline入站处理流程
Pipeline出站处理流程
ChannelHandlerContext上下文
byteBuf缓冲区
Netty提供了ByteBuf来替代Java NIO的ByteBuffer缓冲区,以操纵内存缓冲区
ByteBuf优势
Pooling(池化,这点减少了内存复制和GC,提升了效率)
复合缓冲区类型,支持零复制
扩展性好,例如StringBuffer
可自定义缓冲区类型
读取和写入索引分开
方法的链式调用
可以进行引用计数,方便重复使用
ByteBuf的重要属性
readerIndex(读指针)
writerIndex(写指针)
maxCapacity(最大容量)
ByteBuf缓冲区的类型
Heap ByteBuf
内部数据为一个java数组,存储JVM的堆空间中
Direct ByteBuf
内部数据存储在操作系统的物理内存中
CompositeBuffer
多个缓冲区组合表示
ByteBuf浅层复制
切片(slice)浅层复制
整体(duplicate)浅层复制
Decoder与Encoder
Decoder实践原理
ByteToMessageDecoder解码器
实现解码器的流程
(1)首先继承ByteToMessageDecoder抽象类
(2)然后实现其基类的decode抽象方法。将ByteBuf到POJO解码的逻辑写入此方法。将ByteBuf二进制数据,解码成一个一个的Java POJO 对象。
(3)在子类的decode方法中,需要将解码后的Java POJO对象,放入decode的List<Object>是惨重。这个实参是ByteToMessageDecoder父类传入的,也就是父类的结果手机列表。
(2)然后实现其基类的decode抽象方法。将ByteBuf到POJO解码的逻辑写入此方法。将ByteBuf二进制数据,解码成一个一个的Java POJO 对象。
(3)在子类的decode方法中,需要将解码后的Java POJO对象,放入decode的List<Object>是惨重。这个实参是ByteToMessageDecoder父类传入的,也就是父类的结果手机列表。
ReplyingDecoder解码器
不需要判断长度,内部已经处理好了
整数的分包解码器的实践案例
state属性
内置Decoder
固定长度数据包解码器--FixedLengthFrameDecoder
行分割数据包解码器--LineBaedFrameDecoder
自定义分隔符数据包解码器--DelimiterBasedFrameDecoder
自定义长度数据包解码器——LengthFieldBasedFrameDecoder
Encoder原理与实践
MessageToByteEncoder编码器
MessageToMeeageEncoder编码器
JSON和ProtoBuf序列化
描述
在开发一些远程过程调用(RPC)的程序时,通常会涉及对象的序列化/反序列化的问题,目前可选择的编码方式:
1、使用JSON。将Java POJO对象转换成JSON结构化字符串。基于HTTP协议,在Web应用、移动开发方面等,这是常用的编码方式,因为JSON的可读性较强。但是它的性能稍差。
2、基于XML。和JSON一样,数据在序列化成字节流之前都转换成字符串。可读性强,性能差,异构系统、Open API类型的应用中常用。
3、 使用Java内置的编码和序列化机制,可移植性强,性能稍差,无法跨平台(语言)。
4、他开源的序列化/反序列化框架,例如Apache Avro, Apache Thrift,这两个框架和Protobuf相比,性能非常接近,而且设计原理如出一辙;其中Avro在大数据存储(RPC数据交换,本地存储)时比较常用;Thrift的亮点在于内置了RPC机制,所以在开发一些RPC交互式应用时,客户端和服务器端的开发与部署都非常简单。
1、使用JSON。将Java POJO对象转换成JSON结构化字符串。基于HTTP协议,在Web应用、移动开发方面等,这是常用的编码方式,因为JSON的可读性较强。但是它的性能稍差。
2、基于XML。和JSON一样,数据在序列化成字节流之前都转换成字符串。可读性强,性能差,异构系统、Open API类型的应用中常用。
3、 使用Java内置的编码和序列化机制,可移植性强,性能稍差,无法跨平台(语言)。
4、他开源的序列化/反序列化框架,例如Apache Avro, Apache Thrift,这两个框架和Protobuf相比,性能非常接近,而且设计原理如出一辙;其中Avro在大数据存储(RPC数据交换,本地存储)时比较常用;Thrift的亮点在于内置了RPC机制,所以在开发一些RPC交互式应用时,客户端和服务器端的开发与部署都非常简单。
粘包和拆包
概念:
(1)粘包,指接收端(Receiver)收到一个ByteBuf,包含多个发送端(Sender)的ByteBuf,多个ByteBuf“粘”在一起。
(2)半包,就是接收端将一个发送端的ByteBuf“拆”开了,收到多个破碎的包。换句话说,一个接收端收到的ByteBuf是发送端的一个ByteBuf的一部分
(1)粘包,指接收端(Receiver)收到一个ByteBuf,包含多个发送端(Sender)的ByteBuf,多个ByteBuf“粘”在一起。
(2)半包,就是接收端将一个发送端的ByteBuf“拆”开了,收到多个破碎的包。换句话说,一个接收端收到的ByteBuf是发送端的一个ByteBuf的一部分
半包现象原理
解决思路
基本思路是,在接收端,Netty程序需要根据自定义协议,将读取到的进程缓冲区ByteBuf,在应用层进行二次拼装,重新组装我们应用层的数据包。接收端的这个过程通常也称为分包,或者叫作拆包。
JSON协议通信
分类
阿里的FastJson、谷歌的Gson和开源社区的Jackson。
在实际开发中,目前主流的策略是:Google的Gson库和阿里的FastJson库两者结合使用。在POJO序列化成JSON字符串的应用场景,使用Google的Gson库;在JSON字符串反序列化成POJO的应用场景,使用阿里的FastJson库
Protobuf协议通信
Protobuf协议语法
文件组成部分:头部声明、消息结构体
基于Netty的单体IM系统的开发
Zookeeper分布式协调
分布式缓存Redis
亿级高并发IM架构的开发实践
高并发IM架构的理论基础
亿级流量的系统架构的开发实践
支撑亿级流量的高并发IM通信的几大集群中,最为核心的是Netty集群、ZooKeeper集群、Redis集群,它们是主要实现亿级流量通信功能不可缺少的集群。其次是SpringCloud WEB服务集群、MySql集群,完成海量用户的登录和存储,以及离线消息的存储。最后是RocketMQ消息队列集群,用于离线消息的保存。
主要集群介绍如下:
(1)Netty服务集群 主要用来负责维持和客户端的TCP连接,完成消息的发送和转发。
(2)ZooKeeper集群负责Netty Server集群的管理,包括注册、路由、负载均衡。集群IP注册和节点ID分配。主要在基于ZooKeeper集群提供底层服务
(3)Redis集群负责用户、用户绑定关系、用户群组关系、用户远程会话等等数据的缓存。缓存其他的配置数据或者临时数据,加快读取速度。
(4)MySql集群保存用户、群组、离线消息等。
(5)RocketMQ消息队列集群主要是将优先级不高的操作,从高并发模式转成低并发的模式。例如,可以将离线消息发向消息队列,然后通过低并发的异步任务保存到数据库。
(1)Netty服务集群 主要用来负责维持和客户端的TCP连接,完成消息的发送和转发。
(2)ZooKeeper集群负责Netty Server集群的管理,包括注册、路由、负载均衡。集群IP注册和节点ID分配。主要在基于ZooKeeper集群提供底层服务
(3)Redis集群负责用户、用户绑定关系、用户群组关系、用户远程会话等等数据的缓存。缓存其他的配置数据或者临时数据,加快读取速度。
(4)MySql集群保存用户、群组、离线消息等。
(5)RocketMQ消息队列集群主要是将优先级不高的操作,从高并发模式转成低并发的模式。例如,可以将离线消息发向消息队列,然后通过低并发的异步任务保存到数据库。
技术选型
(1)核心Netty4.x + spring4.x + ZooKeeper 3.x + redis 3.x + rocketMQ 3.x+ mysql 5.x+ monggo3.x
(2)短连接服务:spring cloud基于RESTful短连接的分布式微服务架构,完成用户在线管理、单点登录系统。
(3)长连接服务:Netty主要用来负责维持和客户端的TCP连接,完成消息的发送和转发。
(4)消息队列:rocketMQ高速消队列。
(5)数据库:mysql+mongodbmysql用来存储结构化数据,如用户数据。mongodb很重要,用来存储非结构化的离线消息。
(6)序列化协议:Protobuf + JSONProtobuf是最高效的二进制序列化协议,用于长连接。JSON是最紧凑的文本协议,用于短连接。
(2)短连接服务:spring cloud基于RESTful短连接的分布式微服务架构,完成用户在线管理、单点登录系统。
(3)长连接服务:Netty主要用来负责维持和客户端的TCP连接,完成消息的发送和转发。
(4)消息队列:rocketMQ高速消队列。
(5)数据库:mysql+mongodbmysql用来存储结构化数据,如用户数据。mongodb很重要,用来存储非结构化的离线消息。
(6)序列化协议:Protobuf + JSONProtobuf是最高效的二进制序列化协议,用于长连接。JSON是最紧凑的文本协议,用于短连接。
分布式
CAP理论
Consistency(一致性),Availability(可用性),Partition(分区容错性),三者不可兼得
1.一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问最新的数据备份)
2.可用性(A):在集群中一部分节点故障后,集群整体是否还能相应客户端的读写请求。(对数据更新具备高可用性)
3.分区容错性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能再时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择
2.可用性(A):在集群中一部分节点故障后,集群整体是否还能相应客户端的读写请求。(对数据更新具备高可用性)
3.分区容错性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能再时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择
幂等性
幂等(idempotent)是一个数学与计算机概念,常见于抽象代数中。在编程中一个幂等操作的特点是任意多次所产生的影响均与一次执行的影响相同
分布式计算
大运算量计算场景
MapReduce、Hadoop、Spark
分布式存储
大数据量存储场景
一致性哈希Consist Hashing算法
分布式数据库
Redis、MongoDB、HBase等
分布式文件系统Distrubuted File System,HDFS
分布式消息服务(消息队列)
基础Netty
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文件,打开注释:<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster">
2、在web.xml文件中加入配置:<distribute/>
2、在web.xml文件中加入配置:<distribute/>
软件架构
SOA
是一种粗粒度、松耦合的服务架构、各服务间均需要基于ESB(Enterprise Service Bus,企业服务总线)进行消息通信
微服务
概念
框架工具
技术选型
Dubbo + Zookeeper
dubbo作为RPC调用框架,提供服务调用功能;zookeeper作为服务的注册中心
Spring Cloud
主要组件
Docker容器
主要解决的问题
Docker的安装
yum -y install docker
相关概念
镜像
自定义镜像
两种方式
通过Dockerfile文件快速创建镜像
编写Dockerfile文件,然后执行docker build命令创建镜像
使用docker commit命令从容器创建一个新的镜像
仓库
本地镜像仓库
远程镜像仓库
容器
常用命令
docker login 【OPTIONS】【SERVER】
登录到一个Docker镜像仓库
docker search 【OPTIONS】TERM
搜素远程仓库镜像,如docker search centos表是与centos相关的镜像
docker pull 【OPTIONS】NAME【:TAG|@DISGEST】
从远程仓库拉取镜像到本地,默认tag(版本号)是lastest
OPTIONS:-a:拉取所有tagged镜像
如:docker pull centos表示拉取最新的centos镜像到本地
docker rmi【OPTIONS】镜像ID/仓库名:镜像名
删除本地仓库中的镜像
OPTIONS:-f:强制删除
docker run 【OPTIONS】【镜像ID/仓库名:镜像名】
包含两步操作:
1.将镜像放到容器中
2.启动容器,相当于docker start
1.将镜像放到容器中
2.启动容器,相当于docker start
OPTIONS:
1)-i:以交互模式运行,通常与-t一起使用简写为-it
2)-d:以后台程序运行,并发挥容器ID
3)-p:指定端口映射,宿主机端口:容器端口
4)--name:为容器指定一个名字
1)-i:以交互模式运行,通常与-t一起使用简写为-it
2)-d:以后台程序运行,并发挥容器ID
3)-p:指定端口映射,宿主机端口:容器端口
4)--name:为容器指定一个名字
框架工具
技术选型
Dubbo + Zookeeper
dubbo作为RPC调用框架,提供服务调用功能;zookeeper作为服务的注册中心
Spring Cloud
主要组件
Docker容器
主要解决的问题
Docker的安装
yum -y install docker
相关概念
镜像
自定义镜像
两种方式
通过Dockerfile文件快速创建镜像
编写Dockerfile文件,然后执行docker build命令创建镜像
使用docker commit命令从容器创建一个新的镜像
仓库
本地镜像仓库
远程镜像仓库
容器
常用命令
docker login 【OPTIONS】【SERVER】
登录到一个Docker镜像仓库
docker search 【OPTIONS】TERM
搜素远程仓库镜像,如docker search centos表是与centos相关的镜像
docker pull 【OPTIONS】NAME【:TAG|@DISGEST】
从远程仓库拉取镜像到本地,默认tag(版本号)是lastest
OPTIONS:-a:拉取所有tagged镜像
如:docker pull centos表示拉取最新的centos镜像到本地
docker rmi【OPTIONS】镜像ID/仓库名:镜像名
删除本地仓库中的镜像
OPTIONS:-f:强制删除
docker run 【OPTIONS】【镜像ID/仓库名:镜像名】
包含两步操作:
1.将镜像放到容器中
2.启动容器,相当于docker start
1.将镜像放到容器中
2.启动容器,相当于docker start
OPTIONS:
1)-i:以交互模式运行,通常与-t一起使用简写为-it
2)-d:以后台程序运行,并发挥容器ID
3)-p:指定端口映射,宿主机端口:容器端口
4)--name:为容器指定一个名字
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容器
exit 或 Ctrl+D命令退出并销毁当前docker容器
Ctrl+P,Ctrl+Q也可退出,且不会销毁docker容器
端口映射
命令格式:
docker run -p 宿主机端口:容器端口
docker run -p
docker run -p 宿主机端口:容器端口
docker run -p
-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
-p 80:80 : 将容器的80端口映射到主机的80端口
-- name mynginx : 将容器命名为mynginx
如创建并启动MySQL容器:
docker run --name mysql -p 3306:3360 -v /var/lib/mysql/:/var/lib/mysql/ -e MYSQL)ROOT)PASSWORD=123 -d mysql:5.7
其中 --name指定容器已mysql命名,-p指定端口映射,-v 指定挂载宿主机目录,-e指定环境变量,-d指定镜像
docker run --name mysql -p 3306:3360 -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 ps:查看正在运行的容器
docker ps -a : 查看所有的容器,包括已经停止的、
docker imahes 【OPTIONS】【REPOSITORY】【:TAG】
查看本地有哪些镜像
docker logs <容器名或ID>
查看容器日志
docker port <容器名或ID>
查看容器端口映射情况
docker exec -it <容器名或ID> bash
以交互模式进入正在运行的容器,输入exit则退出
Jenkins持续集成工具
消息队列
Zookeeper
1.基本概念
2.基本原理
3.重要概念
1.概述
2.会话(Session)
3.Znode
4.版本
5.Watcher
6.ACL
4.ZooKeeper特点
1.顺序一致性
2.原子性
3.单一系统映像
4.可靠性
5.ZooKeeper 设计目标
1. 简单的数据模型
2.可构建集群
3.顺序访问
4.高性能
5.ZooKeeper 集群角色介绍
6. ZooKeeper &ZAB 协议&Paxos算法
1.ZAB 协议&Paxos算法
2.ZAB 协议介绍
3. ZAB 协议两种基本的模式:崩溃恢复和消息广播
7.ZooKeeper安装使用
ActiveMQ
RabbitMQ
RocketMQ
1.RocketMQ入门
2.快速安装
3.简单的消息示例
4.基于 Spring 使用 RocketMQ 以及监控
5. 基于 Spring Boot 使用 RocketMQ
6.原理与实践
Kafka
1.简介
1.概述
2.消息系统介绍
3.点对点消息传递模式
4.发布-订阅消息传递模式
2.Kafka的优点
1.解耦
2.冗余(副本)
3.扩展性
4.灵活性&峰值处理能力
5.可恢复性
6.顺序保证
7.缓冲
8.异步通信
3.Kafka中的术语解释
1.概述
2.broker
3.Topic
4.Partition
5.Producer
6.Consumer
7.Consumer Group
8.Leader
9.Follower
性能优化
性能指标
硬件层面
软件层面
响应时间
指系统对请求作出相应的时间,通常包括客户端响应时间,网络响应时间和服务端响应时间
吞吐量
并发用户数
性能测试
Jmeter
硬件优化
CPU、内存、磁盘
数据库SQL优化
分析SQL执行计划
MySQL使用explain命令
如explain select ...
Oracle 使用 explain plan for 命令
如 explain plan for select ...
SQL语句优化
建立及优化索引
索引类型
单值索引
唯一索引
复合索引
索引结构
BTree
Hash
full-text全文索引
R-Tree
JVM参数调优
内存泄漏
内存使用后未得到及时释放,而且不能被GC回来,导致虚拟机不能再次使用该内存
内存溢出OOM
即OutOfMemoryError,当没有足够的空闲内存可供程序使用时出现
常见类型
Java Heap Space:Java堆内存溢出
此种情况最常见,一半由于内存泄漏或者堆大小设置不当引起
对于内存泄漏,需要通过内存监控软件(如heapdump)查找程序中的泄漏代码;而堆大小可通过设置JVM的参数-Xms、-Xmx来解决
对于内存泄漏,需要通过内存监控软件(如heapdump)查找程序中的泄漏代码;而堆大小可通过设置JVM的参数-Xms、-Xmx来解决
PermGen Space:永久带内存溢出
即方法去内存溢出,如果程序加载的类过多,或者使用反射,gclib等动态代理生成类的技术,就可能导致该去发生内存溢出。
此种情况可以通过更改方法区的大小来解决,设置-XX:PermSize=64m -XX:MaxPermSize=256m参数。
另外,过多的常量尤其是字符串也会导致方法区溢出,因为常量池也位于方法区中。
此种情况可以通过更改方法区的大小来解决,设置-XX:PermSize=64m -XX:MaxPermSize=256m参数。
另外,过多的常量尤其是字符串也会导致方法区溢出,因为常量池也位于方法区中。
注:从Java8开始移除了Permgen Space,取而代之的是MetaSpace。
StackOverError:栈溢出
即虚拟机栈或本地方法栈区域内存溢出
出现原因:程序中出现死循环或者递归次数过多;也可能是栈大小设置过小导致,可通过设置-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++)进行实现,可以提高程序执行xiaolv
JDK中使用了很多native方法,如System类中的arraycopy,currentTimeMillis方法等
收藏
0 条评论
下一页