您现在的位置是:首页 > 原理深入 > Java面试总结Java面试总结

Web阶段

第十三双眼睛2019-05-10【Java面试总结】人已围观

简介本栏目主要记录框架内容面试时可能问到的知识

1什么是存储过程,什么是触发器
存储过程是在大型数据库系统中,一组为了完成特定功能的SQL语句集合,经过编译后存储于SQL中,用户可以通过存储过程的名字和参数来调用它。
触发器类似于java中的监听器,当某一个动作发生时,被触发,进而产生相应的动作,分为行级触发器和表级触发器两种,触发器被触发的时机也有两种,动作之前后动作之后,当数据库中有INSERT UPDATE DELETE的时候,可以触发触发器。

2数据库三范式是哪三范式
1字段具有原子性,不可再分,如姓名必须作为一个整体,无法区分出哪个是姓,哪个是名,如果非要区分,则必须要设计成两个独立的字段
2数据库表中的每个行必须可被唯一的区分,通常需要给表加上一个列,这个列叫做主键.并且其他列要完全依赖于主键,不能只依赖主键的一部分
如有一张表中有以下字段(员工编号,员工岗位,员工姓名,员工工资)员工编号和员工岗位作为联合主键,其中,员工编号决定员工姓名,员工岗位决定员工工资,而员工岗位决定员工工资,这个例子就不符合第二范式,因为,姓名只依赖了主键的一部分,工资也只依赖了主键的一部分。
3非主键列必须直接依赖主键列,不能间接依赖主键列,如有一张表,有如下字段(员工编号,员工姓名,员工部门,部门经理),员工编号决定了员工的部门,部门决定了部门经理,存在传递依赖。

3说一些数据库优化的方法
字段长度够用就行,比如邮政编码6位就够用,就给6位,多一位都别给。
用PreparedStatement,因为一个SQL语句发送给数据库服务器后,包含如下过程:语法检查,语义分析,编译,缓存,执行。而用PreparedStatement,是支持预编译的。

表之间的外键关系在程序中进行控制,因为表之间的外键关系会影响数据的插入和删除性能,
适当添加冗余字段。提高查询效率。
SQL语句全部大写,特别是表明和列名都要大写。
添加合适的索引也能提高查询效率
用连接查询代替子查询
4union和unionall 有什么区别
它们的区别在于对重复结果的处理,union会将重复的记录删除,而unionall不会,从效率上来说,unionall比union要块,因为它不会去掉重复的,但是数据如果不存在重复的话,推荐用unionall。

5注册驱动的三种方式
1  DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
2  System.setProperty("jdbc.drivers","oracle.jdbc.driver.OracleDriver");
3  Class.forName("oracle.jdbc.driver.OracleDriver"); 

6Class.forName()的作用是什么
它的作用是按照括号中字符串形式的类路径去搜索并加载相应的类,如果该类之前被加载过,则返回该类对象,如果没有被加载过,则进行加载,并创建类对象

7说出数据库连接池的工作机制是什么
web服务器启动时,会建立一定数量的数据库连接,并一致维持不少于此数量的数据库连接,当客户端程序需要用到连接时,数据库连接池会返回给应用程序一个未正在使用的连接,并且将它标记未忙状态,如果当前没有空闲的连接,数据库连接池就创建一个连接并交给应用程序使用,并标记为忙状态,新建立的连接数由配置的参数决定,当应用程序使用完该连接后,连接池就会将该连接标记为闲状态。其他的调用就可以使用这个连接

8为什么要用ORM?和JDBC有啥不一样
ORM是以一种思想,就是把数据库中的数据转变为对象,或者把对象转变为数据库中的数据,我们可以用jdbc来实现这种思想,也有许多其他技术,对jdbc进行了封装,实现了这种思想,省去了我们直接使用jdcb时的繁琐细节,提高了开发效率。


9Tomcat优化
物理内存足够的情况下,增大其使用的内存。
<Connector port="8080" maxHttpHeaderSize="8192" maxThreads="150" minSpareThreads="30" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" /> 
以上为默认值,可以根据需要适当修改。具体含义如下:
maxThreads:tomcat使用线程来处理请求,这个值表示可创建的最大线程数
acceptCount:指定当所有的线程都在服务状态时,可以被放到队列中的请求个数,超过这个数的请求不予处理,
connection timeOut:网络连接超时时间,单位,毫秒,设置为0将永不超时,这样设置是由隐患的,建议设置成30000毫秒
minSpareThreads:初始化时创建的线程数量
maxSpareThreads:容器中最大支持的线程数。
如果http和https都要用到,则要合理的分配这两个数据,如果只用到其中的一个,则可以将另一个设置的小一点
另外,还可以给java虚拟机设置可以使用的内存来提高性能,tomcat默认可以使用的内存时128MB,在大型项目中,这个是不够用的,
Windows 下,在文件{tomcat_home}/bin/catalina.bat,Unix 下,在文件 {tomcat_home}/bin/catalina.sh 的前面
增加如下设置: JAVA_OPTS='-Xms【初始化内存大小】 -Xmx【可以使用的最大内存】' 需要把这个两个参数值调大。
例如: JAVA_OPTS='-Xms256m -Xmx512m' 
测试发现,当tomcat线程数增大,但是没有超过最大线程时,平均响应时间会增大,这并不意味着在tomcat线程增大时响应速度变慢,这是因为,在线程数增多时,会导致请求会排队,排队时间会导致平均响应时间的增大。
代码方面:System.out 语句会严重影响代码执行的效率,在这些代码的功能完成以后,要删除他们。

10GET请求和POST请求的区别
get是从服务器上获取数据,Post是向服务器上传递数据
get将数据以name=value的形式添加的请求url后面,post将数据放在请求体里面
get是不安全的,因为在传送过程中,数据放在请求url后面,对用户是可见的,而Post是不可见的
get可以传送的数据量小,因为url的长度是由限制的,Post可以传送的数据量比较大
get限制表单里的数据必须是ASCII字符,,而Post支持整个ISO10646 字符集
get是默认的

11说说servlet的生命周期
servlet的生命周期是从开始创建到最后销毁的整个过程,主要包括以下几个过程,包括加载,实例化,初始化,处理请求,和销毁
web容器将servlet加载到内存中,进行实例化,实例化完毕后,调用Init方法进行初始化,初始化完成后就一直存在于web容器中,等待处理客户端请求,当web容器关闭的时候,就会调用destory方法进行销毁。
其中servlet的实例化时机分为两种情况,一种时启动时加载,就是在web容器启动的过程中就将servlet实例化出来,另一种时请求时加载,就是在第一次处理用户请求的时候实例化。

12forward()和redirect()的区别
前者是转发,是在容器内部的跳转,客户端浏览器中只显示用户请求时的url,是一次请求,一次响应。后者时重定向,是服务器返回给浏览器一个请求地址,浏览器根据返回的请求地址自动发出请求,在客户端的浏览器的地址里是会显示服务器第一次返回的请求地址的,是两次请求,两次响应。所以前者的效率是要高于后者的。在前者能满足要求的情况下,尽量使用前者,这样也能隐藏请求连接,提高系统的安全性。但是如果要跳转到其他服务器时,就必须使用redirect了。

13jsp内置对象
request:此对象封装了客户端请求参数
response:此对象封装了返回给客户端的响应数据
pageContext:管理页面的属性
session:页面请求有关的会话期
application:当前应用
out:用来向response对象传送响应内容
config:servlet的构架部件,用来存储servlet实例化参数
page:jsp网页本身,表示从该页面产生的一个servlet实例
exception:针对网页错误的异常对象

14jsp有哪些动作指令
jsp:include:在页面被请求时引入一个文件
jsp:useBean:实例化一个对象
jsp:setProperty:设置对象属性
jsp:getProperty:获取对象属性
jsp:forward:跳转
jsp:plugin:根据浏览器类型为java插件生成OBJECT或者EMBED标记

15jsp动态引入和静态引入的区别
动态引入时,先将要引入的页面进行编译,然后在引入,静态引入,先引入,在将整体进行编译

16jsp和servlet有什么相同和不同
jsp是servlet技术的扩展,本质上是一样的,jsp被翻译后就是servlet,他们最主要的不同点在于,servlet的应用逻辑是在java文件中,与表示层HtmL分开,侧重的是控制器,而jsp是java和html的结合,更侧重于视图

17谈谈对struts2的认识
Struts2 是 Struts1的下一代产品,是在 struts1.X 和 WebWork 的技术基础 上进行了合并的全新的 Struts 2 框架。Struts 2 以 WebWork 为核心,采用拦截器的机制来处理用户的请求。 所以 Struts2 可以理解为 WebWork 的更新产品。Struts2.X 采用的 MVC 的设计思想设计,将 web开发大体上分为3层M(Model)层,V(View)层,C(controller) 层。使得 web开发结构层次化,结构化,提高代码的扩展性、重用性和可维护性。

18struts的工作流程
1客户端浏览器发出http请求
2根据web.xml的配置,请求被FilterDispatcher 拦截
3根据struts.xml的配置,找到需要调用的action类和方法,并通过ioc的方式,将参数注入给action
4action调用业务方法处理请求,
5action执行完毕,返回字符串
6根据struts.xml中的配置找到对应的result标签,跳转到响应的页面 ,并将页面返回给客户端浏览器
所有的请求都要过StrutsPrepareAndExecuteFilter 过滤器,它被称为前端过滤器

19hibernate对象的三种状态是什么
瞬时态,持久态,托管态

20什么是Redis
Redis是一个使用c语言编写的,开源的nosql,内存型数据库,和memcache类似,但是支持更多的数据类型,包括,String list,set zset hash,支持的操作包括push,pop,add,remove,取交集,并集,差集的等操作,而且,这些操作都是原子性的,而且,还会周期性的把内存中的数据写到磁盘上,以防止服务崩溃后数据丢失,还实现了主从同步。而且,单个value的限制是1G,不像memcache只有1M,它的主要缺点是受物理内存的限制,不能用作海量数据的读写,

21Redis比memcache的优势有哪些
memcache只支持字符串,而redis支持的数据类型有5种
redis的速度比memcache块很多
redis支持持久化

22Redis的持久化机制
redis提供了两种持久化机制,rdb和aof
rdb指的是在指定的时间间隔内将内存种的数据保存到磁盘上,默认的文件名为dump.rdb,rdb持久化机制是redis默认的持久化机制
可以通过修改配置文件来设置持久化的时间。当达到保存时机时,产生一个子进程来执行数据持久化。父进程继续执行客户端请求,子进程将数据写到临时文件,由于操作系统的写时复制机制,父子进程会共享相同的页面,当父进程处理写请求时,操作系统会为父进程要修改的页面创建临时副本,而不是写共享的页面,所以子进程的地址空间内时fork时客数据库整个数据的一个快照。当子进程将临时文件写入完毕后,用临时文件替换原来的数据文件,子进程退出。
客户端也可以使用save或者bgsave做一次快照持久化,这个操作是在主线程中做的,由于主线程是用来做所有的客户端请求的,所以这一操作会阻塞所有客户端请求。不建议使用,而且,每次持久化都是将数据全量的写入磁盘文件中。
rdb优点:一旦采用这种方式,整个redis数据库只有一个数据文件,这样的化,方便进行备份,rdb在恢复大数据集的时候要比aof快的多
rdb可以最大化数据库的性能,在需要持久化时,父进程只要产生一个子进程,而不需要做任何事情
缺点:一旦发生事故,则发生事故和上一次保存时之间的那部分数据就会丢失。

aof机制,redis会将每一个收到的写命令都用write函数写入文件中,默认时appendonly.aof,当redis重启时,会重新执行日志文件中的命令来恢复数据库,由于操作系统会在内核中缓存写操作命令,所以也并不是立即写到磁盘上,也会丢失一部分数据。
aof 的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用incr test命令100次,文件中必须保存全部的100条命令,其实有99条都是多余的。因为要恢复数据库的状态其实文件中保存一条set test 100就够了。
为了压缩aof的持久化文件。redis提供了bgrewriteaof命令。收到此命令redis将使用与快照类似的方式将内存中的数据 以命令的方式保存到临时文件中,最后替换原来的文件。具体过程如下:
1redis调用fork ,现在有父子两个进程
2子进程根据内存中的数据库快照,往临时文件中写入重建数据库状态的命令
3父进程继续处理client请求,除了把写命令写入到原来的aof文件中。同时把收到的写命令缓存起来。这样就能保证如果子进程重写失败的话并不会出问题
4当子进程把快照内容写入已命令方式写到临时文件中后,子进程发信号通知父进程。然后父进程把缓存的写命令也写入到临时文件
5现在父进程可以使用临时文件替换老的aof文件,并重命名,后面收到的写命令也开始往新的aof文件中追加


23xml有哪些解析方式
1dom方法:首先在内存中创建一个document对象,然后把xml文档读取进来赋值给这个对象,由于dom对象时基于树结构的,所以,对dom对象进行遍历即可,对内存中的对象可以 进行查询,删除,修改操作,还可以回写原xml文档进行保存。它的优点是可以对整个dom对象进行随机访问,缺点是整个文档必须一次性解析完,而且,对于大的文档,耗用内存较高
2sax方式,不同于dom方式,sax是事件驱动的,它顺序读取xml文件,不需要一次全部装载真个xml文档,当遇到文件开头,文件结束,标签开头,标签结束时,都会触发一个事件,用户通过在回调事件中写入处理代码来处理xml文件,此方式适合顺序访问xml,它的优点是,无需装在整个文档到内存中,消耗内存少,缺点是不能随机访问xml文档中的各个节点,不能修改文档,查询一次就要对整个文档从头到尾遍历一次。
3jdom,是对dom方式进行了包装得到的方法。优缺点和dom一样
4dom4j,它是jdom的一种智能分支,它合并了许多超出基本xml文档表示的功能,它使用接口时抽象基本类方法,性能优异,灵活性好,功能强大,简单易用。

24xml文档定义有几种形式,他们有什么区别
两种形式,dtd和schema,schema文件主要对xml文件进行定义,并校验xml文件的有效性,dtd的作用定义xml合法构建模块,它使用一系列的元素来定义文档结构,他们主要有以下区别:
1schema本身是xml文档,dtd和xml没有什么关系
2dtd文档的结构是平铺型的,如果要定义比较复杂的文档类型,很难把握元素之间的嵌套关系,schema文档的结构清晰,很容易把我元素之间的嵌套关系
3dtd只能指定元素含有文本,不能指定元素文本的具体类型,如字符,整数,日期等,schema可以
4schema支持元素节点顺序的描述,dtd没有定义无序情况的描述,要定义无序,必须琼剧所有顺序情况,schema可以用xs:all来表示无序的情况
5对命名空间的支持,dtd无法利用xml的命名空间,schema很好满足命名空间,而且,schema还提供了两种引用命名空间的方式,include和import


25html5有哪些不同类型的存储
1localStorage:适用于长期存储数据,浏览器关闭后,数据不丢失
2sessionStorage :存储的数据在浏览器关闭后自动删除

26http协议
超文本传输协议,用来在互联网传输信息,是最重要的协议,最常用的协议,处于tcp/ip参考模型的应用层。


27Cookie 和 Session
都可以保存信息,不同的是)Cookie 将状态保存在客户端,Session 将状态保存在服务器端
session:Session 是针对每一个用户的,变量的值保存在服务器上,用一 个sessionID来区分是哪个用户session变量,这个值是通过用户的浏 览器在访问的时候返回给服务器
session比cookie安全

28Session 的实现方式 
使用 Cookie 来实现 服务器给每个Session分配一个唯一的JSESSIONID,并通过Cookie 发送给客户端。 当客户端发起新的请求的时候,将在 Cookie 头中携带这个 JSESSIONID。这样服务器能够找到这个客户端对应的 Session


29https 的实现原理
有两种基本的加解密算法类型: 1)对称加密:密钥只有一个,加密解密为同一个密码,且加解密速 度快,典型的对称加密算法有 DES、AES 等;
非对称加密:密钥成对出现(且根据公钥无法推知私钥,根据私 钥也无法推知公钥),加密解密使用不同密钥(公钥加密需要私钥解 密,私钥加密需要公钥解密),相对对称加密速度较慢,典型的非对 
 
https 通信的优点:
1)客户端产生的密钥只有客户端和服务器端能得到;
2)加密的数据只有客户端和服务器端才能得到明文;
3)客户端到服务端的通信是安全的。


30tomcat 有那几种 Connector 运行模式?
tomcat 的运行模式有 3 种.修改他们的运行模式.3 种模式的运行是否 成功,可以看他的启动控制台,或者启动日志.或者登录他们的默认页 面 http://localhost:8080/查看其中的服务器状态。
bio:默认的模式,性能非常低下,没有经过任何优化处理和支持.
nio:利用 java 的异步 io 护理技术,no blocking IO 技术
apr:安装起来最困难,但是从操作系统级别来解决异步的 IO 问题,大幅度 的提高性能.




31MyBatis缓存
使用缓存可以更快的获取数据,避免频繁的操作数据库,查询越多,缓存命中率越高的情况下,使用缓存的作用就越明显,MyBatis提供了一级缓存和二级缓存
一般提到MyBatis缓存时,就是指二级缓存,因为一级缓存时默认开启的,并且不能控制得,一般很少说到。
MyBatis的一级缓存存在于SqlSession的生命周期中,在同一个SqlSession中查询时,MyBatis会把执行的方法和参数通过算法生成缓存的键,将查询结果做为值,放入map中,如果用同一个SqlSession查询时,如果执行的方法和查询的参数完全一致,就会返回缓存中的对象。可以设置select标签中的flushCache属性的值为true,此时,执行查询的时候,就会清空当前SqlSession的一级缓存。去数据库里查询。但是会使得该SqlSession的只读数据在每次查询的时候,都会去查询数据库,增加了数据库服务器的压力。任何的INSERT UPDATE DELETE操作会情况当前SqlSession的一级缓存。
MyBatis的二级缓存非常强大,不同于一级缓存只存在于SqlSession的生命周期中,二级缓存存在于SqlSessionFactory的生命周期中。
在MyBatis的全局配置文件中,有一个cacheEnabled属性,当把该属性的值设置为true时,二级缓存为开启状态,如果设置为false,则为关闭状态,二级缓存和namespace是绑定在一起的,即需要配置在Mapper.xml中,只需要在mapper文件中添加<cache/>标签即可,添加了二级缓存以后,会有如下效果:
1映射文件中的所有的SELECT语句都会被缓存
2映射文件中的所有INSERT UPDATE DELETE 都会刷新缓存
3缓存会使用Least Recently Used,最近最少使用算法来回收,
4根据时间表,缓存不会以任何时间顺序来刷新
5缓存会存储集合或者对象的1024个引用
6缓存被视为read/write可读可写的,意味着对象检索不是共享的,而且可以安全的被调用者修改,而不干扰其他调用者或线程所作的潜在修改
MyBatis提供的缓存是默认基于Map实现的内存缓存,已经可以满足基本的需要,但是需要缓存的数据量非常大时,不能仅仅通过提供增大内存来使用MyBatis的二级缓存,还可以通过使用一些类似EhCache的缓存框架,或者时Redis缓存数据库来是保存MyBatis二级缓存数据,如果要使用其他缓存框架,需要在cache标签中指定type属性的值,改制为缓存类的全限定名
32脏数据的产生和避免
二级缓存虽然能提高应用效率,减轻服务器的压力,但是,如果使用不当,也会造成许多脏数据,这些脏数据会不知不觉中影响业务逻辑。
MyBatis的二级缓存是和namespace绑定的,所以,每个mapper文件都拥有自己的二级缓存,不同mapper文件的二级缓存互不影响,在应用程序中,多表关联非常常用,这样一个多表查询的结果就会缓存在该命名空间下,涉及这些表的增删改操作通常不在一个namespace中,因此,当数据有变化时,缓存未必会清空,这种情况下就会产生脏数据。此时,使用参照缓存就可以避免这个问题。
33二级缓存的使用场景
二级缓存的好处虽然非常多,但是不是什么时候都可以用,如下场景中,建议使用二级缓存
1查询远远大于增删该的应用中可以使用二级缓存
2绝大多数进行单表操作时,由于不会关联别的表,不会产生脏数据,可以使用二级缓存
3如果可以按业务划分表的分组时,如果关联的表比较少,可以使用参照缓存的方式,可以使用二级缓存
4如果系统对脏数据要求不是很高的情况下,也可以使用二级缓存

34nginx负载均衡
nginx的代理过程,就是将请求发送给nginx,然后将请求转发给后端服务器,后端服务器处理完毕之后将结果再发给nginx,nginx再把结果发送给客户端。后端服务器可在远程也可在本地,也可以是nginx服务器内部定义的其他虚拟主机。这些接收nginx转发的服务器被称为上游(upstream)
nginx也提供了缓冲的机制,用于提高性能。没有缓冲的情况下,数据直接从后端服务器发送给客户端。缓冲的作用是在nginx上临时存储来自后端服务器的处理结果,从而可以提早关闭nginx到后端的连接,减少IO的损耗。一般内容存放在内存当中,但当内容过多,造成的内存不够时,会把内容存放在临时文件目录下。

35调度算法
轮询:按时间顺序逐一分配到不同的后端服务器。
加权轮询:可在配置的server后面加个weight=number,number值越高,分配的概率越大。
ip_hash:每个请求按访问IP的hash分配,这样来自同一IP固定访问一个后台服务器。
least_hash:最少链接数,哪个机器连接数少就发分发给哪个机器。
url_hash:按访问的url的hash结果分配请求,是每个url定向到同一后端服务器上。
hash关键值:hash自定义的key

36spring框架的ioc(di依赖注入)
Inversion of Control(控制反转):就是把程序中需要用到的的对象配置在配置文件中,而不是直接new ,在运行过程中,由容器返回一个进行赋值,

37spring框架的aop
Aspect Oriented Programming(面向切面编程):对系统中的业务进行分离,比如将核心业务与日志,事务等分离,在运行的过程中,由spring框架将核心功能和增强功能结合在一起形成一个代理对象。

38什么是类的加载
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。

39类的生命周期
类的生命周期包括以下几个部分:
加载,连接,初始化,使用,卸载
加载:查找并将class文件读入到内存,在java堆中创建出一个class对象
连接:连接又包含三块内容:验证、准备、初始化。
1)验证,文件格式、元数据、字节码、符号引用验证;
2)准备,为类的静态变量分配内存,并将其初始化为默认值;
3)解析,把类中的符号引用转换为直接引用
初始化:为类的静态变量赋初始值
使用:创建实例并使用
卸载:垃圾回收器回收

40类加载器
类加载器分为如下几种:
启动类加载器:Bootstrap ClassLoader,负责加载存放在JDK\jre\lib(JDK代表JDK的安装目录,下同)下,或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库
扩展类加载器:Extension ClassLoader,该加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载DK\jre\lib\ext目录中,或者由java.ext.dirs系统变量指定的路径中的所有类库(如javax.*开头的类),开发者可以直接使用扩展类加载器
应用程序类加载器:Application ClassLoader,该类加载器由sun.misc.Launcher$AppClassLoader来实现,它负责加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器

41类加载的机制
全盘负责,当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入
父类委托,先让父类加载器试图加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类
缓存机制,缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效

42java虚拟机内存分区
java虚拟机内存分为5大部分,java虚拟机栈,本地方法栈,堆,程序计数器pc,方法区,其中方法区和堆在所有线程中共享,另外三者在线程间独享
Java堆(Heap),是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
方法区(Method Area),方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
程序计数器(Program Counter Register),程序计数器(Program Counter Register)是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器
JVM栈(JVM Stacks),与程序计数器一样,Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程
本地方法栈(Native Method Stacks),本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。

43对象分配的原则
对象优先分配在Eden区,如果Eden区没有足够的空间时,虚拟机执行一次Minor GC
大对象直接进入老年代(大对象是指需要大量连续内存空间的对象)。这样做的目的是避免在Eden区和两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)
长期存活的对象进入老年代。虚拟机为每个对象定义了一个年龄计数器,如果对象经过了1次Minor GC那么对象会进入Survivor区,之后每经过一次Minor GC那么对象的年龄加1,知道达到阀值对象进入老年区。
动态判断对象的年龄。如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代。
空间分配担保。每次进行Minor GC时,JVM会计算Survivor区移至老年区的对象的平均大小,如果这个值大于老年区的剩余值大小则进行一次Full GC,如果小于检查HandlePromotionFailure设置,如果true则只进行Monitor GC,如果false则进行Full GC

44对象存活判断
判断对象是否存活一般有两种方式
引用计数:每个对象有一个引用计数属性,当一个新的引用指向该对象时,该属性加1,当有一个引用不在指向该对象时,该属性减1,为0时可以回收,此方法无法解决对象循环引用的情况
可达性算法:从gcroot向下搜索,搜索走过的路径称为引用链,当一个对象与任何一条引用链都不相连时,此对象就是不可达的,会被垃圾收集器回收

45GC算法
标记 -清除算法,“标记-清除”(Mark-Sweep)算法,如它的名字一样,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象
复制算法,“复制”(Copying)的收集算法,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉
标记-压缩算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存
分代收集算法,“分代收集”(Generational Collection)算法,把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。

46垃圾回收器
Serial收集器,串行收集器是最古老,最稳定以及效率高的收集器,可能会产生较长的停顿,只使用一个线程去回收
ParNew收集器,ParNew收集器其实就是Serial收集器的多线程版本
Parallel收集器,Parallel Scavenge收集器类似ParNew收集器,Parallel收集器更关注系统的吞吐量
Parallel Old 收集器,Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法
CMS收集器,CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。
G1收集器,G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征


47jdk动态代理与cglib动态代理的区别
什么是代理,代理模式是java中常见的一种设计模式,英文名字叫做proxy,代理的本意是一个人代表另一个人,或者一个机构代表另一个机构,做一些事情,比如生活中的租房子,中介就是房东的代理,
按照代理对象的创建时期,代理分为静态代理和动态代理
静态代理,由程序员手动实现,然后进行编译。在程序运行时,由类加载器加载到内存中,和普通的类创建方式一样。
java动态代理类是InvocationHandler,位于java.lang.reflect包中,该接口中定义了一个方法,Invoke(Object obj,Method method, Object[] args),其中,第一个参数是被代理的类,第二个是被代理的方法,第三个是方法中的参数。
用Proxy类调用一个静态的方法,Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用 (可使用被代理类的在Subject接口中声明过的方法)。
jdk动态代理只能代理实现接口的类,没有实现接口的类就不能使用jdk动态代理,cglib是对那些继承了抽象类的类进行代理的,它的原理是针对指定的目标类,生成一个子类,并对其中的方法进行增强,


48struts2执行过程
1客户端浏览器发出请求
2被web.xml中配置的StrutsPrepareAndExecuteFilter所拦截
3根据struts.xml的配置,找到需要调用的action类和方法
4Action执行完毕,返回字符串,在struts.xml中找到对应<result>标签,跳转到对应的jsp.
5jsp执行完毕生成Html,返回响应到浏览器。


49springmvc执行流程
1客户端发送请求到服务器
2服务器对请求进行解析,如果匹配请求映射地址,则将请求交给请求分发器
3请求分发器根据请求地址找到对应的类和方法,执行完成后,返回字符串,交给视图解析器,视图解析器加上前缀和后缀,生成物理视图,物理视图执行完毕后,生成html,返回给客户端


50lucene介绍
全文检索引擎工具包,它将java对象转换位document对象,根据指定的分词策略将对象进行拆分,将分词后的结果存储到检索库,检索库分为两个部分,一部分叫做词汇表,主要存放分词后的结果,另一部分叫做原始记录表,存放document对象。

51shiro框架介绍
强大且易用的安全框架,提供认证,授权,加密,session管理等功能.
内部主要依赖安全管理器,securityManager

支持java项目和web项目
不依赖任何容器,方便集成

52springmvc和struts2的区别
1springmvc入口是一个servlet前端控制器(DispatcherServlet),struts2入口是一filter过滤器(StrutsPrepareAndExecuteFilter).
2struts2通过在action类中定义成员变量接收参数,(属性驱动和模型驱动),它只能使用多例模式管理action.
3springmvc通过在coontroller方法中定义形参接收参数,springmvc可以使用单例模式管理controller. 
4Struts2框架是类级别的拦截,每次来了请求就创建一个Action,然后调用get和set方法吧request中的数据注入.SpringMVC是方法级别的拦截,拦截到方法后根据参数的注解,把requset数据注入进去springmvc容器中
5struts2采用值栈存储请求和相应的数据,通过OGNL存取数据,springmvc通过参数绑定期将request请求内容解析,并给方法形参赋值


53事务传播机制
1REQUIRED(默认):支持使用当前事务,如果当前事务不存在,创建一个新事务。
2SUPPORTS:支持使用当前事务,如果当前事务不存在,则不使用事务
3MANDATORY:中文翻译为强制,支持使用当前事务,如果当前事务不存在,则抛出Exception。
4REQUIRES_NEW:创建一个新事务,如果当前事务不存在,把当前事务挂起。
5NOT_SUPPORTED:无事务执行,如果当前事务不存在,把当前事务挂起。
6NEVER:无事务执行,如果当前有事务则抛出Exception。
7NESTED:嵌套事务,如果当前事务存在,那么在嵌套的事务中执行。如果当前事务不存在,则表现跟REQUIRED一样。
重点讲一下requires_new和nested的区别,requires_new完全是一个新事务,nested是一个外部事务的子事务,是外部事务的一部分,如果嵌套事务发生异常回滚,则只回滚嵌套事务部分。而外部事务的提交和回滚均会提交/回滚嵌套事务。requires这是两个事务互不干扰,如果内部事务发生异常且异常抛到了外部调用方法,那么两个事务都回滚,如果内部事务提交成功,外部事务提交失败,外部事务不影响内部事务,或者外部事务提交成功,但内部事务失败的异常被外部事务catch住,则不影响外部事务

54事务隔离级别
并发下事务产生的问题
脏读:就是一个事务读到了另一个事务还没有提交的数据,比如银行取钱,事务A开启事务,此时切换到事务B,事务B开启事务-->取走100元,此时切换回事务A,事务A读取的肯定是数据库里面的原始数据,因为事务B取走了100块钱,并没有提交,数据库里面的账务余额肯定还是原始余额,这就是脏读
不可重复读:就是在一个事务里面读取了两次数据,两次数据不一样,还是以银行取钱为例,事务A开启事务-->查出银行卡余额为1000元,此时切换到事务B事务B开启事务-->事务B取走100元-->提交,数据库里面余额变为900元,此时切换回事务A,事务A再查一次查出账户余额为900元,这样对事务A而言,在同一个事务内两次读取账户余额数据不一致,这就是不可重复读
幻读:就是在一个事务中操作了未被操作的数据,比如学生信息,事务A开启事务-->修改所有学生当天签到状况为false,此时切换到事务B,事务B开启事务-->事务B插入了一条学生数据,此时切换回事务A,事务A提交的时候发现了一条自己没有修改过的数据,这就是幻读,就好像发生了幻觉一样。幻读出现的前提是并发的事务中有事务发生了插入、删除操作
事务隔离级别,就是为了解决上面几种问题而诞生的。为什么要有事务隔离级别,因为事务隔离级别越高,在并发下会产生的问题就越少,但同时付出的性能消耗也将越大,因此很多时候必须在并发性和性能之间做一个权衡。所以设立了几种事务隔离级别
default:默认隔离级别,每种数据库支持的事务隔离级别不一样,如果Spring配置事务时将isolation设置为这个值的话,那么将使用底层数据库的默认事务隔离级别
READ_UNCOMMITTED:读未提交,即能够读取到没有被提交的数据,所以很明显这个级别的隔离机制无法解决脏读、不可重复读、幻读中的任何一种,因此很少使用
READ_COMMITED:读已提交,即能够读到那些已经提交的数据,自然能够防止脏读,但是无法限制不可重复读和幻读
REPEATABLE_READ:重复读取,即在数据读出来之后加锁,类似"select * from XXX for update",明确数据读取出来就是为了更新用的,所以要加一把锁,防止别人修改它。REPEATABLE_READ的意思也类似,读取了一条数据,这个事务不结束,别的事务就不可以改这条记录,这样就解决了脏读、不可重复读的问题,但是幻读的问题还是无法解决
SERLALIZABLE:串行化,最高的事务隔离级别,不管多少事务,挨个运行完一个事务的所有子事务之后才可以执行另外一个事务里面的所有子事务,这样就解决了脏读、不可重复读和幻读的问题了

Tags:

很赞哦! ()

文章评论

    共有条评论来说两句吧...

    用户名:

    验证码:

本站推荐

站点信息

  • 网站名称:JavaStudy
  • 建站时间:2019-1-14
  • 网站程序:帝国CMS7.5
  • 文章统计242篇文章
  • 标签管理标签云
  • 统计数据百度统计
  • 微信公众号:扫描二维码,关注我们