前后端进行交互依靠的是HTTP协议
前端三剑客:
- html
- css
- js(javascript)
一、 html
html不是一门编程语言,而是一种用来告知浏览器如何组织页面的标记语言
-
form get/post 提交 -
div 块级元素 <div> 我爱我的祖国</div>
具有换行作用,是一个块级元素
-
段落元素 <p> 我爱我的祖国 </p>
具有换行的作用,行与行之间的间隙较大
-
strong 强调 <strong>我爱我的祖国</strong>
-
br 换行 <br> 没有闭合标签,换行之后的间隙小
-
img src 图片 (空元素) <img title="我的图片" src = "图片地址源"> title是当图片显示不出来的时候,就会显示这几个字(属性)
title:属性名称 我的图片:属性值
-
input <input type = "text" disabled> disabled代表使得input不能输入
<input type = "text" disabled="true">
<input type = "text" disabled="false">
<input type = "text" disabled="随便些什么"> 这三个和第一个的作用是相同的
-
textarea 多行文本 -
a herf 超链接 <a target = "_black" href = "https://www.baidu.com/">我的收藏</a>
其中target="_black" 代表用新页面打开链接,不加这个只有后半句代表在当前页面刷新跳转
-
标题 h <h1>字体最大的标题</h1>
<h2></h2>
<h3></h3>
<h4>块级标签</h4>
<h5>有换行的作用</h5>
<h6>最小的标题</h6>
-
有序列表 ol <ol>
<li>油条</li>
<li>豆浆</li>
</ol>
- 油条
- 豆浆
-
无序列表 ul <ul>
<li>油条</li>
<li>豆浆</li>
</ul>
- 加粗 b
二、 css
- margin-top、left 边距
- text-algin:centent 居中
- 颜色 color
CSS是用来美化前端页面的,是一种样式规则语言
<style>
.fun{
margin-left: 480px;
margin-top: 10px;
font-size: 20px;
}
</style>
<body>
<div class="fun"> <!-- 这样的代码就是调用上面的方法样式 -->
数字1:<input id="num1" type="number" placeholder="请输入数字1">
</div>
<div class="fun">
数字2:<input id="num2" type="number" placeholder="请输入数字2">
</div>
</body>
<style>
div{
margin-left: 480px;
margin-top: 10px;
font-size: 20px;
}
</style>
三、js(JavaScript)
a. 创建动态更新的内容 b. 实现接口调用
-
dom 原生的js操作dom docment.getElementBy("id").value = "";
jQuery来操作dom(兼容性,操作简洁) jQuery("#id").val("");
innerHtml -> jQuery("#id").html("")
innerText -> jQuery("#id").text("")
属性操作:jQuery("#id").attr("属性名","value")
内嵌:<iframe src = "网址" style = "width = 100%; height = 600px;"></iframe>
原生的js操作的代码 使用jQuery操作示例 jQuery是一个快速、简洁的JavaScript框架,jQuery就是用javascript更加方便的查询和控制页面控件 jQuery 属性操作和内嵌操作的代码示例
-
自己的逻辑处理 变量的声明:var count = 1;
var str = "";
if、for、while
信息的弹出框:alter
选择框:confim
信息的打印:console.log("")
四、网络 -> 协议
1.HTTP协议(超文本传输协议,前后端交互的基础)
IP是逻辑地址,不好看,一般用域名(应用层协议DNS,DNS是一整套从域名映射到IP的系统),域名定位网络上的主机,端口号定位进程
http: //www.baidu.com:80
协议名:域名(ip) :端口号(可以省略)/ 目录 / 页面地址 参数 标识符
http/https 参数是以?开头的,多个键值对(每个键值对就是一个参数),每个键值对使用=区分,每个键值之间用&分割
http的默认端口号:80 https默认端口号:443
编码和解码:为了正常的实现前后端的交互的,为了保证URL的传输格式正确性
2.HTTPS:超文本传输安全协议
??https是在http的基础上实现的,http传送数据都是明文传输的,包括账号和密码,很容易被窃取,很明显不安全,所以有了https,https可以简单的理解为多加了一层加密解密层,需要用到SSL证书。
3. HTTP协议格式
Request 请求对象
-
首行(方法类型 URL 版本号) 方法类型:get/post
get:在url里面直接传参
post:隐藏参数传递,post没有长度限制;post方式用form表单进行提交
版本号:
http1.0 请求方法:post,get,head
http1.1(主流) 请求方法:post,get,head,options,put,delete,trace,connect
-
Header:请求的属性,冒号分割的键值对;每组属性之间使用\n分割 -
空行:代表Header部分结束 -
Body :如果为get请求时body为空,参数在首行url中;如果是post请求方式,Body有值,会有一个Content-Length属性来标识Body的长度
Response 响应对象
- 首行(版本号 状态码 状态的描述信息)
- Header
- 空行:Header的结束
- Body:如果服务器返回了一个html页面,那么html页面就是在body中
常见的Header信息:
-
Content-Type:格式(数据类型) text/html
appliaction/json
image/jpg(png) 图片
text/css :请求响应类型是CSS
application/JavaScript:请求响应类型是js
-
Content-Length:body的长度 -
Content-CharacterEncoding:编码格式 -
Host:客户端告知服务器,所请求的资源是哪个主机的哪个端口上 -
User-Agent:客户端访问设备信息 -
Cookie:客户端和服务器端保证身份识别的信息 -
location:搭配3××状态码使用,告诉客户端接下来要去哪里访问 -
referer当前页面是从哪个页面跳转过来的
HTTP状态码
-
1XX:信息描述 -
2XX:成功相关的 200表示请求和响应是成功的
-
3XX:跳转相关 301 永久重定向
302 临时重定向
-
4XX:客户端错误 404 未找到当前页面(客户端的问题,可能字母拼错了)
400 服务器不理解请求
405 在请求中被指定的方法是不允许的
401 402 权限不够,不能访问(可能是未登录的状态)
403 禁止访问(不允许客户端访问)
-
5XX:服务器错误信息 500 服务器端遇到了意外的情况(比如客户端传参不完整,出现空指针异常等)
502 服务器从上游服务器未接受到响应
504 网关超时(网络异常)
4.HTTP VS HTTPS
??http传送信息都是明文传送,很容易被窃取,在现有的互联网的应用中,很明显有不安全因素,所以有了https,可以理解为https多加了一层加密解密层,在发送前加密,在收到后解密,在网络中传输的都是经过加密的数据。
5. TomCat
TomCat是http服务器,开源免费的Servlet容器:发布部署应用程序 Tomcat是Java Servlet,JavaServerPages,Java Expression Language和JavaWebSocket(Java EE)技术的开源实现。
- 因为可以通过HTTP提供HTML页面等静态内容的请求访问,所以是一个WEB服务器;
- 因为实现了Servlet规范,所以也是一个Servlet容器,可以运行Servlet程序;
- 因为可以通过Servlet容器,调用Servlet处理动态请求,所以也是一个应用服务器;
- 所以,可以说Tomcat是Java(EE) WEB应用服务器。
TomCat安装之后的目录:
bin 存放各种启动,停止脚本的,.sh是在Linux上使用的 .bat是在windows上面使用的
logs tail -f cat...out 产生日志,定位问题
webapps war包或者jar包只能放在根路径,存放发布的项目
conf/server.xml -> 配置TomCat端口号 , 乱码问题的解决
端口号被占用的解决方案:
1.更换端口号
2.重启 (将所有的程序关闭)
3.kill -9 pid(找到是哪个程序占用了端口号,然后关闭)
TomCat不能直接运行程序员写好的.java程序,只能运行jar包或者war包
6. Maven 构建和发布java程序的工具。
maven是用来管理项目的工具,不使用maven的时候,jar包下载繁琐(jar包版本不同)
(1)maven的作用
- 外部jar管理(用来下载外部引用)(pom.xml)
- 打包项目,生成jar或war包
- 将打包的项目发布到TomCat上面运行
(2)Maven 出现问题的解决方法
- 将中央仓库的地址更换为国内
- 将本地仓库的jar包清空,重新下载三遍以上
- 关闭杀毒软件,防火墙
在pom.xml里面配置各种项目所需要的依赖
(3)Google -> Gradle(构建工具)、Maven
Maven VS Gradle
- Maven 依靠的是xml 来管理引用;Gradle使用的是Gradle 脚本来管理引用
- Mavel xml 的配置比较繁琐,而Gradle比较 简洁
- Gradle 性能更高(Gradle使用的是增量式解决方案)
- Gradle脚本是非常灵活的
7. Servlet
(1)什么是Servlet
?? Java Servlet 是运行在Web服务器或者是应用服务器上的程序,它是作为Web浏览器或其他HTTP客户端的请求和HTTP服务器上的数据库或应用程序之间的中间层
(2)作用
?? 其主要功能在于交互式的浏览和修改数据,生成动态的Web内容
(3)Servlet 项目路由注册
- web.xml 里面配置信息
- 注解: @WebServlet("/userlist")
(4)Servlet 项目的关键实现
(创建servlet项目要引入setvlet依赖,Servlet API有3个Java包:javax.servlet, javax.servlet.http, javax.servlet.annotation)
-
继承HttpServlet -
重写doGet/doPost/doDelete/… request、response
拿到接口的请求信息
将信息返回给接口
前端通过ajax访问后端
ajax -> jQuery.getJSON('url',{参数},function(data){});
getJSON请求的方式是doGet方法
(5) Servlet 执行流程(也就是生命周期)(面试题)
- init方法(只执行一次,创建Servlet项目的时候加载Servlet框架)
- service(doGet/doPost)【可以调用多次】
- destory 销毁方法(执行一次)
(6)Cookie VS Session
session和cookie存在的原因:http协议是无状态协议,就是说这一次请求和上一次请求是没有任何关系的,互不认识的,没有关联的。这种无状态的好处就是快速。坏处是需要进行用户状态保持的情景时(登录转台下进行页面跳转,或者用户信息多页面共享场景),必须使用一些方式或者手段,比如:session和cookie
-
Cookie以文本格式存储在客户端(浏览器端),Session存储在服务器端(session的默认有效期是30分钟) -
Cookie 可以很容易的进行修改和伪造,所以Cookie的安全级别比较低 -
Session 机制实现依靠的是SessionId,而SessionId放在客户端的,存储在Cookie里面,当禁用了本地Cookie之后,Session就用不了了 -
Session和Cookie他的大小是不同的,通常情况下,Cookie有大小限制,一般浏览器Cookie的限制是4K(原因:每次发起http请求,都要携带有效cookie信息,所以cookie一般都有大小限制,以防止增加网络压力) request.getCookie -> Cookie[]
response.addCookie(T) -> new Cookie(); (T是一个对象)
request.getSession() -> (传递true或者不传递参数的时候)先获取Session,如果获取不到,则创建一个Session。【第一次登录的时候使用】
request.getSession() -> 从request获取Session,如果获取不到,不创建Session。【进行权限校验的时候使用】
8. Linux -> CentOS
操作系统 | 优点 | 缺点 |
---|
Windows | 图形化界面,操作简单 | 图形化的界面导致很多额外的性能开销(不适合普通用户) | Linux | 性能较高 | 操作复杂 | MacOS | UI设计非常美观,比Linux操作简单,比Windows性能开销少 | 没有Linux性能高,没有Windows操作简单 |
Linux(内核) 内核 != 操作系统 操作系统:内核+配套的软件
(1)Linux环境的搭建方式
- 直接安装在物理机上,但是由于Linux桌面使用起来非常不友好,不推荐
- 使用虚拟机软件,将Linux搭建在虚拟机上,但是由于当前的虚拟机软件存在一些BUG,会导致环境上出现各种各样的问题
- 使用云服务器(使用XShell远程登陆服务器)
(2)Linux基本操作:
-
目录:ls/cd/pwd ls 显示当前的目录下面的所有的目录与文件
pwd 显示用户当前所在的目录
-
文件:touch /cat / echo(内容写入) touch 文件
echo "hello" > text.txt (内容覆盖)
echo "java" >> text.txt (内容追加)
cat 文件名 展示文件的详情
-
文件夹 rm -f 文件删除
rm -i 删除前注意询问确认
rm -r 删除目录及其下所有文件,会逐一询问
创建文件夹:mkdir a(创建单个路径)
mkdir -p a/b/c (创建多个路径(目录))
文件移动:mv 旧地址 新地址 (将旧地址里面的内容移动到新地址(如果新地址不存在,就创建并移动内容到这里),然后删除旧地址)
文件的拷贝: cp 旧地址 新地址 (如果新地址不存在,创建新地址并将就地址的内容移动到新地址里面)
-
查看帮助文档:man -
日志 cat 全量查询
less 文件/目录 查询少量文件 less -n 文件 显示的行数
head 文件 查看日志开头的内容
tail 文件 查看最后的日志 tail -f 日志(动态展示)
-
查看所有运行的java程序: ps -ef grep java -
关闭某一个进程: kill -9 pid
五、进阶的主要内容
- 网络
- 多线程编程
- JVM
1. 网络部分
(1)OSI 7 层模型
- 应用层:将标准的协议转换成程序专业协议 HTTP:80 ? HTTPS ? DNS:53 ? FTP:21 ? SSH:22 ? TELNET:23 ? SMTP
- 表示层:设备格式到标准格式的转换(将网络信息包转换成程序需要的数据结构)
- 会话层:用来管理通信双方之间的会话(负责建立和断开连接) SSL
- 传输层:管理两个节点的数据传输,用来确保两个节点的数据的可靠传输 TCP/UDP(用来填写收件人和发件人信息的)
- 网络层:用来管理地址和路由选择的(选择传递的方式,选择合适的协议) IP协议
- 数据链路层:用来确保相邻节点之间的数据传递(确定具体的路线),互联设备之间传送和识别数据帧
- 物理层:将数据转换成光电信号
七层模型详解
(2)TCP/IP 4 层模型
传输层数据传输5要素:
- 目的IP
- 目的端口号
- 源地址IP
- 源地址端口号
- 协议类型
(3)数据包分装和分用
- 不同的协议层对数据包有不同的称谓,在传输层叫段,在网络层叫数据包,在数据链路层叫帧
- 应用层数据通过协议栈发送到网络上的时候,每层协议都要加上一个数据首部,称为封装
- 首部信息中包含一些类似于首部有多长,上层协议是什么等信息
- 数据封装成帧之后发到传输介质上,达到目的的主机后每层协议在剥掉响应的首部,根据首部中的“上层协议字段”将数据交给对应的上层协议处理
(4)IP地址,MAC地址
IP协议两个版本:IPV4,IPV6
- IP地址是在IP协议中,用来标识网路中不同主机的地址
- 对于IPV4来说,IP地址就是一个4字节,32位的整数
- 通常使用“点分十进制” 的字符串标识IP地址,比如:192.168.0.1;用点分割的每一个数字标识一个字节,范围是0-255
MAC 地址(网络地址,物理地址)
- MAC地址用来识别数据链路层中相连的节点
- 长度位48位,即6个字节,一般用16进制加上:的形式来表示(08:00:27:03:fb:19)
- 在网卡出厂之后就确定了,不能修改,MAC地址是唯一的
IP VS MAC
- 组成的长度不同
- 传输的作用不同,IP网络中的两个节点的数据传输使用(路途的起点和终点),相邻设备的数据传输依靠的是MAC(路途上每一个区间的起点和终点)(IP找交换机,MAC找具体的客户端)
一台计算机可以绑定多个网卡,进而可以拥有多个MAC地址,一个MAC地址可以对应多个IP地址,使网络更加灵活
(5)传输层
- 端口号划分,端口号标识了一个主机上进行通信的不同的应用程序
- 著名端口号:0-1023 ssh:22 ftp:21 telnet:23 http:80 https:443 tomcat:8080 mysql:3306
- 动态端口号:1024 - 65535
面试题:端口的作用:确定机器中运行的进程
- 一个端口可以被多个进程使用吗?不可以
- 一个程序可以有多个端口号吗?可以
传输层:TCP、UDP
UDP:无连接,不可靠,面向数据报 UDP 缓存区:没有发送缓冲区,有接收缓冲区(接收缓冲区不能保证收到的UDP报的顺序和发送UDP报的顺序相同,如果缓冲区满了,在到达UDP的数据就会被丢弃)
UDP的使用场景(基于UDP的应用层协议):
- DNS:域名解析协议
- NFS:网络文件的传输
- TFTP:简单文件传输协议
- DHCP:动态主机配置协议
- BOOTP:启动协议
TCP:有连接,可靠,面向数据流 TCP 10 大特性(保证TCP的稳定性)
-
确认应答(ACK) TCP将每个字节的数据都进行了编号,即为序列号,每个ACK都带有对应的序列号,意思告诉发送者,我收到了哪些数据,下一次从哪里开始发送数据
-
超时重传:解决确认应答非正常情况 导致超时重传的原因有两个:数据未发送到接收端,接收端给发送端发送的ACK丢失 如果是因为ACK丢失,那么发送方也会继续重新发送数据给接收方,此时接收方就会收到很多的重复数据,但是TCP协议可以识别出重复的包,并且将重复的包丢掉(利用序列号做到去重的效果)
超时的时间的确定: 策略1:发送时间间隔以指数级增长
超时以500ms为一个单位时间进行控制,每次判定超时重发的时间都是500ms的整数倍
重发一次得不到响应,等待2*500ms后再次重发
如果任然得不到应答,等待4*500ms进行重传,以此类推,指数形式递增
策略2:在发送了一定次数之后,如果还没有响应,此时会停止发送
即使确认对方下线了,还是会以固定的频率发送检测包,探测对方是否上线
-
连接管理 TCP三次握手四次挥手详解 -
滑动窗口 一发一收的方式性能较低,所以一次发送多条数据,就可以大大提高性能 操作系统为了维护这个滑动窗口,需要开辟发送缓冲区来记录当前还有哪些数据没有应答,只有确认应答过的数据,才会从发送缓冲区里面删除掉 当某一段报文段丢失之后,发送端会一直接收到1001这样的ACK,就是在告诉发送端我没有收到这一段信息,请重新发送
如果发送端连续三次收到了同样的一个1001,就会把TCP头部的紧急指针设置为true,并且将16位紧急指针设为1001,然后将1001-2000对应的数据重新发送
接收端收到1001之后,再次返回的ACK就是7001了,因为后面的数据在开始的时候其实就已经收到了,被放到了接收端操作系统内核的接收缓冲区里面了
这种机制也被称为 快重传
-
流量控制(接收端的接收缓冲区的大小) 接收端处理数据的速度是有限的,如果发送端发送的太快,会导致接收端的缓冲区被装满,这个时候如果发送端继续发送,就会造成丢包,从而引起丢包重传等一系列的反应 TCP支持接收端的数据处理的能力来控制发送端的发送速度 接收端将自己可以接收的缓冲区大小放入TCP首部中的“窗口大小”字段,通过ACK发送给发送端
窗口大小字段越大,说明网络的吞吐量越高。
根据接收缓冲区的实际大小来决定下一次数据传递的大小
会动态控制滑动窗口的大小
在刚开始发送消息的时候,并不是直接发送很大的数据,而是发送端首先会发送少量信息,接收端给发送端一个响应,同时给窗口大小设置值,代表接收端的接收能力,滑动窗口的大小根据窗口大小进行调节
-
拥塞控制(网络的状态)
根据当前网络情况来决定消息的发送策略
慢启动
少量的丢包,仅仅触发超时重传,大量的丢包,就认为是网络拥塞
-
延迟应答 如果接收数据的主机接收到数据之后立刻返回ACK应答,这时候返回的窗口可能比较小,可能接收端的梳理数据的能力很强,很快就将数据处理掉了,这个时候在返回ACK时窗口的大小就变大了 策略:
a) 以固定的次数实现延迟应答
b) 以固定的时间来实现延迟应答
注意延迟应答的时间不要超过超时重传的时间,否则会触发超时重传
-
捎带应答 将多次应答合并为一次
-
面向数据流 沾包半包(应用层的数据包)
在TCP的协议头中,没有像UDP一样的“报文长度”这样的字段,但是有一个序号这样的字段,
站在传输层的角度,TCP时一个一个报文过来的,按照序号拍好放到缓冲区里面
站在应用层的角度,看到的只是遗传连续的字节数据,就不知道从哪个部分开始到哪个部分结束是一个完整的应用层数据包了
解决方案:
1.固定大小的发送数据(消息的长度不够的时候使用空格占位)
2.表示明确的边界,比如使用 \n 作为结束符号
-
异常处理的特性 有反应时间的异常:重启电脑,关闭进程,和正常关闭一样
没有反应时间的异常:掉电、断网,TCP健康检测机制,每隔一段时间询问一下是否正常,没有反应在进行关闭
基于TCP的应用层协议
- HTTP:超文本传输协议
- HTTPS:超文本传输安全协议
- SSH:安全外壳协议
- Telnet:INternet远程登录服务的标准协议
- FTP:文件传输协议
- SMTP:电子邮件传输协议
面试题:如何让UDP稳定传输 答案就是让UDP实现TCP的功能
(6)网络层
IP协议的协议头
- 4位版本号:指定IP协议的版本,对于IPV4来说,就是4
- 8位服务类型:3位优先权字段(弃用),4位TOS字段,和一位保留字段(为0),4位TOS字段相互冲突,只能选择一个。
- 16位标识:唯一的标识主机发送的报文,如果IP报文在数据链路层被分片了,,那么每一个片里面的这个id都是相同的
- 3位标志:第一位不用,第二位为1标识禁止分片,这时候如果报文长度超过MTU,IP模块就会丢弃报文,第三位表示更多分片。
- 13为分片偏移:是分片相对于原始IP报文开始处的偏移,确定先后顺序,正确组包
- 8位协议:上层协议的类型
- 16位头部校验和:使用CRC进行校验,来鉴别头部是否损坏
IP地址分为两个部分,网络号和主机号
- 网络号:保证相互连接的两个网段具有不同的标识
- 主机号:同一网段内,主机之间具有相同的网络号,但是必须具有不同的主机号
IP地址分类:
- A类:0.0.0.0到127.255.255.255
- B类:128.0.0.0到191.255.255.255
- C类:192.0.0.0到223.255.255.255
- D类:224.0.0.0到239.255.255.255
- E类:240.0.0.0到247.255.255.255
因为上面的IP地址的分类方式会导致很多的IP地址浪费的情况,就出现了新的IP地址的划分方案:CIDR
- 引入额外的子网掩码来区分网络号和主机号
- 子网掩码是一个32位的正整数,通常用一串0来结尾
- 将IP地址和子网掩码进行按位与操作,得到的结果就是网络号
- 网络号和主机号的划分与这个IP地址是ABC类无关
将IP地址中的主机地址全部设为0,就成为了网络号,代表这个局域网 将IP地址中的主机地址全部设为1,就成为了广播地址,用于给同一个链路中相互连接的所有主机发送数据包
(7)数据链路层
以太网中MTU(最大传输单元)的最大长度是1500字节
- MTU对IP协议的影响:由于数据链路层MTU的限制,对于较大的IP数据包要进行分包
- MTU对UDP的影响:一旦UDP携带的数据超过1472(1500-20(IP首部)-8(UDP首部)),那么就会在网络层分成多个IP数据报,这多个IP数据包一旦丢失,都会引起接收端网络层重组失败,那么就意味着如果UDP数据报在网络层被分片,真个数据丢失的概率就大大增大了
- MTU对TCP的影响:TCP的一个数据报也不能无限大,还是受制于MTU,TCP的单个数据报的最大消息长度,称为MSS(最大帧大小),在通信双方中选择较小的作为最终的MSS值(MSS值正好是在IP不会被分片处理的最大长度)
ARP协议:介于数据链路层和网络层之间的协议 ARP协议的作用:建立了主机IP地址和MAC地址之间的映射关系
面试题:当URL输入地址之后,会发生什么情况?
- 浏览器校验HTTP格式是否是有效的
- 查看浏览器缓存
- 如果没有缓存,去DNS服务器找到IP
- TCP 协议创建连接(三次握手)
- 将客户端所有的参数发送给服务器端
- 接收到客户端的消息,进行业务处理和数据库操作
- 再将数据返回给客户端
- 关闭TCP连接(四次挥手)
- 浏览器的执行引擎会解析返回的内容,并展示给用户。
2. 多线程编程
操作系统包括:内核和其他程序
(1)进程:操作系统分配资源的最小单位,是程序组成的实际单位(进程的本质是PCB,PCB就是一种结构体,是进程排队执行的)
- pid(进程主键id,两次启动同一个程序他的PID不同)
- 状态(创建,就绪,运行,阻塞,终止)
- 优先级
- 记账信息
- 上下文
- 一组内存(根据内存访问进程拥有的资源)
(2)时间片
- 操作系统调度任务是采用时间片轮转的抢占式调度方式,也就是说一个任务执行一小段时间后强制暂停去执行下一个任务,每个任务轮流执行
- 任务执行的一小段时间叫做时间片,任务正在执行的状态叫运行状态,任务执行一段时间后强制暂停去执行下一个任务,被暂停的任务就处于就绪状态等待下一个属于他的时间片的到来
进程的缺点:不能共享资源
并行:多个CPU多个任务 并发:多个任务,轮流执行,CPU的个数不足(微观上是抢占式执行的)
内核态:拥有的权限更多, 用户态:权限较小,执行权重较低
(3)线程
线程(并发编程的核心):操作系统执行任务的最小单位
进程 VS 线程
- 进程里面包含了线程,线程要依靠进程而存在
- 进程是系统分配资源的最小单位,而线程是操作系统执行任务的最小单位
- 进程里面实际执行单位就是线程,一个进程里面至少包含一个线程
- 线程是可以共享资源文件的,而进程不行
(4)线程的创建方式及方法
线程的创建方式:
-
继承Thread来实现 -
实现Runnable接口实现 -
实现Callable接口方式【有任务的执行返回值】 线程创建的具体的代码
线程的常见构造方法:
- 规定线程名称 Thread(String name)
- 将线程进行分组 Thread(ThreadGroup group, Runnable target)
- 指定任务
- 创建线程对象 Thread()
- 使用Runnable对象创建线程对象 Thread (Runnable target)
- 使用Runnable对象创建线程对象,并命名 Thread(Runnable target, String name)
面试题:线程的常用方法
-
start/run run() vs start()
1. run()方法是一个对象的普通方法,它使用的是主线程来执行任务的
2. start() 方法是线程开启的方法,它使用新的线程来执行任务
3. start() 方法只能执行一次,而run() 方法可以调用很多次
-
join等待线程执行结束 -
yield 让出cpu -
线程通信的方法:wait/notify/notifyall | LockSupport park/unpark (指定唤醒线程) 注意:
1)wait 必须配合synchronized 一起使用
2)wait 和synchronized 必须使用同一把锁(同一个对象)
3) wait在使用时会释放锁
-
其他:设置线程名,设置线程类型,设置优先级(默认优先级是5,优先级最大的是10)
面试题:sleep 和 wait 的区别!!!!! wait,notify使用以及常见面试题
线程中断:
public class Test2 {
static boolean flag = false;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (!flag) {
System.out.println("正在转账");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("有内鬼,终止交易");
}
}
System.out.println("啊,它是骗子啊,差点误了大事");
}
},"张三");
System.out.println(thread.getName()+"开始转帐了");
thread.start();
Thread.sleep(10000);
System.out.println("那人是骗子,快停止转账");
flag = true;
}
}
public class Test3 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("正在转账");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("有内鬼,停止交易");
break;
}
}
System.out.println("啊,它是骗子,差点误了大事");
}
},"里斯");
System.out.println("让里斯开始转账");
thread.start();
Thread.sleep(10000);
System.out.println("他是个骗子,快让里斯停止转账");
thread.interrupt();
}
}
??我们会发现使用系统的intrrupt()可以及时终止线程,即使线程处于休眠状态也可以终止;而使用自定义全局变量终止线程的方式比较温柔,不能立即终止。
重点说一下通过thread对象调用interrupt()方法通知该线程停止运行
- 如果线程调用wait/join/sleep等方法而阻塞挂起,则以InterriptedException异常的形式通知,清除中断标志
- 否则,知识通过内部的一个中断标志被设置,thread可以通过:
?Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志 ?Thread.currentThread().isInterrupted()判断指定指针线程的中断标志被设置,不清除中断标志
(5)线程状态
(6)线程安全问题
线程安全问题详解
- CPU抢占式执行
- 原子性
- 编译器优化(指令重排序)
- 同一时间多个线程同时修改同一个变量
- 内存可见性
保证线程安全的手段
- 加锁:synchronized、手动锁
- ThreadLocal
synchronized三种使用场景:
- 修饰静态方法
- 修饰普通方法
- 修饰代码块
面试题:synchronized实现原理
- JVM层面
- java层面
- 操作系统层面:互斥锁
synchronized的执行过程(synchronized的优化):无锁,偏向锁,轻量级锁,重量级锁
手动锁Lock
- lock放在try里面
- finally里面执行unlock
轻量级锁:volatile - > 内存可见性,禁止指令重排序
(7)死锁
死锁问题详解
死锁的4个条件
-
互斥条件 -
请求拥有条件(解决死锁的入口) -
不可剥夺条件 -
环路等待条件(解决死锁的入口) 死锁的常见解决方案:使用一定的顺序来获取
(8)线程池
- 控制线程的个数和任务数
- 有更好的拒绝策略
- 可以复用线程
- 拥有更多的功能(延迟任务执行)
线程池的7种创建方式
- 创建固定个数的线程池
- 创建带有缓存池的线程池
- 创建执行定时任务的线程池
- 单机版的执行定时任务的线程池
- 创建单个线程的线程池 -> 1.复用线程; 2.更好的分配和执行任务
- JDK1.8,根据当前的CPU和任务数来创建线程池(异步线程池)
- 原生的创建方式 ThreadPollExcutor
线程池创建方式1 线程池创建方式2
ThreadPollExcutor 7 大参数
ThreadPollExcutor 的执行流程
拒绝策略:
JDK自带的拒绝策略
- 不执行任务,抛出异常(默认的拒绝策略)
- 使用调用的线程来执行任务
- 舍弃任务
- 舍弃旧任务
自定义拒绝策略
拒绝策略的具体实现在线程池的创建的那篇博客里面都有,希望小伙伴们可以好好学习。
|