同步异步阻塞非阻塞
同步与异步
实际上同步与异步是针对应用程序与内核的交互而言的。同步过程中进程触发IO操作并等待或者轮询的去查看IO操作是否完成。异步过程中进程触发IO操作以后,直接返回,做自己的事情,IO交给内核来处理,完成后内核通知进程IO完成。同步与异步如下图所示:
阻塞与非阻塞
简单理解为需要做一件事能不能立即得到返回应答,如果不能立即获得返回,需要等待,那就阻塞了,否则就可以理解为非阻塞。
什么是Servlet
Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。
重点理解:Servlet 编写过滤器
Servlet 和 Filter 的比较
详解: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的区别
简述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区别
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
super T> 下界通配符
下界通配符 super T>表示的是参数化类型是T的超类型(包含自身),层层至上,直至Object,编译器无从判断get()返回的对象的类型是什么,因此get()方法受限。但是可以进行add()方法,add()方法可以添加T类型和T类型的子类型,如第二个例子中首先添加了一个Cat类型对象,然后添加了两个Cat子类类型的对象,这种方法是可行的,但是如果添加一个Animal类型的对象,显然将继承的关系弄反了,是不可行的。
> 无界通配符
在理解了上界通配符和下界通配符之后,其实也自然而然的理解了无界通配符。无界通配符用>表示,?代表了任何的一种类型,能代表任何一种类型的只有null(Object本身也算是一种类型,但却不能代表任何一种类型,所以List
定义:
用一句话来解释反射的定义:自控制,自描述。即通过反射可以动态的获取类、属性、方法的信息,也能构造对象并控制对象的属性和行为。
应用:
JDBC的驱动加载方式是通过反射机制实现的,JDBC只是设计了驱动需要实现的接口,并不关心驱动厂商的个数和实现方式,只要安装统一的规范即可,至于类型的判断和具体方法的触发,交给运行期动态判断即可,这种反射机制的使用淋漓尽致的体现了多态,并且降低了类与类之间的耦合度。
定义:可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。
应用:@Override @controller
Thread类的方法有哪些,如何多种方式实现线程同步
多线程有两种实现方法,一是继承Thread类,重写方法run(),二是实现Runnable接口,实现方法run();
同步有两种实现方法,分别是synchronized、wait与notify。
进程与线程的区别,JAVA中有哪些方式可以创建线程。
参考:java中进程与线程--三种实现方式
进程:系统分配资源的基本单位,资源独立
线程:系统(CPU)调度的基本单位,也是程序执行的最小单位。与同进程中的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
关系:一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
创建方式:
进程的五种基本状态
现有一学生表结构(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"%>
Insert title here
<%
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();
}
}
%>
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生命周期
ajax怎么解决跨域?
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同时对相同的老数据进行更新势必会因此数据的异常。
可参考:线程安全问题
关于锁
顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁。
顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
死锁及其解决方案(避免、预防、检测)
所谓死锁:是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁
1.因竞争资源发生死锁 现象:系统中供多个进程共享的资源的数目不足以满足全部进程的需要时,就会引起对诸资源的竞争而发生死锁现象
2.进程推进顺序不当发生死锁
(1)互斥条件:进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源
(2)请求和保持条件:进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放
(3)不可剥夺条件:是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放
(4)环路等待条件:是指进程发生死锁后,必然存在一个进程--资源之间的环形链
预防死锁(破坏四个必要条件):
避免死锁(银行家算法):
预防死锁的几种策略,会严重地损害系统性能。因此在避免死锁时,要施加较弱的限制,从而获得 较满意的系统性能。由于在避免死锁的策略中,允许进程动态地申请资源。因而,系统在进行资源分配之前预先计算资源分配的安全性。若此次分配不会导致系统进入不安全状态,则将资源分配给进程;否则,进程等待。其中最具有代表性的避免死锁算法是银行家算法。
检测死锁
解除死锁:
当发现有进程死锁后,便应立即把它从死锁状态中解脱出来,常采用的方法有:
另外可补充:这是我见过最有用的java面试题,面试了无数公司总结的