同步异步阻塞非阻塞
同步与异步
实际上同步与异步是针对应用程序与内核的交互而言的。同步过程中进程触发IO操作并等待或者轮询的去查看IO操作是否完成。异步过程中进程触发IO操作以后,直接返回,做自己的事情,IO交给内核来处理,完成后内核通知进程IO完成。同步与异步如下图所示:
阻塞与非阻塞
简单理解为需要做一件事能不能立即得到返回应答,如果不能立即获得返回,需要等待,那就阻塞了,否则就可以理解为非阻塞。
什么是Servlet
Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
重点理解:Servlet 编写过滤器
Servlet 和 Filter 的比较
servlet:servlet是一种运行服务器端的java应用程序,具有独立于平台和协议的特性,并且可以动态的生成web页面,它工作在客户端请求与服务器响应的中间层。
filter:filter是一个可以复用的代码片段,可以用来转换HTTP请求、响应和头信息。Filter不像Servlet,它不能产生一个请求或者响应,它只是修改对某一资源的请求,或者修改从某一的响应。
详解:filter与servlet的比较(概念 、 生命周期 、职责 、执行过程)
什么是中间件
中间件是一类独立的系统软件或服务程序,分布式应用软件借助这种软件在不同的技术之间共享资源。中间件位于客户机/服务器的操作系统之上,管理计算机资源和网络通信。
常见的有如下几种:服务中间件、集成中间件、数据中间件、消息中间件、安全中间件。
用Java实现的中间件,统称Java中间件。中间件,可以理解为类库,介于类库和产品之间。
说简单一点,就是你的程序A和程序B互相通信使用的协议,程序A,B可以由不同语言不同平台构建。但是协议可以保证他们能互相认识互发的东西。
举例:
1 , RMI ( Remote Method Invocations, 远程调用)
2 , Load Balancing( 负载均衡,将访问负荷分散到各个服务器中 )
3 , Transparent Fail-over( 透明的故障切换 )
4 , Clustering( 集群 , 用多个小的服务器代替大型机)
5 , Back-end-Integration( 后端集成,用现有的、新开发的系统如何去集成遗留的系统 )
6 , T ransaction 事务(全局 / 局部)全局事务(分布式事务)局部事务(在同一数据库联 接
内的事务)
7 , Dynamic Redeployment ( 动态重新部署 , 在不停止原系统的情况下,部署新的系统)
8 , System Management( 系统管理 )
9 , Threading( 多线程处理 )
10 , Message-oriented Middleware 面向消息的中间件(异步的调用编程)
11 , Component Life Cycle( 组件的生命周期管理 )
12 , Resource pooling (资源池)
13 , Security (安全)
14 , Caching (缓存)
什么是反射
定义:
用一句话来解释反射的定义:自控制,自描述。即通过反射可以动态的获取类、属性、方法的信息,也能构造对象并控制对象的属性和行为。
应用:
JDBC的驱动加载方式是通过反射机制实现的,JDBC只是设计了驱动需要实现的接口,并不关心驱动厂商的个数和实现方式,只要安装统一的规范即可,至于类型的判断和具体方法的触发,交给运行期动态判断即可,这种反射机制的使用淋漓尽致的体现了多态,并且降低了类与类之间的耦合度。
什么是面向对象
OOP , Object-Oriented Programming ,面向对象编程不同于面向过程编程:
1 ) OOP 关注对象和角色,也就是事物的本质
2) OOP 把客观世界中的对象抽象成对应的类;
3 )通过类构造实例;
4)通过依赖、继承、实现等形式建立对象间的通信关系
优点:
( 2 ) OOP 易于扩展,增加或改变业务的功能,无需大幅改动改变源代码
( 3 ) OOP 易于建模, OOP 就是软件架构师在计算机高级语言中对客观世界的抽象和
再现,
线程与线程池
附:JAVA多线程编程
POJO
简单的Java对象(Plain Ordinary Java Objects)实际就是普通JavaBeans
POJO有一些private的参数作为对象的属性。然后针对每个参数定义了get和set方法作为访问的接口。例如:
public class User {
private long id;
private String name;
public void setId(long id) {
this.id = id;
}
public void setName(String name) {
this.name=name;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
}
POJO对象有时也被称为Data对象,大量应用于表现现实中的对象。
简述cookies和session的区别
cookies:是针对每一个网站的信息,每一个网站只对应一个,其它网站不能访问,这个文件是保存在客户端的,每次你打相应网站,浏览器会查找这个网站的cookies,如果有就会将这个文件起发送出去。cookies文件的内容大致包函这些信息如用户名,密码,设置等,也可以是web服务器按照一定算法产生的只有Web服务器可以理解的数据,这些数据发送给客户端,客户端带着这些数据访问该网站才能被该网站识别。
从session: 是针对每一个用户的,只有客户机访问,程序就会为这个客户新增一个session。session里主要保存的是用户的登录信息,操作信息等。这个session在用户访问结束后会被自动消失(如果超时也会)。
简述Servlet与JSP的关系
最重要的一点就是 JSP就是servlet , jsp继承了servlet,JSP与Servlet主要有两方面的不同:编译:JSP修改后可以立即看到结果,不需要编译;而Servelt缺需要编译。转换:JSP是动态网页开发技术,是运行在服务器端的脚本语言,而Servlet是web服务器端编程技术。所以JSP运行时就是转换为Servlet,也就是java程序来执行。
作用范围:application > session > request > page
application所有用户,项目的所有页面
session:项目的所有页面(仅限于用户的一次登录)
request:仅限于用户的一次登录,只适用于一次请求,数据只能两个页面传输
page数据只在本页面可用
JSP内置对象有哪些,各自起到的作用
1、HttpServletRequest的 request对象
作用:代表请求对象,用来接收客户端通过http协议连接传输到服务器端的数据。
2、HttpServletResponse的response对象
作用:代表响应对象,用来向客户端发送数据。
3、JspWriter的 out 对象
作用:主要用于向客户端发送数据。其中JspWriter是out的基类。
4、HttpSession 的session 对象
作用:主要用于来分别保存每个用户的个人信息,与请求关联的对话。会话状态的维持是每个web应用开发者都必须面对的问题。
5、ServletContext的application对象
作用:主要用于保存用户信息,代码片断的运行环境。它是一个共享的内置对象。即一个容器中多个用户共享一个application对象,故其保存的信息被所有的用户所共享。
6、PageContext的PageContext对象
作用:管理网页的属性,为jsp页面包装页面的上下文,管理对属于jsp中特殊可见部分中已经命名对象的访问。它的创建和初始化的工作都是由容器来自动完成的。
7、ServletConfig的Config对象
作用:代码片断配置对象,表示对servlet的配置。
8、Object 的page(相当于this) 对象
作用:处理jsp网页,是object类的一个实例。即它也是jsp的本身,只有在jsp的页面范围之内它才是合法的。
9、Exception
作用:处理jsp页面执行时,发生的错误和异常。
常用的设计模式(伪代码),并简述应用场景
七大设计原则:
1、单一职责原则【SINGLE RESPONSIBILITY PRINCIPLE】:一个类负责一项职责.
2、里氏替换原则【LISKOV SUBSTITUTION PRINCIPLE】:继承与派生的规则.
3、依赖倒置原则【DEPENDENCE INVERSION PRINCIPLE】:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。即针对接口编程,不要针对实现编程.
4、接口隔离原则【INTERFACE SEGREGATION PRINCIPLE】:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少.
5、迪米特法则【LOW OF DEMETER】:低耦合,高内聚.
6、开闭原则【OPEN CLOSE PRINCIPLE】:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭.
7、组合/聚合复用原则【Composition/Aggregation Reuse Principle(CARP) 】:尽量使用组合和聚合少使用继承的关系来达到复用的原则.
附:Java23种设计模式
附:Java23种设计模式(经典)
HashMap实现原理及源码分析
HashMap实现原理及源码分析
HashMap和HashTable区别
HashTable
底层数组+链表实现,无论key还是value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低,ConcurrentHashMap做了相关优化
初始size为11,扩容:newsize = olesize*2+1
计算index的方法:index = (hash & 0x7FFFFFFF) % tab.length
HashMap
底层数组+链表实现,可以存储null键和null值,线程不安全
初始size为16,扩容:newsize = oldsize*2,size一定为2的n次幂
扩容针对整个Map,每次扩容时,原来数组中的元素依次重新计算存放位置,并重新插入
插入元素后才判断该不该扩容,有可能无效扩容(插入后如果扩容,如果没有再次插入,就会产生无效扩容)
当Map中元素总数超过Entry数组的75%,触发扩容操作,为了减少链表长度,元素分配更均匀
计算index方法:index = hash & (tab.length – 1)
HashSet和TreeSet的区别
HashSet
HashSet有以下特点
不能保证元素的排列顺序,顺序有可能发生变化
不是同步的
集合元素可以是null,但只能放入一个null
当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。
简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值相 等
注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对 象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。
TreeSet类
TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0
自然排序
自然排序使用要排序元素的CompareTo(Object obj)方法来比较元素之间大小关系,然后将元素按照升序排列。
Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现了该接口的对象就可以比较大小。
obj1.compareTo(obj2)方法如果返回0,则说明被比较的两个对象相等,如果返回一个正数,则表明obj1大于obj2,如果是 负数,则表明obj1小于obj2。
如果我们将两个对象的equals方法总是返回true,则这两个对象的compareTo方法返回应该返回0
定制排序
自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法。
最重要:
1、TreeSet 是二差树实现的,Treeset中的数据是自动排好序的,不允许放入null值。
2、HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束。
3、HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的 String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例 。
HashSet与HashMap的区别:
HashMap HashSet
实现了Map接口 实现Set接口
存储键值对 仅存储对象
调用put()向map中添加元素 调用add()方法向Set中添加元素
HashMap使用键(Key)计算Hashcode
HashSet使用成员对象来计算hashcode值,
对于两个对象来说hashcode可能相同,
所以equals()方法用来判断对象的相等性,
如果两个对象不同的话,那么返回false
HashMap相对于HashSet较快,因为它是使用唯一的键获取对象 HashSet较HashMap来说比较慢
JAVA集合框架
简述泛型、反射、注解应用场景及各自解决了哪些问题
泛型:
类型泛化,即由具体的、个别的扩大为一般的。就是通过类型参数化,来解决程序的通用性设计和实现的若干问题。比如:
编译器类型检查问题
强制类型转换问题
可读性,灵活性问题
泛型通配符约定:
<? extends T> 上界通配符
上界通配符顾名思义,<? extends T>表示的是类型的上界(包含自身),因此通配的参数化类型可能是T或T的子类。正因为无法确定具体的类型是什么,add方法受限(可以添加null,因为null表示任何类型),但可以从列表中获取元素后赋值给父类型。如上图中的第一个例子,第三个add()操作会受限,原因在于List<Animal>和List<Cat>是List<? extends Animal>的子类型。
<? super T> 下界通配符
下界通配符<? super T>表示的是参数化类型是T的超类型(包含自身),层层至上,直至Object,编译器无从判断get()返回的对象的类型是什么,因此get()方法受限。但是可以进行add()方法,add()方法可以添加T类型和T类型的子类型,如第二个例子中首先添加了一个Cat类型对象,然后添加了两个Cat子类类型的对象,这种方法是可行的,但是如果添加一个Animal类型的对象,显然将继承的关系弄反了,是不可行的。
<?> 无界通配符
在理解了上界通配符和下界通配符之后,其实也自然而然的理解了无界通配符。无界通配符用<?>表示,?代表了任何的一种类型,能代表任何一种类型的只有null(Object本身也算是一种类型,但却不能代表任何一种类型,所以List<Object>和List<null>的含义是不同的,前者类型是Object,也就是继承树的最上层,而后者的类型完全是未知的)。
反射
定义:
用一句话来解释反射的定义:自控制,自描述。即通过反射可以动态的获取类、属性、方法的信息,也能构造对象并控制对象的属性和行为。
应用:
JDBC的驱动加载方式是通过反射机制实现的,JDBC只是设计了驱动需要实现的接口,并不关心驱动厂商的个数和实现方式,只要安装统一的规范即可,至于类型的判断和具体方法的触发,交给运行期动态判断即可,这种反射机制的使用淋漓尽致的体现了多态,并且降低了类与类之间的耦合度。
注解
定义:可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。
应用:@Override @controller
Thread类的方法有哪些,如何多种方式实现线程同步
多线程有两种实现方法,一是继承Thread类,重写方法run(),二是实现Runnable接口,实现方法run();
同步有两种实现方法,分别是synchronized、wait与notify。
进程与线程的区别,JAVA中有哪些方式可以创建线程。
参考:java中进程与线程--三种实现方式
进程:系统分配资源的基本单位,资源独立
线程:系统(CPU)调度的基本单位,也是程序执行的最小单位。与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
关系:一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
创建方式:
继承自Thread类并重写 run() 方法,
实现 Runnable 接口并重写 run() 方法
使用callable和future创建线程
进程的五种基本状态
创建状态:进程在创建时需要申请一个空白PCB,向其中填写控制和管理进程的信息,完成资源分配。如果创建工作无法完成,比如资源无法满足,就无法被调度运行,把此时进程所处状态称为创建状态
就绪状态:进程已经准备好,已分配到所需资源,只要分配到CPU就能够立即运行
执行状态:进程处于就绪状态被调度后,进程进入执行状态
阻塞状态:正在执行的进程由于某些事件(I/O请求,申请缓存区失败)而暂时无法运行,进程受到阻塞。在满足请求时进入就绪状态等待系统调用
终止状态:进程结束,或出现错误,或被系统终止,进入终止状态。无法再执行
现有一学生表结构(student_id,class_id,name),请写出统计每班有多少学生的SQL语句
select class_id,count(*) from student group by class_id
假如你正在开发一个系统的登录程序,请简述你是如何实现记住用户名和密码这个操作的,并如何实现?
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%
String username = "";
String password = "";
//获取当前站点的所有Cookie
Cookie[] cookies = request.getCookies();
for (int i = 0; i < cookies.length; i++) {//对cookies中的数据进行遍历,找到用户名、密码的数据
if ("username".equals(cookies[i].getName())) {
username = cookies[i].getValue();
} else if ("password".equals(cookies[i].getName())) {
password = cookies[i].getValue();
}
}
%>
</head>
<body>
<form action="login_handler.jsp" method="post">
username:<input type="text" name="name" value="<%=username%>" /><br/>
password:<input type="password" name="pwd" value="<%=password%>" /><br/>
<input type="checkbox" value="y" name="isLogin">自动登录<br/>
<input type="submit" value="登录" />
</form>
</body>
</html>
controller:
@RequestMapping(value = "login", method = RequestMethod.POST)
public String login(String firstname, String lastname,ModelMap model,HttpServletRequest request,HttpServletResponse response) {
User user=userService.findByUsername(firstname);
if(user!=null && lastname!=null){
if(lastname.equals(user.getPassword())){
model.put("username", firstname);
HttpSession session = request.getSession();
session.setAttribute("users",user);
model.put("nowtime", new Date());
model.put("users", user);
String flag=request.getParameter("remember");
if("1".equals(flag)){
//创建两个cookie对象
Cookie namecookie=new Cookie("username",firstname);
//设置cookie的有效天为一周
namecookie.setMaxAge(60*60*24*7);
Cookie passcookie=new Cookie("password",lastname);
passcookie.setMaxAge(60*60*24*7);
response.addCookie(namecookie);
response.addCookie(passcookie);
}
return "redirect:/ toList.do";
}
}else{
model.put("error", "账号或密码错误");
return "manager/login";
}
return "manager/login";
}
在视图层不支持存储cookie,服务端不支持session的场景下如何保持用户登陆状态。
视图层生成并发送sessionID(视图层的每一次浏览器请求都携带此sessionID),服务端接收sessionID并据此查询用户登录信息
黑盒测试、灰盒测试、白盒测试、单元测试有什么区别?
黑盒测试关注程序的功能是否正确,面向实际用户;
白盒测试关注程序源代码的内部逻辑结构是否正确,面向编程人员;
灰盒测试是介于白盒测试与黑盒测试之间的一种测试。
单元测试(Unit Testing)是对软件基本组成单元进行的测试,如函数或是一个类的方法。这里的单元,就是软件设计的最小单位。
怎么对数据库百万级数据进行优化?
使用读写分离技术(
主数据库(master)处理事务性增、改、删操作(INSERT、UPDATE、DELETE),
从数据库(slave)处理SELECT查询操作
)
springmvc生命周期
客户端发出http请求,只要请求形式符合web.xml文件中配置的*.action的话,就由DispatcherServlet来处理。
DispatcherServlet再将http请求委托给映射器的对象来将http请求交给对应的Action来处理
映射器根据客户的http请求,再对比<bean name="/hello.action如果匹配正确,再将http请求交给程序员写的Action
执行Action中的业务方法,最终返回一个名叫ModelAndView的对象,其中封装了向视图发送的数据和视图的逻辑名
ModelAndView对象随着响应到到DispatcherServlet中了
这时DispatcherServlet收到了ModelAndView对象,它也不知道视图逻辑名是何意,又得委托一个名叫视图解析器的对象去具体解析ModelAndView对象中的内容
将视图解析器解析后的内容,再次交由DispatcherServlet核心控制器,这时核心控制器再将请求转发到具体的视图页面,取出数据,再显示给用户
servlet生命周期
Servlet 通过调用 init () 方法进行初始化。
Servlet 调用 service() 方法来处理客户端的请求。
Servlet 通过调用 destroy() 方法终止(结束)。
最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的
ajax怎么解决跨域?
代理
JSONP
添加响应头
addHeader(‘Access-Control-Allow-Origin:*’);//允许所有来源访问
addHeader(‘Access-Control-Allow-Method:POST,GET’);//允许访问的方式
Mysql索引类型
普通索引
唯一索引
主键索引
组合索引
全文索引
参考:Mysql索引
SpringCloud是什么
Spring Cloud 是致力于分布式系统、云服务的框架。
为开发人员提供了快速构建分布式系统中一些常见模式的工具,例如:
配置管理
服务注册与发现
断路器
智能路由
服务间调用
负载均衡
微代理
控制总线
一次性令牌
全局锁
领导选举
分布式会话
集群状态
分布式消息
……
参考:史上最全的 Spring Cloud 教程
Hibernate的三种状态是什么?怎么将游离状态转换为持久化状态?
对Java线程安全与不安全的理解
定义:
存在成员变量的类用于多线程时是不安全的,不安全体现在这个成员变量可能发生非原子性的操作,而变量定义在方法内也就是局部变量是线程安全的。想想在使用struts1时,不推荐创建成员变量,因为action是单例的,如果创建了成员变量,就会存在线程不安全的隐患,而struts2是每一次请求都会创建一个action,就不用考虑线程安全的问题。所以,日常开发中,通常需要考虑成员变量或者说全局变量在多线程环境下,是否会引发一些问题。
经典案例:
多个线程执行时,CPU对线程的调度是随机的,我们不知道当前程序被执行到哪步就切换到了下一个线程,一个最经典的例子就是银行汇款问题,一个银行账户存款100,这时一个人从该账户取10元,同时另一个人向该账户汇10元,那么余额应该还是100。那么此时可能发生这种情况,A线程负责取款,B线程负责汇款,A从主内存读到100,B从主内存读到100,A执行减10操作,并将数据刷新到主内存,这时主内存数据100-10=90,而B内存执行加10操作,并将数据刷新到主内存,最后主内存数据100+10=110,显然这是一个严重的问题,我们要保证A线程和B线程有序执行,先取款后汇款或者先汇款后取款,此为有序性。
对原子性的理解:
我们可以把左边的圆看成是一行代码,右边的圆被分割成了两行代码。如果数据没有破坏原子性,由于线程被调度一次的最少要执行1行代码,那么t1只要执行了这行代码,就会连读带写全部完成,其他线程再拿到的数据就是被写过的最新数据,不会有任何安全隐患;而如果数据破坏了原子性,将读写进行了分割,那么t1,读取完数据如果停掉的话,t2执行的时候拿到的就是一个老数据(没有被更新的数据),接下来t1,t2同时对相同的老数据进行更新势必会因此数据的异常。
注意:
只存在读数据的时候,不会产生线程安全问题。
在java中,只有同时操作成员(全局)变量的时候才会产生线程安全问题,局部变量不会(每个线程执行时将会把局部变量放在各自栈帧的工作内存中,线程间不共享,故不存在线程安全问题,
解决方法:
使用synchronized解决线程安全问题
同步代码块
同步函数
静态同步函数
可参考:线程安全问题
关于锁
乐观锁:
顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
悲观锁
顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果经常产生冲突,上层应用会不断的进行retry,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适(比如Synchronized就是悲观锁)。
死锁及其解决方案(避免、预防、检测)
所谓死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁
死锁产生的原因?
1.因竞争资源发生死锁 现象:系统中供多个进程共享的资源的数目不足以满足全部进程的需要时,就会引起对诸资源的竞争而发生死锁现象
2.进程推进顺序不当发生死锁
死锁的四个必要条件:
(1)互斥条件:进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源
(2)请求和保持条件:进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放
(3)不可剥夺条件:是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放
(4)环路等待条件:是指进程发生死锁后,必然存在一个进程--资源之间的环形链
处理死锁的基本方法
预防死锁(破坏四个必要条件):
资源一次性分配:(破坏请求和保持条件)
可剥夺资源:即当某进程新的资源未满足时,释放已占有的资源(破坏不可剥夺条件)
资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件)
避免死锁(银行家算法):
预防死锁的几种策略,会严重地损害系统性能。因此在避免死锁时,要施加较弱的限制,从而获得 较满意的系统性能。由于在避免死锁的策略中,允许进程动态地申请资源。因而,系统在进行资源分配之前预先计算资源分配的安全性。若此次分配不会导致系统进入不安全状态,则将资源分配给进程;否则,进程等待。其中最具有代表性的避免死锁算法是银行家算法。
检测死锁
首先为每个进程和每个资源指定一个唯一的号码;
然后建立资源分配表和进程等待表,
通过系统所设置的检测机构,及时地检测出死锁的发生,并精确地确定与死锁有关的进程和资源,然后采取适当措施,从系统中将已发生的死锁清除掉。
解除死锁:
当发现有进程死锁后,便应立即把它从死锁状态中解脱出来,常采用的方法有:
剥夺资源:从其它进程剥夺足够数量的资源给死锁进程,以解除死锁状态;
撤消进程:可以直接撤消死锁进程或撤消代价最小的进程,直至有足够的资源可用,死锁状态.消除为止;所谓代价是指优先级、运行代价、进程的重要性和价值等。
---------------------
作者:宿雪Plus
来源:CSDN
原文:https://blog.csdn.net/qq_28202661/article/details/81782963
版权声明:本文为博主原创文章,转载请附上博文链接!