赞
踩
2、大数据类型转小数据类型 像大杯子里的水倒进小杯 会出现溢出
4、对象就好像是一张张工牌,工牌的形式早已规定好。类就好比是对象的蓝图,java虚拟机根据蓝图来创建对象。(抽象类或者接口则是留白更多的蓝图)
对象本身已知的事物被称作是实例变量,对象可以执行的动作称为方法。
面向对象的过程:a、找出几个类中的共同部分;b、将共同有的特性与方法而提取出新的类。
继而子类可以继承父类的状态与方法,子类覆盖父类的方法实现不同的动作。
覆盖:就是要遵守合约
a、参数必须要一样,且返回类型必须要兼容,返回一样的类型或者该类的子类,子类一定要能执行父类的一切
b、不能降低方法的存取权限,存取权限必须相同或者更加开放
6、BigInteger
构造方法:BigInteger(String val) BigInter.add();只是返回一个值并不改变原来的变量
11、数组是一个对象 类型不变、大小不变
12、在java中,变量分为两种,
一种是primitive主数据类型,也称之其为基本数据类型,
还有一种是引用数据类型;下面就这两种类型分别展开进行讨论;
<1>primitive主数据类型
primitive主数据类型包括八种:
boolean, char, byte,short,int,long,float,double
对于变量的赋值,都是将某个变量的值赋给另一个变量;这两个变量之间并没有其他什么联系,
只是在初次赋值时,其值刚好相等而已;之后则各走各路,并无任何瓜葛;
<2>引用数据类型
除上述八种primitive主数据类型之外,其余类型都称之为引用数据类型;
引用数据类型,顾名思义就是:“引用”,当一个对象赋值给一个引用变量时,
那么,则表明这个引用变量是指向这个对象的;一个对象可以有多个引用;
一个引用同一时刻,则只能指向一个对象;
13、对象
对象有状态和行为两种属性。分别由实例变量和方法来表示。类是对象的蓝图。类所描述的是对象知道什么与执行什么。
16、守护线程
线程分守护线程和非守护线程(即用户线程)
只要JVM实例中存在任何一个非守护线程没有结束,守护线程就全部工作,只有当最后一个非守护线程结束时,守护
线程随着JVM一同结束工作。守护线程最典型的应用就是GC(垃圾回收器)
17、存储过程和函数的区别
存储过程是用户定义的一系列SQL语句的集合,涉及特定表或其他对象的任务,用户可以调用存储过程。函数通常是
数据已定义的方法,它接收参数并返回某种类型的值,而且不涉及特定用户表。
存储过程有两种方式返回值:
第一:通过output 参数
第二:通过return来实现
而在你的存储过程已经声明了一个output参数,只要你在你的存储过程已经给这个值赋值了,它就能返回回去.
建议一般用output参数,因为它可以返回多个,而return只能是一个,return一般用来返回:影响的行数,错误编码等
简单例子:
DECLARE @tmpCount int
SET @tmpCount int = (SELECT COUNT(*) FROM 表名 WHERE 你要进行搜索的条件)
IF (@tmpCount = 0)
BEGIN
INSERT 操作
RETURN 1
END
ELSE
BEGIN
RETURN 0
END
18、数据库事务
数据库事务是指单个逻辑工作单元执行的一系列操作,这些操作要么全做,要么全不做,是一个不可分割的工作单位。事务具有原子性、一致性、独立性及持久性等特点。
原子性:一个事务要么全部执行,要么不执行。不可能执行一半就停止。
一致性:事务的运行并不改变数据库中数据的一致性。例如,完整性约束了a+b=10,一个事务改变了a,那么b也应该
随之改变。
独立性:两个以上的事务不会出现交错执行的状态,因为这样可能导致数据不一致。
持久性:事务运行成功以后,系统的更新是永久的,不会无缘无故回滚。
19、执行数据库查询时,如果要查询的数据有很多,假设有1000w条,用什么方法可以提高查询效率?在数据库或
Java方面有什么优化办法?
1、在数据库设计方面
建立索引,分区(比如按时间分区),尽量使用固定长度的字段,限制字段长度
2、在数据库I/O方面
增加缓冲区;如果涉及表的级联,不同的表存储在不同的磁盘上,以增加I/O速度。
3、在SQL语句方面
优化SQL语句,减少比较次数;限制返回的条目数
4、在Java方面
如果是反复使用的查询,使用PreparedStatement减少查询次数。
5、分库分表
业务数据集中其中几列就垂直分表,表间无关联就分库,列多数据多就横向分表
20、常见数据库对象
转载链接:https://www.cnblogs.com/yingtoumao/p/8556976.html
常见的数据库对象
表 table 表是存储数据的逻辑单元,以行和列的形式存在,列就是字段,行就是记录
数据字典 就是系统表,存放数据库相关信息的表。系统表的数据通常由数据库系统维护,程序员通常不应该修改,只可查看
约束 constraint 执行数据校验的规则,用于保证数据完整性的规则
视图 view 一个或者多个数据表里的数据的逻辑显示,视图并不存储数据
索引 index 用于提高查询性能,相当于书的目录
函数 function 用于完成一次特定的计算,具有一个返回值
存储过程 procedure 用于完成一次完整的业务处理,没有返回值,但可通过传出参数将多个值传给调用环境
触发器 trigger 相当于一个事件监听器,当数据库发生特定事件后,触发器被出发,完成相应的处理
21、Struts2
三次:让actionmapper获取action信息,调用actionproxy根据struts.xml获取action,调用actioninvocation执行action
转载链接:https://blog.csdn.net/u011958281/article/details/74685659
转载链接:https://www.cnblogs.com/quchengfeng/p/4916856.html
strutsprepareandexecutefilter-actionmapper-actionproxy-actioninvocation
(1) 客户端(Client)向Action发用一个请求(Request)
(2) Container通过web.xml映射请求,并获得控制器(Controller)的名字
(3) 容器(Container)调用控制器(StrutsPrepareAndExecuteFilter或FilterDispatcher)。在Struts2.1以前调用FilterDispatcher,Struts2.1以后调用StrutsPrepareAndExecuteFilter
(4) 控制器(Controller)通过ActionMapper获得Action的信息
(5) 控制器(Controller)调用ActionProxy
(6) ActionProxy读取struts.xml文件获取action和interceptor stack的信息。
(7) ActionProxy把request请求传递给ActionInvocation
(8) ActionInvocation依次调用action和interceptor
(9) 根据action的配置信息,产生result
(10) Result信息返回给ActionInvocation
(11) 产生一个转载链接:HttpServletResponse响应
(12) 产生的响应行为发送给客服端。
StrutsPrepareAndExecuteFilter或FilterDispatcher)。在Struts2.1以前调用FilterDispatcher,Struts2.1以后调StrutsPrepareAndExecuteFilter,那么,他们之间真正的区别目的在哪里呢,
- StrutsDispatch和StrutsPrepareAndExecuteFilter区别
应该知道如果我们自己定义过滤器的话, 是要放在strtus2的过滤器之前的, 如果放在struts2过滤器之后,你自己的过滤器对action的过滤作用就废了,不会有效!除非你是访问jsp/html!
那我现在有需求, 我必须使用Action的环境,而又想在执行action之前拿filter做一些事, 用FilterDispatcher是做不到的.!
那么StrutsPrepareAndExecuteFilter可以把他拆分成StrutsPrepareFilter和StrutsExecuteFilter,可以在这两个过滤器之间加上我们自己的过滤器.!
23、Servlet
一、Servlet简介
Servlet是sun公司提供的一门用于开发动态web资源的技术。
Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
1、编写一个Java类,实现servlet接口。
2、把开发好的Java类部署到web服务器中。
按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet
二、Servlet的运行过程
Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:
①Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
②装载并创建该Servlet的一个实例对象。
③调用Servlet实例对象的init()方法。
④创建一个用于封装转载链接:HTTP请求消息的转载链接:HttpServletRequest对象和一个代表转载链接:HTTP响应消息的转载链接:HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
⑤WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。
24、转发和重定向
请求转发:response.getRequestDispatcher("/student_list.jsp").forward(request,response);
重定向: response.sendRedirect(request.getContextPath + “/student_list.jsp”)
1、转发是在服务器端完成的,重定向是在客户端发生的;
2、转发的速度快,重定向速度慢;
3、转发是同一次请求,重定向是两次请求;
4、转发地址栏没有变化,重定向地址栏有变化;
5、转发必须是在同一台服务器下完成,重定向可以在不同的服务器下完成。
25、servlet与JSP区别
1.JSP的本质就是Servlet,JVM只能识别java的类,不能识别JSP的代码,Web容器将JSP的代码编译成JVM能够识别的java类。
jsp就是在html里面写java代码,servlet就是在java里面写html代码…其实jsp经过容器解释之后就是servlet.
只是我们自己写代码的时候尽量能让它们各司其职,jsp更注重前端显示,servlet更注重模型和业务逻辑。
JSP 工作原理:
JSP页面在执行的时候都会被服务器端的JSP引擎转换为Servelet(.java),然后又由JSP引擎调用Java编译器,将Servelet(.java)编译为Class文件(.class),并由Java虚拟机(JVM)解释执行。下面验证这一点:
有一个JSP页面Test.jsp,在浏览器地址栏中输入转载链接:http://localhost:8080/Test.jsp,将会出现执行结果。同时在�TALINA_HOME%/work/Catalina/localhost下多出两个文件:_Test_jsp.java和_Test_jsp.class,他们分别就是Servelet和Class文件。
2.Servlet的应用逻辑是在Java文件中,从Java代码中动态输出HTML,并且完全从表示层中的HTML里分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。JSP侧重于视图,Servlet主要用于控制逻辑。
26、四种会话跟踪技术
会话跟踪是一种灵活、轻便的机制,它使Web上的状态编程变为可能。
转载链接:HTTP是一种无状态协议,每当用户发出请求时,服务器就会做出响应,客户端与服务器之间的联系是离散的、非连续的。
当用户在同一网站的多个页面之间转换时,根本无法确定是否是同一个客户,会话跟踪技术就可以解决这个问题。
当一个客户在多个页面间切换时,服务器会保存该用户的信息。
有四种方法可以实现会话跟踪技术:URL重写、隐藏表单域、Cookie、Session。
1)隐藏表单域:,非常适合步需要大量数据存储的会话应用。
2)URL 重写:URL 可以在后面附加参数,和服务器的请求一起发送,这些参数为名字/值对。 见 转载链接:http://blog.csdn.net/xh16319/article/details/8464055
3)Cookie:一个 Cookie 是一个小的,已命名数据元素。服务器使用 SET-Cookie 头标将它作为 转载链接:HTTP
响应的一部分传送到客户端,客户端被请求保存 Cookie 值,在对同一服务器的后续请求使用一个
Cookie 头标将之返回到服务器。与其它技术比较,Cookie 的一个优点是在浏览器会话结束后,甚至
在客户端计算机重启后它仍可以保留其值。 见:转载链接:http://blog.csdn.net/xh16319/article/details/8464319
4)Session:使用 setAttribute(String str,Object obj)方法将对象捆绑到一个会话
隐藏域和URL重写有着共同的优点:
它们在Cookie被禁用或者根本不支持的情况下依旧能够工作。
缺点:所有页面必须是表单提交之后的结果,还有涉及许多冗长的处理工作。
Session 与 Cookie 的作用都是为了保持访问用户与后端服务器的交互状态。它们有各自的优点,也有各自的缺陷,然而具有讽刺意味的是它们的优点和它们的使用场景又是矛盾的。例如,使用 Cookie 来传递信息时,随着 Cookie 个数的增多和访问量的增加,它占用的网络带宽也很大,试想假如 Cookie 占用 200 个字节,如果一天的 PV 有几亿,它要占用多少带宽?所以有大访问量的时候希望用 Session,但是 Session 的致命弱点是不容易在多台服务器之间共享,所以这也限制了 Session 的使用。
1)、访问*.html的静态资源因为不会被编译为Servlet,也就不涉及session的问题。
2)、当JSP页面没有显式禁止session的时候,在打开浏览器第一次请求该jsp的时候,服务器会自动为其创建一个session,并赋予其一个sessionID,发送给客户端的浏览器。以后客户端接着请求本应用中其他资源的时候,会自动在请求头上添加:
Cookie:JSESSIONID=客户端第一次拿到的session ID
这样,服务器端在接到请求时候,就会收到session ID,并根据ID在内存中找到之前创建的session对象,提供给请求使用。这也是session使用的基本原理
session的id是从哪里来的,sessionID是如何使用的:当客户端第一次请求session对象时候,服务器会为客户端创建一个 session,并将通过特殊算法算出一个session的ID,用来标识该session对象,当浏览器下次(session继续有效时)请求别的资源 的时候,浏览器会偷偷地将sessionID放置到请求头中,服务器接收到请求后就得到该请求的sessionID,服务器找到该id的session返 还给请求者(Servlet)使用。一个会话只能有一个session对象,对session来说是只认id不认人。
一般来说,每次请求都会新创建一个session。
但这个也不一定的,总结下:对于多标签的浏览器(比如360浏览器)来说,在一个浏览器窗口中,多个标签同时访问一个页面,session是一个。对 于多个浏览器窗口之间,同时或者相隔很短时间访问一个页面,session是多个的,和浏览器的进程有关。对于一个同一个浏览器窗口,直接录入url访问 同一应用的不同资源,session是一样的。
Session的超时时间为maxInactiveInterval属性,可以通过对应的getMaxInactiveInterval()获取,通过setMaxInactiveInterval(longinterval)修改。
Session的超时时间也可以在web.xml中修改。另外,通过调用Session的invalidate()方法可以使Session失效。
Cookie的不可跨域名性
Cookie默认的maxAge值为–1。
如果maxAge为0,则表示删除该Cookie。Cookie机制没有提供删除Cookie的方法,因此通过设置该Cookie即时失效实现删除Cookie的效果。失效的Cookie会被浏览器从Cookie文件或者内存中删除,
例如:
Cookie cookie = new Cookie(“username”,“helloweenvsfei”); // 新建Cookie
cookie.setMaxAge(0); // 设置生命周期为0,不能为负数
response.addCookie(cookie); // 必须执行这一句
response对象提供的Cookie操作方法只有一个添加操作add(Cookie cookie)。
转载链接:https://blog.csdn.net/canot/article/details/50667793 (说的很细,很好)
Cookie的域名
如果想所有 helloweenvsfei.com名下的二级域名都可以使用该Cookie,需要设置Cookie的domain参数,例如:
Cookie cookie = new Cookie(“time”,“20080808”); // 新建Cookie
cookie.setDomain(".helloweenvsfei.com"); // 设置域名
cookie.setPath("/"); // 设置路径
cookie.setMaxAge(Integer.MAX_VALUE); // 设置有效期
response.addCookie(cookie); // 输出到客户端
我们实现一个永久登录的Demo:
方法:只在登录时查询一次数据库,以后访问验证登录信息时不再查询数据库。实现方式是把账号按照一定的规则加密后,连同账号一块保存到Cookie中。下次访问时只需要判断账号的加密规则是否正确即可
Session中禁止使用Cookie
既然WAP上大部分的客户浏览器都不支持Cookie,索性禁止Session使用Cookie,统一使用URL地址重写会更好一些。Java Web规范支持通过配置的方式禁用Cookie。下面举例说一下怎样通过配置禁止使用Cookie。
打开项目sessionWeb的WebRoot目录下的META-INF文件夹(跟WEB-INF文件夹同级,如果没有则创建),打开context.xml(如果没有则创建),编辑内容如下:
部署后TOMCAT便不会自动生成名JSESSIONID的Cookie,Session也不会以Cookie为识别标志,而仅仅以重写后的URL地址为识别标志了。
注意:该配置只是禁止Session使用Cookie作为识别标志,并不能阻止其他的Cookie读写。也就是说服务器不会自动维护名为JSESSIONID的Cookie了,但是程序中仍然可以读写其他的Cookie。
26.1单点登录
转载链接:https://www.cnblogs.com/ywlaker/p/6113927.html
cookie是有限制的,这个限制就是cookie的域(通常对应网站的域名),浏览器发送转载链接:http请求时会自动携带与该域匹配的cookie,而不是所有cookie。cookie本身不安全
prv:也就是A请求登录,发现没登录跳转到C服务器登录页完成登录,C往客户端(也即是浏览器)种下C自己的cookie(用来辨别是不是这个浏览器),
当B请求登录时,浏览器就会把C的cookie发送给C,然后C发现登录过了就重定向到B的主页。
cookie的查看权限只限于请求的域名,请求百度的时候浏览器只能看到百度种的cookie,新浪的cookie是看不到操作不了的。但是都是存在浏览器里面的。
27、dwr
DWR(Direct Web Remoting)是一个用于改善web页面与Java类交互的远程服务器端Ajax开源框架,可以帮助开发人员开发包含AJAX技术的网站。它可以允许在浏览器里的代码使用运行在WEB服务器上的JAVA函数,就像它就在浏览器里一样。
28、多态
最终解释:接口就是多态。相同接口多个实现类展现成各种各样的个体
父类声明指向子类对象,一个接口或者父类有多个子类实现形态,用在对集合的类型定义,公用方法的泛型类型定义上,可传入同一个类的不同子类实例
抽象类和接口要实例化,涉及到多态
抽象类主要用来抽象类别,接口主要用来抽象方法功能。关注事物的本质,用抽象类;关注一种操作,用接口
抽象类的而重点在于被子类继承的共同的代码,还有一个作用就是多态,可以使用父类声明作为方法的参数、返回类型或数组的类型,通过这个机制可以加入新的子类到程序中,却又不用修改程序代码,
父类声明指向子类对象
多态相对于重载==晚绑定
不要把重载理解为多态(重载是兄弟级别不是父子级别所以肯定不是多态) ,因为多态是一种运行期行为,不是编译器行为
多态:父类的引用可以指向子类对象
所谓多态,就是父类声明指向子类对象,或者接口类型的引用可以指向实现该接口的类的实例。
重载:两个方法名称相同但是参数不同。返回类型可以不同,不能只改变返回类型(重载主要是要参数不同),可以更改存取权限
prv:定义通用方法中用到的泛型(返回类型定义继承或者传参)也是多态的体现,集合的泛型也是
32、数据库事务
转载链接:https://blog.csdn.net/zhangwj0101/article/details/50945379
包含了对数据库进行读或写的一个操作序列,如果失败则进行回滚。
4个特性:原子性、一致性、隔离性、持久性 (ACID)
并非任意的对数据库的操作序列都是数据库事务。事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。
原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
持久性(Durability):一个事务一旦提交,他对数据库的修改应该永久保存在数据库中。
举例
用一个常用的“A账户向B账号汇钱”的例子来说明如何通过数据库事务保证数据的准确性和完整性。熟悉关系型数据库事务的都知道从帐号A到帐号B需要6个操作:
1、从A账号中把余额读出来(500)。
2、对A账号做减法操作(500-100)。
3、把结果写回A账号中(400)。
4、从B账号中把余额读出来(500)。
5、对B账号做加法操作(500+100)。
6、把结果写回B账号中(600)。
原子性:
保证1-6所有过程要么都执行,要么都不执行。一旦在执行某一步骤的过程中发生问题,就需要执行回滚操作。 假如执行到第五步的时候,B账户突然不可用(比如被注销),那么之前的所有操作都应该回滚到执行事务之前的状态。
一致性
在转账之前,A和B的账户中共有500+500=1000元钱。在转账之后,A和B的账户中共有400+600=1000元。也就是说,数据的状态在执行该事务操作之后从一个状态改变到了另外一个状态。同时一致性还能保证账户余额不会变成负数等。
隔离性
在A向B转账的整个过程中,只要事务还没有提交(commit),查询A账户和B账户的时候,两个账户里面的钱的数量都不会有变化。
如果在A给B转账的同时,有另外一个事务执行了C给B转账的操作,那么当两个事务都结束的时候,B账户里面的钱应该是A转给B的钱加上C转给B的钱再加上自己原有的钱。
持久性
一旦转账成功(事务提交),两个账户的里面的钱就会真的发生变化(会把数据写入数据库做持久化保存)!
事务的原子性与一致性缺一不可。
33、abstract、extends、implements
转载链接:https://blog.csdn.net/zhandoushi1982/article/details/8458081
extends是继承父类,只要那个类不是声明为final就能继承。JAVA中不支持多重继承,但是可以用接口来实现,这样就要用到implements。
继承只能继承一个类,但implements可以实现多个接口,用逗号分开就行了,比如 class A extends B implements C,D,E。
与extends的差别:extends 是继承某个类,继承之后可以使用父类的方法也可以重写父类的方法;implements 是实现多个接口,
接口的方法必须重写才能使用。要注意以下几点:
A,接口中一般定义的是常量和抽象方法。抽象类中可以包含抽象方法,也可以有非抽象方法,但是有抽象方法的类一定是抽象类。
抽象方法不能有方法体,不能有大括号。
B,接口(interface)中,方法只能定义抽象方法而且默认是Public,常量则是public static final 修饰的(不管有没有这些修饰符,
方法和常量默认具这种属性)。
C,一个类可以实现多个无关的接口(这点和继承要有所区别)。
D,接口可以继承其他的接口,并添加新的属性和抽象方法。
E,在类中实现接口的方法时必须加上public修饰符。
(1)相同点
A,两者都是抽象类,都不能实例化。
B,interface实现类及abstrct class的子类都必须要实现已经声明的抽象方法。
(2)不同点
A,interface实现,要用implements,而abstract class的实现,要用extends。
B,一个类可以实现多个interface,但一个类只能继承一个abstract class。
C,interface强调特定功能的实现,而abstract class强调所属关系。
D,尽管interface实现类及abstrct class的子类都必须要实现相应的抽象方法,但实现的形式不同。interface中的每一个方法都是抽象方法
,都只是声明的(declaration, 没有方法体),必须要实现。而abstract class的子类可以有选择地实现。
抽象类的这个选择有两点含义:一是Abastract class中并非所有的方法都是抽象的,只有那些冠有abstract的方法才是抽象的,
子类必须实现。那些没有abstract的方法,在Abstrct class中必须定义方法体。二是abstract class的子类在继承它时,
对非抽象方法既可以直接继承,也可以覆盖;而对抽象方法,可以选择实现,也可以通过再次声明其方法为抽象的方式,无需实现,
留给其子类来实现,但此类必须也声明为抽象类。既是抽象类,当然也不能实例化。
E,interface是完全抽象的,只能声明方法,而且只能声明pulic的方法,不能声明private及protected的方法,不能定义方法体,
也不能声明实例变量。
34、外部类不能使用private和protected修饰
外部类不能使用private和protected修饰,是因为外部类没有处于任何一个类的内部,也就是说它没有所在类的内部,所在类的子类这两个范围,因此private和protected访问控制符对外部类是没有意义的。说的再直白点就是,外部类它找不到一个可以跟它说的上是处于”同一个类中“或”子类中“的类。顶级类(外部类)只能是public或默认(default)修饰
35、spring&springmvc
转载链接:https://www.cnblogs.com/hhx626/p/6010293.html
spring是一种容器,里面包括了springmvc框架
36、基本数据类型
byte(8位二进制)
char(16位)
short(16位)
float(32位)
int(32位)
long(64位)
double(64位)
boolean JVM规范指出boolean当做int处理,也就是4字节,boolean数组当做byte数组处理
double 和 float 的区别是double精度高,有效数字16位,float精度7位。但double消耗内存是float的两倍,double的运算速度比float慢得多,java语言中数学函数名称double 和 float不同,不要写错,能用单精度时不要用双精度(以省内存,加快运算速度)。
spring是一个开源框架,功能主要是依赖注入和控制反转。
依赖注入有三种形式
1、构造注入(bytype)
2、setter注入
3、接口注入(byname) 而控制反转则主要是起到操控作用,把对象的创建,初始化,销毁交给spring容器来处理。面向切面(把功能分离出来)实现共用。
spring MVC类似于struts是负责前台和后台的交互,还有就是spring可以集成许多工具,像数据库配置,缓存配置,定时器配置等等都是在spring中完成的,而spring MVC是做不到的。
37、Spring AOP与IOC TODO需要更深理解
IoC(Inversion of control): 控制反转
控制权由对象(程序)本身转向容器;由容器根据配置文件去创建实例并创建各个实例之间的依赖关系
核心:bean工厂;在Spring中,bean工厂创建的各个实例称作bean
AOP(Aspect-Oriented Programming): 面向方面编程
1、 代理的两种方式:
静态代理:
针对每个具体类分别编写代理类;
针对一个接口编写一个代理类;
动态代理:
针对一个方面编写一个InvocationHandler,然后借用JDK反射包中的Proxy类为各种接口动态生成相应的代理类
依赖注入的三种方式:(1)接口注入(2)Construct注入(3)Setter注入
控制反转(IoC)与依赖注入(DI)是同一个概念
Spring核心IoC和AOP的理解
spring 框架的优点是一个轻量级笔记简单易学的框架,实际使用中的有点优点有哪些呢!
1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦
2.可以使用容易提供的众多服务,如事务管理,消息服务等
3.容器提供单例模式支持
4.容器提供了AOP技术,利用它很容易实现如权限拦截,运行期监控等功能
5.容器提供了众多的辅助类,能加快应用的开发
6.spring对于主流的应用框架提供了集成支持,如hibernate,JPA,Struts等
7.spring属于低侵入式设计,代码的污染极低
8.独立于各种应用服务器
9.spring的DI机制降低了业务对象替换的复杂性
10.Spring的高度开放性,并不强制应用完全依赖于Spring,开发者可以自由选择spring的部分或全部
什么是DI机制?
依赖注入(Dependecy Injection)和控制反转(Inversion of Control)是同一个概念,具体的讲:当某个角色
需要另外一个角色协助的时候,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在spring中
创建被调用者的工作不再由调用者来完成,因此称为控制反转。创建被调用者的工作由spring来完成,然后注入调用者
因此也称为依赖注入。
spring以动态灵活的方式来管理对象 , 注入的两种方式,设置注入和构造注入。
设置注入的优点:直观,自然
构造注入的优点:可以在构造器中决定依赖关系的顺序。
什么是AOP?
面向切面编程(AOP)完善spring的依赖注入(DI),面向切面编程在spring中主要表现为两个方面
1.面向切面编程提供声明式事务管理
2.spring支持用户自定义的切面
面向切面编程(aop)是对面向对象编程(oop)的补充,
面向对象编程将程序分解成各个层次的对象,面向切面编程将程序运行过程分解成各个切面。
AOP从程序运行角度考虑程序的结构,提取业务处理过程的切面,oop是静态的抽象,aop是动态的抽象,
是对应用执行过程中的步骤进行抽象,,从而获得步骤之间的逻辑划分。
aop框架具有的两个特征:
1.各个步骤之间的良好隔离性
2.源代码无关性
39、java内存模型
内存模型:
内存模型描述了程序中各个变量(实例域、静态域和数组元素)之间的关系,以及在实际计算机系统中将变量存储到内存和从内存中取出变量这样的底层细节
1、主内存和工作内存
Java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样底层细节。
2、内存间的交互操作
关于主内存与工作内存之间的具体交互协议,即一个变量如何从主内存拷贝到工作内存、如何从工作内存同步到主内存之间的实现细节,
Java内存模型定义了以下八种操作来完成:转载链接:https://blog.csdn.net/u012552052/article/details/44542971
内存名词:虚拟机栈、堆、方法区、直接内存、本地NATIVE方法栈、程序计数器
java内存模型、内存管理、java堆和栈、垃圾回收
40、数据库视图
作用:
①简化了操作,把经常使用的数据定义为视图。
我们在使用查询时,在很多时候我们要使用聚合函数,同时还要 显示其它字段的信息,可能还会需要关联到其它表,这时写的语句可能会很长,如果这个动作频繁发生的话,我们可以创建视图,这以后,我们只需要select * from view就可以啦,这样很方便。
②安全性,用户只能查询和修改能看到的数据。
因为视图是虚拟的,物理上是不存在的,只是存储了数据的集合,我们可以将基表中重要的字段信息,可以不通过视图给用户,视图是动态的数据的集合,数据是随着基表的更新而更新。同时,用户对视图不可以随意的更改和删除,可以保证数据的安全性。
③逻辑上的独立性,屏蔽了真实表的结构带来的影响。
视图可以使应用程序和数据库表在一定程度上独立。如果没有视图,应用一定是建立在表上的。有了视图之后,程序可以建立在视图之上,从而程序与数据库表被视图分割开来。
缺点:
①性能差
数据库必须把视图查询转化成对基本表的查询,如果这个视图是由一个复杂的多表查询所定义,那么,即使是视图的一个简单查询,数据库也要把它变成一个复杂的结合体,需要花费一定的时间。
②修改限制
当用户试图修改视图的某些信息时,数据库必须把它转化为对基本表的某些信息的修改,对于简单的视图来说,这是很方便的,但是,对于比较复杂的试图,可能是不可修改的。
42、overrride&overloaded
overrride
不能缩小父类权限,不能比父类抛出更多异常可以不抛出,final方法不能重写
overloaded
参数类型,个数,顺序至少有一个不同
不能改变返回值类型
44、ArrayList&LinkedList
arraylist数组式的,查询快,但是任意增加删除比较慢,因为要移动元素等内存操作,所以比linkedlist慢
vector数组式,线程安全,所以性能没arraylist好。
linkedlist双向链表式实现存储,增加删除快,但是查询慢,因为要遍历指针
String类型大小不能被修改,当修改时其实是生成了一个新的String对象
StringBuffer可以修改,而且是线程安全的。
stringbuffer线程安全,stringbuilder不安全
序列化:
1. 如果子类实现Serializable接口而父类未实现时,父类不会被序列化!
2. 如果父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口。
45、同步有几种实现方式
同步的实现方式有两种,分别是synchronize,wait和notify
反对使用stop()和suspend(),因为stop不安全,会接触由线程获取的所有锁定。
suspend容易发生死锁,所以应在自己的Thread类中置入一个标志。
wait与notify
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,
而是由JVM确定唤醒哪个线程,而且不是按优先级。就算唤醒了也不一定立刻能获取对象锁或者执行,还要竞争的。
Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
prv:有wait就表示释放了锁让别人先,sleep则是把钥匙压在身下。
join可以把一个线程加塞到主线程前面,次线程执行完再执行主线程。
wait() 方法要以 try/catch 包覆,或是掷出 InterruptedException
46、final修饰对象时表示该对象引用不能改变,但该对象本身可以做修改
48、如何获取一个目录下有多少文件
File file = new File(“D://”);
int count = file.list().length;
49、简述你对java反射机制的理解
JAVA反射机制是运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意
一个对象,都能调用它的任意一个方法和属性。
prv:相当于java自己在运行过程中创建类实例化对象调用属性和方法,本来jvm就可以自己创建类对象。可以让开发者利用,
用类加载器加载类实例化对象并调用属性或者方法。
50、Hibernate
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架
个人理解:一级缓存是Session级缓存,属于事务范围的。生命周期短,各个session间无法共享,执行getloadupdatesave时将对象进行缓存。
二级缓存:SessionFactory缓存,属于进程级、群集范围的,对一些不经常update的数据进行缓存,可插拔式的。
延迟加载:获取对象时先利用JDK的代理机制先获取对象的代理,而不是真的对象引用,但涉及对象调用时才真的去加载对象。
1、一级缓存
一级缓存是Session级的缓存(事务级别跟会话不一样),其生命周期很短,与Session相互对应。一级缓存由Hibernate进行管理,属于事务范围的缓存。
当程序调用Session的load()方法、get()方法、save()方法、saveOrUpdate()方法、update()方法或查询接口方法时,Hibernate会对实体对象进行缓存;当通过load()方法或get()方法查询实体对象时,Hibernate会首先到缓存中查找,在找不到实体对象的情况下,Hibernate才会发出SQL语句到数据库中查询,从而提高了Hibernate的使用效率。
例:如果在同一Session中连续两次查询同一对象,由于一级缓存的存在,Hibernate只发出一条SQL语句。
注:一级缓存的生命周期与Session相对应,它并不会在Session之间共享,在不同的Session中不能得到其它Session中缓存的实体对象。
2、二级缓存
二级缓存是SessionFactory级的缓存,其生命周期与SessionFactory一致。二级缓存可以在多个Session之间共享,属于进程范围或群集范围的缓存。
二级缓存是一个可插拔的缓存插件,它的使用需要第三方缓存产品的支持。在Hibernate框架中,通过Hibernate配置文件配置二级缓存的使用策略。
注:对于二级缓存,可以使用一些不经常更新的数据或参考的数据,此时其性能会得到明显的提升。例如一个新闻网站,当发布一条热点新闻时,会有成千上万的访问量,而此条新闻并没有发生任何的变化,如果每一个用户访问都要查询数据库,势必对系统性能造成一定的影响,此时可以考虑应用二级缓存。如果经常变换的数据则不应应用二级缓存。
3、Lazy策略
Lazy策略为延迟加载策略,Hibernate通过JDK代理对其进行实现,即使用延迟加载的对象,在获取对象的时候返回的是对象的代理,并不是对象的真正引用,只有在对象真正被调用的时候,Hibernate才会对其进行查询,返回真正的对象。
这在某种程度上对性能起到一定的优化。Hibernate的延迟加载还可以减少程序与数据库的连接次数,因为使用了延迟加载,Hibernate将延缓执行SQL语句,减少对数据库的访问次数,从而提高执行效率。
例://第一个session
Session.beginTransaction();
User user=(User)session.load(User.class, new Integer(1));
session.getTransaction.commit();
//第二个session
Session.beginTransaction();
User user=(User)session.load(User.class, new Integer(1));
System.out.println(“name=”+user.getName());
session.getTransaction.commit();
解释:实例中开启了两个session对象,两次均使用了load()方法查询,在第一次查询中,对于查询到的对象并没有任何引用,所以Hibernate不会发出SQL语句;而第二次查询中,实例输出了user对象的名称属性,对查询后的对象进行引用,因此此时Hibernate会发出一条SQL语句。
Session
Session接口负责执行被持久化对象的CRUD操作(CRUD的任务是完成与数据库的交流,包含了很多常见的SQL语句)。但需要注意的是Session对象是非线程安全的。同时,Hibernate的session不同于JSP应用中的转载链接:HttpSession。这里当使用session这个术语时,其实指的是Hibernate中的session,而以后会将转载链接:HttpSession对象称为用户session。
SessionFactory
SessionFactory接口负责初始化Hibernate。它充当数据存储源的代理,并负责创建Session对象。这里用到了工厂模式。需要注意的是SessionFactory并不是轻量级的,因为一般情况下,一个项目通常只需要一个SessionFactory就够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。
Transaction
Transaction 接口是一个可选的API,可以选择不使用这个接口,取而代之的是Hibernate 的设计者自己写的底层事务处理代码。 Transaction 接口是对实际事务实现的一个抽象,这些实现包括JDBC的事务、JTA 中的UserTransaction、甚至可以是CORBA 事务。之所以这样设计是能让开发者能够使用一个统一事务的操作界面,使得自己的项目可以在不同的环境和容器之间方便地移植。
Query
Query接口让你方便地对数据库及持久对象进行查询,它可以有两种表达方式:HQL语言或本地数据库的SQL语句。Query经常被用来绑定查询参数、限制查询记录数量,并最终执行查询操作。
Criteria
Criteria接口与Query接口非常类似,允许创建并执行面向对象的标准化查询。值得注意的是Criteria接口也是轻量级的,它不能在Session之外使用。
Configuration
Configuration 类的作用是对Hibernate 进行配置,以及对它进行启动。在Hibernate 的启动过程中,Configuration 类的实例首先定位映射文档的位置,读取这些配置,然后创建一个SessionFactory对象。虽然Configuration 类在整个Hibernate 项目中只扮演着一个很小的角色,但它是启动hibernate 时所遇到的第一个对象。
一级缓存
当应用程序调用Session的save()、update()、saveOrUpdate()、get()或load(),以及调用查询接口的 list()、iterate()或filter()方法时,如果在Session缓存中还不存在相应的对象,Hibernate就会把该对象加入到第一级缓存中。当清理缓存时,Hibernate会根据缓存中对象的状态变化来同步更新数据库。 Session为应用程序提供了两个管理缓存的方法: evict(Object obj):从缓存中清除参数指定的持久化对象。 clear():清空缓存中所有持久化对象。
二级缓存
3.1. Hibernate的二级缓存策略的一般过程如下:
1) 条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象。
2) 把获得的所有数据对象根据ID放入到第二级缓存中。
3) 当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照ID放入到缓存。
4) 删除、更新、增加数据的时候,同时更新缓存。
3.2. 什么样的数据适合存放到第二级缓存中? 1 很少被修改的数据 2 不是很重要的数据,允许出现偶尔并发的数据 3 不会被并发访问的数据 4 参考数据,指的是供应用参考的常量数据,它的实例数目有限,它的实例会被许多其他类的实例引用,实例极少或者从来不会被修改。
3.3. 不适合存放到第二级缓存的数据? 1 经常被修改的数据 2 财务数据,绝对不允许出现并发 3 与其他应用共享的数据。
延迟加载编辑
延迟加载
Hibernate对象关系映射提供延迟的与非延迟的对象初始化。非延迟加载在读取一个对象的时候会将与这个对象所有相关的其他对象一起读取出来。这有时会导致成百的(如果不是成千的话)select语句在读取对象的时候执行。这个问题有时出现在使用双向关系的时候,经常会导致整个数据库都在初始化的阶段被读出来了。当然,你可以不厌其烦地检查每一个对象与其他对象的关系,并把那些最昂贵的删除,但是到最后,我们可能会因此失去了本想在ORM工具中获得的便利。
一个明显的解决方法是使用Hibernate提供的延迟加载机制。这种初始化策略只在一个对象调用它的一对多或多对多关系时才将关系对象读取出来。这个过程对开发者来说是透明的,而且只进行了很少的数据库操作请求,因此会得到比较明显的性能提升。这项技术的一个缺陷是延迟加载技术要求一个Hibernate会话要在对象使用的时候一直开着。
幸运的是,Spring框架为Hibernate延迟加载与DAO模式的整合提供了一
Hibernate有关书籍
Hibernate有关书籍(10张)
种方便的解决方法。以一个Web应用为例,Spring提供了OpenSessionInViewFilter和OpenSessionInViewInterceptor。我们可以随意选择一个类来实现相同的功能。两种方法唯一的不同就在于interceptor在Spring容器中运行并被配置在web应用的上下文中,而Filter在Spring之前运行并被配置在web.xml中。不管用哪个,他们都在请求将当前会话与当前(数据库)线程绑定时打开Hibernate会话。一旦已绑定到线程,这个打开了的Hibernate会话可以在DAO实现类中透明地使用。这个会话会为延迟加载数据库中值对象的视图保持打开状态。一旦这个逻辑视图完成了,Hibernate会话会在Filter的doFilter方法或者Interceptor的postHandle方法中被关闭。
Hibernate缓存及延迟加载
原创 2014年11月03日 09:58:49 815
“缓存”在提高系统性能方面发挥着重要的作用。其基本实现原理:将原始数据通过一定的算法,将其备份并保存到新的媒介中,使其访问速度远远高于原始数据的访问数据。通常情况下,其介质一般是内存,所以读写速度非常块。
Hibernate框架也应用了缓存技术,并实现了两级缓存,一级缓存即Session的缓存,二级缓存即SessionFactory的缓存。
51、Hibernate&Mybatis
Mybatis优势MyBatis可以进行更为细致的SQL优化,可以减少查询字段。
MyBatis容易掌握,而Hibernate门槛较高。
Hibernate优势
Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。
Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。
Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。
Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。
53、工厂模式
所谓的工厂模式,一般有三种方式来封装
简单工厂:把对象的创建放到一个工厂类中,通过参数来创建不同的对象。这个缺点是每添一个对象,就需要对简单工厂进行修改
(尽管不是删代码,仅仅是添一个switch case,但仍然违背了“不改代码”的原则)
工厂方法:每种产品由一种工厂来创建,一个工厂保存一个new基本完美,完全遵循 “不改代码”的原则
抽象工厂:仅仅是工厂方法的复杂化,保存了多个new大工程才用的上,定义在类层面,里面包含多种产品实例化方法。
54、comparable&comparator
prv:comparable自己让对象自己跟自己比较,有一个compareTo方法。内比较外比较
comparator 可以直接是实现比较规则,利用compare方法
comparable-compareTo & comparator-compare
Comparable
Comparable可以认为是一个内比较器,实现了Comparable接口的类有一个特点,就是这些类是可以和自己比较的,至于具体和另一个实现了Comparable接口的类如何比较,则依赖compareTo方法的实现,compareTo方法也被称为自然比较方法。如果开发者add进入一个Collection的对象想要Collections的sort方法帮你自动进行排序的话,那么这个对象必须实现Comparable接口。compareTo方法的返回值是int,有三种情况:
1、比较者大于被比较者(也就是compareTo方法里面的对象),那么返回正整数
2、比较者等于被比较者,那么返回0
3、比较者小于被比较者,那么返回负整数
public class Domain implements Comparable
{
private String str;
public Domain(String str) { this.str = str; } public int compareTo(Domain domain) { if (this.str.compareTo(domain.str) > 0) return 1; else if (this.str.compareTo(domain.str) == 0) return 0; else return -1; } public String getStr() { return str; } } Comparator Comparator可以认为是是一个外比较器,个人认为有两种情况可以使用实现Comparator接口的方式: 1、一个对象不支持自己和自己比较(没有实现Comparable接口),但是又想对两个对象进行比较 2、一个对象实现了Comparable接口,但是开发者认为compareTo方法中的比较方式并不是自己想要的那种比较方式 Comparator接口里面有一个compare方法,方法有两个参数T o1和T o2,是泛型的表示方式,分别表示待比较的两个对象,方法返回值和Comparable接口一样是int,有三种情况: 1、o1大于o2,返回正整数 2、o1等于o2,返回0 3、o1小于o3,返回负整数 写个很简单的例子,上面代码的Domain不变(假设这就是第2种场景,我对这个compareTo算法实现不满意,要自己写实现): public class DomainComparator implements Comparator<Domain> { public int compare(Domain domain1, Domain domain2) { if (domain1.getStr().compareTo(domain2.getStr()) > 0) return 1; else if (domain1.getStr().compareTo(domain2.getStr()) == 0) return 0; else return -1; } } 总结一下,两种比较器Comparable和Comparator,后者相比前者有如下优点: 1、如果实现类没有实现Comparable接口,又想对两个类进行比较(或者实现类实现了Comparable接口,但是对compareTo方法内的 比较算法不满意),那么可以实现Comparator接口,自定义一个比较器,写比较算法 2、实现Comparable接口的方式比实现Comparator接口的耦合性 要强一些,如果要修改比较算法,要修改Comparable接口的实现类, 而实现Comparator的类是在外部进行比较的,不需要对实现类有任何修 改。
55、Enumeration接口和Iterator接口的区别有哪些?
Enumeration速度是Iterator的2倍,同时占用更少的内存。但是,Iterator远远比Enumeration安全,因为其他线程不能够修改正
在被iterator遍历的集合里面的对象。同时,Iterator允许调用者删除底层集合里面的元素,这对Enumeration来说是不可能的。
56、预编译防sql注入
使用PreparedStatement的参数化的查询可以阻止大部分的SQL注入。在使用参数化查询的情况下,数据库系统不会将参数的内容视为
SQL指令的一部分来处理,而是在数据库完成SQL指令的编译后,才套用参数运行,因此就算参数中含有破坏性的指令,也不会被数据
库所运行。因为对于参数化查询来说,查询SQL语句的格式是已经规定好了的,需要查的数据也设置好了,缺的只是具体的那几个数据
而已。所以用户能提供的只是数据,而且只能按需提供,无法更进一步做出影响数据库的其他举动来。
57、Apache MINA 编辑
转载链接:https://www.cnblogs.com/moonandstar08/p/5475766.html
转载链接:https://blog.csdn.net/onafioo/article/details/7912059
转载链接:https://blog.csdn.net/u012151597/article/details/78870719
断包粘包:
解码器继承CumulativeProtocolDecoder 类,实现对mina 断包,粘包问题解决 [ˈkju:mjələtɪv] 累积的;
主要思路:
1、判断当前缓存去中是否存在数据,如果存在,则进行后续处理。
2、获取报文数据【报文规范为:长度 (2个字节) + 方法编号(1个字节) + 内容】,先获取长度,判断缓存区剩余数据长度与
报文长度是否相等,如果不相等,代表报文数据不完整,返回 false,需要再次从缓存去读取
3、相等,则获取方法编号,内容,获取到该内容后,则先将该部分完整数据送给handler处理,
4、判断缓存区是否还存在数据,如果存在,代表该报文后面还粘包了。则返回true.
个人:Acceptor/Connector(select connect事件)–封装链接成IoSession均分给后面–Processor(负责IO读写和后面的–
IoFilterChain&IoHandler、每个Processor维护着一个selector,对它维护的IoSession集合进行select遍历
Processor:(单一的Processor线程内部来看,IO请求的处理流程是单线程顺序处理的。处理的流程包括IoFilter和IoHandler里的
逻辑。如果其中有比较耗时的操作的话(如:读取数据库等),Processor线程将会被阻塞住,后续的请求将得不到处理。这样的情况在
高并发的服务器下显然是不能容忍的。于是,Mina通过在处理流程中引入线程池来解决这个问题。那么线程池应该加在什么地方呢?
正如前面所提到过的:IoFilterChain))
Ioservice–IoProcesser-IoHandler
经过上面的对比,我们已经能够知道IoHandler与IoProcessor的本质区别。
IoHandler是在IoFilterChain执行中最后一个IoFilter中被调用,比如,经过IoFilterChain进行 codec、logging等等操作之后,
已经将通信层的数据转化成我们需要的业务对象数据,这时就可以调用我们定义的IoHandler实 现来进行处理。
IoProcessor是与实际的Socket或Channel相关的操作紧密相关的,也就是说,它是支撑Mina进行处理底层实际I/O请 求的处理器。
IoHandler接口所定义的操作,一共定义了7个处理事件的操作,如下所示:
public interface IoHandler { sessionCreated; sessionClosed、sessionIdle、exceptionCaught、messageReceived、
void messageSent(IoSession session) throws Exception; } 个人:session3个exceptioncaught1个message2个
因为IoHandler是一个接口,所以如果使用该接口我们就必须实现所有的方法,MIna通过使用IoHandlerAdapter来默认实现
IoHandler接口,并在IoHandlerAdapter中全部给出空实现,如果我们要开发自己的IoHandler,可以继承自IoHandlerAdapter,
根据需要选择重写指定的处理Mina事件的方法,而对于你不感兴趣的方法就默认不给予实现(默认使用 IoHandlerAdapter的空实现)。
那么,Mina调用IoHandler的时机是什么呢?又是如何调用的呢?
其实,根据Mina的架构,我们知道,在客户端主动发起I/O操作请求以后,会等待Mina触发相应的事件,在经过一组IoFilter之后,
在 IoFilter链的最后一个IoFilter被调用将要结束的时候,会调用我们注册的IoHandler实现,经过处理来满足实际业务逻辑需要。
Apache Mina是一个能够帮助用户开发高性能和高伸缩性网络应用程序的框架。它通过Java nio技术基于TCP/IP和UDP/IP协议提供了
抽象的、事件驱动的、异步的API。
Acceptor与Connector线程
在服务器端,bind一个端口后,会创建一个Acceptor线程来负责监听工作。这个线程的工作只有一个:调用Java NIO接口在该端口
上select connect事件,获取新建的连接后,封装成IoSession,交由后面的Processor线程处理。
在客户端,也有一个类似的,叫Connector的线程与之相对应。这两类线程的数量只有1个,外界无法控制这两类线程的数量。
Processor线程
Processor线程主要负责具体的IO读写操作和执行后面的IoFilterChain和IoHandler逻辑。Processor线程的数量N默认是CPU数量+1,可以通过配置参数来控制其数量。前面进来的IoSession会被分配到这N个Processor线程中。默认的SimpleIoProcessorPool的策略是session id绝对值对N取模来分配。
每个Porcessor线程中都维护着一个selector,对它维护的IoSession集合进行select,然后对select的结果进行遍历,逐一处理。像前面提到的,读取数据,以事件的形式通知后面IoFilterChain;以及对写请求队列的flush操作,都是在这类线程中来做的。
通过将session均分到多个Processor线程里进行处理,可以充分利用多核的处理能力,减轻select操作的压力。默认的Processor的线程数量设置可以满足大部分情况下的需求,但进一步的优化则需要根据实际环境进行测试。
四、线程模型
线程模型原理
单一的Processor线程内部来看,IO请求的处理流程是单线程顺序处理的。前面也提到过,当Process线程select了一批就绪的IO
请求后,会在线程内部逐一对这些IO请求进行处理。处理的流程包括IoFilter和IoHandler里的逻辑。当前面的IO请求处理完毕后,
才会取下一个IO请求进行处理。也就是说,如果IoFilter或IoHandler中有比较耗时的操作的话(如:读取数据库等),
Processor线程将会被阻塞住,后续的请求将得不到处理。这样的情况在高并发的服务器下显然是不能容忍的。于是,Mina通过在处
理流程中引入线程池来解决这个问题。
那么线程池应该加在什么地方呢?正如前面所提到过的:IoFilterChain是Mina的扩展点。没错,Mina里是通过IoFilter的形式来
为处理流程添加线程池的。Mina的线程模型主要有一下这几种形式:
Mina的线程池实现分析(1)
MINA 可以通过ExecutorFilter 将IO线程与业务处理线程分开
ExecutorFilter 缺省使用OrderedThreadPoolExecutor线程池。
需要注意的是这个线程池,对应同一个session而言,是顺序执行的.
也就是说,当一个连接,发送多笔消息上来时,这些消息都是按顺序执行的,第二笔消息再第一笔处理完之前,是不会执行的。
这对于向下提供同步处理的服务来讲,没有问题,客户端上来一个请求,服务端处理一个,响应,然后处理一下一个。
但是对于处理异步的请求就是个噩梦,同一个连接会同时收到多笔请求。
这时只能创建自己的线程池对象了。
Mina多线程数据结构thread框架
线程池是并发应用中,为了减少每个任务调用的开销增强性能而经常使用的技术。在mina中大量的使用这一技术,除了Executors
的工厂方法构建线程池之外,它还继承自ThreadPoolExecutor提供自己的线程池的实现OrderedThreadPoolExecutor和
UnorderedThreadPoolExecutor。这两者主要应用于ExecutorFilter过滤器。这个过滤器是mina内部实现的众多过滤器之一,
其主要作用是把I/O events提交给线程池同时处理同一个IOSession的事件,其默认的线程池的构造是前者。这两个线程池的区别
就在于同时处理I/O事件时,前者能够保证同一个Session的事件的处理顺序,而后者则不能保证,所以有可能出现sessionClosed
事件在messageReceived事件之前被处理。下面试着从代码解密其怎么保证事件处理顺序的。
个人:ThreadPoolExecutor 即时import java.util.concurrent.Executor;//JDK自带的线程池类
根据图里面的信息,发现在NioProcessor.java中
@Override
protected int select(long timeout) throws Exception {
return selector.select(timeout);
}
然后继续跟踪,在AbstractPollingIoProcessor.java类中
上述行发生了阻塞行为,这个类是干嘛的呢?这个类是MINA2中去轮训SELECTOR中是否有空闲的,查看一下selector的源码:
仔细的看看注释:
Selects a set of keys whose corresponding channels are ready for I/O[color=red][/color]
原来是去轮训IO通道是否空闲,也就是说上述阻塞是发生在这里,也就是说IO通道被轮训发生的阻塞,所以说本文开头的阻塞数量是
这样产生的:当大量的并发消息过来,MINA2服务端需要轮训IO通道是否OK,OK之后就马上交给工作线程(如果有)去处理。所以从
上面看来,这个是正常现象。在同时并发大量消息的时候,MINA2的IO通道还是会有堵塞。
另外:
我们知道:
MINA2采用JAVA原生的newCachedThreadPool,以及MINA2自带的 OrderedThreadPoolExecutor 线程池,在性能上没有太大的区别;
我们知道:MINA2采用的是责任链模式,在处理过程中插入不同的filter,来进行不同的处理。
当服务器端启动的时候,会启动默认的I0线程,也就是主线程,MINA2建议是CPU数量+1,如果代码中不增加上述一行,那么如果加入
上述的ExecutorFilter之后,工作线程将会和IO线程分开,简单的例子,如果你要发一些消息给服务端,要服务端提交一个事务,
如果不采用ExecutorFilter,那么IO线程就会一直等待这个事务结束,才会接着处理下一个任务,否则一直等待,如果采用了
ExecutorFilter,那么IO线程会将任务交给ExecutorFilter的线程池,由线程池去处理事务,而IO线程就释放了,这样IO线程非
常高效的能够同时处理很多的并发任务。
用new ExecutorFilter(),缺省使用OrderedThreadPoolExecutor线程池。需要注意的是这个线程池,对应同一个session而言,
是顺序执行的.也就是说mina2里面的message处理都是顺序的,不会说出现在消息没有接受完毕之前关闭。
常见的也有这样的处理:修改成:
filterChainBuilder.addLast(“threadPool”, new ExecutorFilter(Executors.newCachedThreadPool());
对于没有顺序要请求的情况,可以为ExecutorFilter指定一个Executor来替换掉默认的OrderedThreadPoolExecutor,
让同一个session的多个请求能被并行地处理,来进一步提高吞吐量。
59、工程注意
A1、通过项目对线程池有了更多的了解
B1、业务处理中更好处理需求,对于多用户并发访问,利用mina-excutorfilter方法创建一个固定大小的线程池newFixedThreadPool添加到
过滤链的末端,来提高消息处理速率
四种模型:CachedThreadPool:一个可缓存的线程池,如果线程池的当前规模超过了处理需求时,那么将回收空闲的线程,当需求增加时,则可以添加新的线程,线程池的规模不存在任何的限制。
FixedThreadPool:一个固定大小的线程池,提交一个任务时就创建一个线程,直到达到线程池的最大数量,这时线程池的大小将不再变化。
SingleThreadPool:一个单线程的线程池,它只有一个工作线程来执行任务,可以确保按照任务在队列中的顺序来串行执行,如果这个线程异常结束将创建一个新的线程来执行任务。
ScheduledThreadPool:一个固定大小的线程池,并且以延迟或者定时的方式来执行任务,类似于Timer。
MINA 可以通过ExecutorFilter 将IO线程与业务处理线程分开
过滤链 :filterChainBuilder.addLast(“threadPool”, new ExecutorFilter(Executors.newFixedThreadPool(10));
全国人工服务器 初始化一个线程池 利用JDK1.6的线程池类
import java.util.concurrent.Executors;
private static DoWorker instance = new DoWorker();
private static Executor dbService;
public static DoWorker getInstance() {
return instance;
}
public void init(){
dbService = Executors.newFixedThreadPool(10);
}
public void submit(MyProtocalPack pack) {//AAAA
WXWork work = new WXWork(pack);
try {
dbService.execute(work);
} catch (Exception e) {}}
class WXWork implements Runnable{
private MyProtocalPack pack;
public WXWork(MyProtocalPack pack){
this.pack = pack;
count.incrementAndGet();
}
public void run() {xxxxxxxxxx具体实现}
public class SamplMinaClientHandler extends IoHandlerAdapter//实现IoHandlerAdapter覆盖messageReceived方法当消息到达时创建业务处理对象并放到线程池中。
@Override
public void messageReceived(IoSession session, Object message) throws Exception {
MyProtocalPack pack = (MyProtocalPack) message;
Message mess = new Message();
if (2 == pack.getPackhead().getIInCommand()) {
if (0 == pack.getWorkContext().getCSubCmd()) {
session.write(mess.transfersMsgResp(pack).order(ByteOrder.BIG_ENDIAN));
DoWorker.getInstance().submit(pack);}}//主要是这行,调用上面的submit方法(AAAA)将处理业务
的对象放置到线程池中。
A2、(任选一项目)通过web.xml中配置listener监听器来进行对数据的初始化,并将可能被更改的配置类数据通过定时器实现定时加载,为运营人员配置数据
增加了灵活性。
B2、ConnectListenInit
Timer time = new Timer();
time.schedule(new LoadConfTask(),0, 60601000);
A3、图片服务器项目优化:上传下载分离,负载均衡。限制上传图片大小,检查图片是否包含非法字符,检查图片头格式。服务器按日期层级创建目录结构,
按目录与随机因子加密生成新图片名,比起用数据库表建立图片名与图片路径对应关系省去了数据库连接以及表的读写操作,缓解数据库压力。
A4、(任选一项目):增加了对服务器调优以及web安全方面的认识。由于性能瓶颈更加了解到服务器调优的重要性,了解了jvm-javaopts的配置
以及web安全方面中间件管理后台清理、隐藏版本号、错误统一提示页面设置防止异常信息打印。
B4、JVM内存JAVA_OPTS参数
JAVA_OPTS="-server -Xms2048m -Xmx2048m -XX:NewSize=128m -XX:MaxNewSize=512m -XX:PermSize=128m -XX:MaxPermSize=512m"
-Xms:初始Heap大小,使用的最小内存,cpu性能高时此值应设的大一些
-Xmx:java heap最大值,使用的最大内存
-XX:PermSize:设定内存的永久保存区域
-XX:MaxPermSize:设定最大内存的永久保存区域
WEB安全方面:清理服务器上各个应用中间件管理后台的相关文件,隐藏中间件的版本号
1、隐藏tomcat版本
转载链接:https://jingyan.baidu.com/article/d2b1d102a9dc955c7e37d487.html
cd tomcat/lib/
jar xvf catalina.jar
vi org/apache/catalina/util/ServerInfo.properties
jar cvf catalina.jar META-INF/ org/
rm -r META-INF/ org/
修改tomcat-lib下catalina.jar包里面的ServerInfo.propeties中tomcat版本信息并重新压缩
2、中间件管理后台是否对公网开放并没有修改默认路径 --各项目删webapps
3、是否对网站的404、400、500等错误状态设置统一的错误提示页面 – web.xml
A5、(任选一管理后台项目或几个项目),注意到了管理后台安全方面的知识,登录验证码时效,尝试次数,ip,业务流程中也需要注意安全认证。
B5、管理后台安全方面:验证码有效时间,同一ip尝试次数,失败次数,用户状态,日志记录,除了登录之外其他地方的安全认证比如
sessionid认证。
tomcat log4j 日志路径设置 log4j.appender.info.File=${catalina.base}/log/info.log
不同服务用properties文件存放差异配置信息,数据库配置,套接字配置,渠道信息。
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("/ipConfig.properties");
Properties p = new Properties();
try {
p.load(inputStream);
} catch (IOException e1) { e1.printStackTrace(); }
SocketEx.HOST=p.getProperty(“ip”);SocketEx.systemid = p.getProperty(“systemid”);
------------------工程轮廓-----------
RobotApp
ip验证
参数验证
判断用户指令:接入,退出,在线
判断消息协议类型:文字,图片,语音
维护用户信息进队列
微信公众号
初始化活动、业务数据,区分地市并定时加载
判断用户状态(地市选择,导航,人工)
根据用户动作(菜单,链接,文字,二维码,摇一摇)转入不同业务流程
维护用户个人信息(高速缓存、本地缓存、数据库),用户队列信息
消息类型封装及调用时机(被动回复,客服消息,模板,群推–纯文字、图文块、图文列表)
高并发的时候负载均衡,与其他应用分库隔离,访问量大的静态资源分流,用户信息必查类的预加载,利用网络层框架mina,利用nginx分发。
访问量高的功能模块拆离,高速缓存memcache
(负载均衡、高并发需要学其他处理技术)
66、springboot
1、Spring Boot 启动加载数据 CommandLineRunner 命令行执行器
实际应用中,我们会有在项目服务启动的时候就去加载一些数据或做一些事情这样的需求。
@Component
@Order(value=2)
public class MyStartupRunner1 implements CommandLineRunner {
SpringBoot应用程序在启动后,会遍历CommandLineRunner接口的实例并运行它们的run方法。也可以利用@Order注解
(或者实现Order接口)来规定所有CommandLineRunner实例的运行顺序。
2、其他注解
@SpringBootApplication :快捷配置启动类,自动扫描配置bean并支持选择是否用系统或者用户定义的重复bean
@MapperScan(“com.im.needs.mapper”):自动配置mapper注解类
@Configuration :bean配置
extends WebMvcConfigurerAdapter
@Bean :将类注入到springioc容器中
public SecurityInterceptor getSecurityInterceptor() {
return new SecurityInterceptor();
}
private class SecurityInterceptor extends HandlerInterceptorAdapter :定义安全拦截器内部类
3、@Responsebody
注解表示该方法的返回的结果直接写入 转载链接:HTTP 响应正文(ResponseBody)中,一般在异步获取数据时使用,通常是在使用 @RequestMapping 后,返回值通常解析为跳转路径,加上 @Responsebody 后返回结果不会被解析为跳转路径,而是直接写入转载链接:HTTP 响应正文中。
4、@RequestBody
@RequestBody 注解则是将 转载链接:HTTP 请求正文插入方法中,使用适合的 转载链接:HttpMessageConverter 将请求体写入某个对象。
作用:
1) 该注解用于读取Request请求的body部分数据,使用系统默认配置的转载链接:HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上;
2) 再把转载链接:HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上。
使用时机:
A) GET、POST方式提时, 根据request header Content-Type的值来判断:
application/x-www-form-urlencoded, 可选(即非必须,因为这种情况的数据@RequestParam, @ModelAttribute也可以处理,当然@RequestBody也能处理);
multipart/form-data, 不能处理(即使用@RequestBody不能处理这种格式的数据);
其他格式, 必须(其他格式包括application/json, application/xml等。这些格式的数据,必须使用@RequestBody来处理);
5、Mapper相关
@Select 是查询类的注解,所有的查询均使用这个
@Result 修饰返回的结果集,关联实体类属性和数据库字段一一对应,如果实体类属性和数据库属性名保持一致,就不需要这个属性来修饰。
@Insert 插入数据库使用,直接传入实体类会自动解析属性到对应的值
@Update 负责修改,也可以直接传入对象
@delete 负责删除
public interface UserMapper {
@Select(“SELECT * FROM users”)
@Results({
@Result(property = “userSex”, column = “user_sex”, javaType = UserSexEnum.class),
@Result(property = “nickName”, column = “nick_name”)
})
List getAll();
@Select("SELECT * FROM users WHERE id = #{id}") @Results({ @Result(property = "userSex", column = "user_sex", javaType = UserSexEnum.class), @Result(property = "nickName", column = "nick_name") }) UserEntity getOne(Long id); @Insert("INSERT INTO users(userName,passWord,user_sex) VALUES(#{userName}, #{passWord}, #{userSex})") void insert(UserEntity user); @Update("UPDATE users SET userName=#{userName},nick_name=#{nickName} WHERE id =#{id}") void update(UserEntity user); @Delete("DELETE FROM users WHERE id =#{id}") void delete(Long id); } 注意,使用#符号和$符号的不同: // This example creates a prepared statement, something like select * from teacher where name = ?; @Select("Select * from teacher where name = #{name}") Teacher selectTeachForGivenName(@Param("name") String name); // This example creates n inlined statement, something like select * from teacher where name = 'someName'; @Select("Select * from teacher where name = '${name}'") Teacher selectTeachForGivenName(@Param("name") String name);
67、maven
引用自定义jar包需要在pom.xml中配置compilerArguments(编译器参数 )
-verbose
-Xlint:unchecked
-Xlint:deprecation
-bootclasspath
e
n
v
.
J
A
V
A
H
O
M
E
/
j
r
e
/
l
i
b
/
r
t
.
j
a
r
<
/
a
r
g
>
<
a
r
g
>
−
e
x
t
d
i
r
s
<
/
a
r
g
>
<
a
r
g
>
{env.JAVA_HOME}/jre/lib/rt.jar</arg> <arg>-extdirs</arg> <arg>
env.JAVAHOME/jre/lib/rt.jar</arg><arg>−extdirs</arg><arg>{project.basedir}/src/main/webapp/WEB-INF/lib
68、Ant&Makefile
Ant是一个将软件编译、测试、部署等步骤联系在一起加以自动化的一个工具。理论上来说,它有些类似于(Unix)C中的make,
但没有make的缺陷。Makefile也很可恶。任何使用过他们的人都碰到过可恶的tab问题。Ant的原作者经常这样问自己:“是否我的命令不执
行只是因为在我的tab前有一个空格?!!”当一个代码项目大了以后,每次重新编译,打包,测试等都会变得非常复杂而且重复,因此c
语言中有make脚本来帮助这些工作的批量完成。
70、Spring
谈谈Spring和Spring MVC的流程和事务;spring配置文件都写什么?
(1)spring提供两种管理事务的方式:一种是声明式事务,一种是编程式事务。
Spring的声明式事务管理,基于Spring的AOP,基于Spring AOP实现,几乎就是xml文件的配置,不再需要不停地写commit,rollback,
(但Spring仍然没有放弃编程式的事务管理策略。
Spring的编程式事务管理,统一的事务编码风格,几乎是一个模板化的。
为我们提供了一个TransactionTemplate,使用回调机制,将应用代码从样板式的资源获取和释放代码中解放出来,不再有大量的try/catch
finally/try/catch代码块。
(2)springMVC的流程和事务:动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的反射 ,反射其实就是在
运行时动态的去创建、调用对象,Spring就是在运行时,跟xml Spring的配置 文件来动态的创建对象,和调用对象里的方法的 。
(3)spring的配置文件:一、引用外部属性文件;二、常用数据源的配置;三、配置事务管理器;四、context:component-scan
;五、aop注解支持;六、缓存配置;七、<!-- Spring、MyBatis的整合,
需要在 Spring 应用上下文中定义至少两样东西:一个SqlSessionFactory和至少一个数据映射器类(UserMapper->iocContext.xml)。
aop用途:日志记录、权限判断、异常处理 不用再有大量的try/catch/finally/try/catch代码块
Spring 框架中都用到了哪些设计模式?
Spring框架中使用到了大量的设计模式,下面列举了比较有代表性的:
代理模式—在AOP和remoting中被用的比较多。
单例模式—在spring配置文件中定义的bean默认为单例模式。
模板方法—用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
前端控制器—Spring提供了DispatcherServlet来对请求进行分发。
视图帮助(ViewHelper )—Spring提供了一系列的JSP标签,高效宏来辅助将分散的代码整合在视图里。
依赖注入—贯穿于BeanFactory / ApplicationContext接口的核心理念。
工厂模式—BeanFactory用来创建对象的实例。
72、jsp页面9个隐含对象
(1) request: 转载链接:HttpServletRequest的一个对象;
(2) response: 转载链接:HttpServletResponse的一个对象;(页面中几乎不用)
(3) pageContext: 页面的上下文,是PageContext的一个对象,可以从中获取其他8个隐含对象,也可以从中获取当前页面的其他信息(可参考如下API中PageContext对象的方法);(自定义标签时使用)
(4) session: 代表游览器和服务器的一次会话,是转载链接:HttpSession的一个对象;
(5) application: 代表当前web应用,是ServletContext的一个对象;
(6) config: 当前jsp对应的servlet的ServletConfig对象,需要访问当前jsp配置的初始化参数(如下);(几乎不使用)
(7) out: JspWriter的一个对象,调用out.println()可以直接将字符串打印到游览器上;
(8) page: 指向当前JSP对应的Servlet对象的引用,但为Object类型,只能调用Object对象的方法;(几乎不使用)
(9) exception:在声明了page指令的isErrorPage="true"时才可以使用(如下);
73.1、binlog 、redo log
prv:server/bin redo-innodb
1. binlog是MySQL Server层记录的日志, redo log是InnoDB存储引擎层的日志。 两者都是记录了某些操作的日志(不是所有)自然有些重
复(但两者记录的格式不同)。
2. 选择binlog日志作为replication我想主要原因是MySQL的特点就是支持多存储引擎,为了兼容绝大部分引擎来支持复制这个特性,
那么自然要采用MySQL Server自己记录的日志而不是仅仅针对InnoDB的redo log,因为如果采用了InnoDB redo log复制,那么其他引擎
也想复制,此时改怎么办呢?对吧
binlog属于逻辑日志,是逻辑操作。innodb redo属于物理日志,是物理变更。
逻辑日志有个缺点是难以并行,而物理日志可以比较好的并行操作,所以redo复制还是有优势的,也许5.7能搞出来。
74、mysql&oracle字段识别的区别
oracle转成mysql时: varchar2(10)可以转成varchar(10) number则要看oracle中存储的具体是什么类型的数据:
1、如果是整型,那么mysql中,用int即可; 2、如果是带小数位的,那么mysql中可用numeric类型
oracle:varchar2 number
mysql :varchar int
oracle自增是要单独建序列,mysql建表可以直接指定自增方式
隔离级别oracle读提交,mysql重复读
75、javaIO
下面是IO中输入字节流的继承图
InputStream
o ByteArrayInputStream
o FileInputStream
o FilterInputStream
o BufferedInputStream
o DataInputStream
o LineNumberInputStream
o PushbackInputStream
o ObjectInputStream
o PipedInputStream
o SequenceInputStream
o StringBufferInputStream
下面是IO中输出字节流的继承图。
OutputStream
ByteArrayOutputStream
FileOutputStream
FilterOutputStream
BufferedOutputStream
DataOutputStream
PrintStream
ObjectOutputStream
PipedOutputStream
下面是IO中输入字符流的继承图。
Reader
BufferedReader
LineNumberReader
CharArrayReader
FilterReader
PushbackReader
InputStreamReader
FileReader
PipedReader
StringReader
下面是IO中输出字符流的继承图。
Writer
BufferedWriter
CharArrayWriter
FilterWriter
OutputStreamWriter
FileWriter
PipedWriter
PrintWriter
StringWriter
77、servlet 用到了什么模式
是基于摸板设计模式 如果人为的覆盖service ,必须要显示调用super 否则无效
将工作流程进行封装,并且对外提供了个性化的控制,但主流程外界不能修改,也就是说,
模版方法模式中,将工作的主体架构规定好,具体类可以根据自己的需要,各自去实现
79、spring启动方式
spring有三种启动方式,使用ContextLoaderServlet,ContextLoaderListener和ContextLoaderPlugIn
spring3.0及以后版本中已经删除ContextLoaderServlet 和Log4jConfigServlet
可以采用余下两种启动方式ContextLoaderListener和ContextLoaderPlugIn
建议使用ContextLoaderListener
N0:1
[java] view plain copy
org.springframework.web.context.ContextLoaderListener
contextConfigLocation
/WEB-INF/applicationContext.xml
80、load-on-startup
在servlet的配置当中,5的含义是:
标记容器是否在启动的时候就加载这个servlet。
当值为0或者大于0时,表示容器在应用启动时就加载这个servlet;
当是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载。
正数的值越小,启动该servlet的优先级越高。
个人:有点像sb中的
@Component 组成
@Order(value=2) @CommandLineRunner
81、Collection Collections
Collections java.util类包含各种关集合操作静态
Collection java.util接口各种集合结构父接口
List, Set继承自Collection接口
Collections类常用方法总结 转载链接:http://www.cnblogs.com/Eason-S/p/5786066.html 1. sort 对集合进行排序 1 public static <T extends Comparable<? super T>> void sort(List<T> list) 3 public static <T> void sort(List<T> list,Comparator<? super T> c) 在使用List时想根据List中存储对象的某一字段进行排序,那么我们要用到Collections.sort方法对list排序,用Collections.sort方法对list排序有两种方法: 第一种是list中的对象实现Comparable接口; 第二种方法是根据Collections.sort重载方法来实现。 2. shuffle 对集合进行随机排序 1 public static void shuffle(List<?> list) 3 public static void shuffle(List<?> list, Random rnd) 示例: 3. binarySearch 查找指定集合中的元素,返回所查找元素的索引 复制代码 1 public static <T> int binarySearch(List<? extends Comparable<? super T>> list,T key) 4 public static <T> int binarySearch(List<? extends T> list, T key,Comparator<? super T> c) 10 int m = Collections.binarySearch(c, "o"); 注意:若查找的元素不存在,示例中的n即表示该元素最有可能存在的位置的索引。 4. max 1 public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) 3 public static <T> T max(Collection<? extends T> coll,Comparator<? super T> comp) 前者采用Collection内含自然比较法,后者采用Comparator进行比较. 5. min 1 public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll) 3 public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp) 前者采用Collection内含自然比较法,后者采用Comparator进行比较。 6. indexOfSubList 查找subList在list中首次出现位置的索引 1 public static int indexOfSubList(List<?> source, List<?> target) 1 public class Practice { 2 public static void main(String[] args){ 3 List list = Arrays.asList("one two three four five six siven".split(" ")); 4 System.out.println(list); 5 List subList = Arrays.asList("three four five six".split(" ")); 6 System.out.println(Collections.indexOfSubList(list, subList)); } } 复制代码 运行结果为:[one, two, three, four, five, six, siven] 7. lastIndexOfSubList 使用与上例方法的使用相同,在此就不做介绍了。 8. replaceAll 替换批定元素为某元素,若要替换的值存在刚返回true,反之返回false 1 public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal) 9. reverse() 反转集合中元素的顺序 public static void reverse(List<?> list) 10. rotate 集合中的元素向后移m个位置,在后面被遮盖的元素循环到前面来 1 public static void rotate(List<?> list,int distance) 2 public static void main(String[] args){ 3 List list = Arrays.asList("one two three four five six siven".split(" ")); 4 System.out.println(list); 5 Collections.rotate(list, 1); 6 System.out.println(list); [one, two, three, four, five, six, siven] [siven, one, two, three, four, five, six] 11. copy 将集合n中的元素全部复制到m中,并且覆盖相应索引的元素 1 public static <T> void copy(List<? super T> dest, 2 List<? extends T> src) 3 List m = Arrays.asList("one two three four five six siven".split(" ")); 4 System.out.println(m); 5 List n = Arrays.asList("我 是 复制过来的哈".split(" ")); 6 System.out.println(n); 7 Collections.copy(m,n); 8 System.out.println(m); [one, two, three, four, five, six, siven] [我, 是, 复制过来的哈] [我, 是, 复制过来的哈, four, five, six, siven] 12. swap 交换集合中指定元素索引的位置 1 public static void swap(List<?> list, 2 int i, 3 int j) 13. fill 用对象o替换集合list中的所有元素 1 public static <T> void fill(List<? super T> list, 2 T obj) 3 List m = Arrays.asList("one two three four five six siven".split(" ")); 4 System.out.println(m); 5 Collections.fill(m, "haha52T25xixi"); 6 System.out.println(m); [one, two, three, four, five, six, siven] [haha52T25xixi, haha52T25xixi, haha52T25xixi, haha52T25xixi, haha52T25xixi, haha52T25xixi, haha52T25xixi] 14. nCopies 返回大小为n的List,List不可改变,其中的所有引用都指向o 1 public static <T> List<T> nCopies(int n, 2 T o) 3 System.out.println(Collections.nCopies(5, "haha")); [haha, haha, haha, haha, haha] java基础——Collections.sort的两种用法 转载链接:https://www.cnblogs.com/yw0219/p/7222108.html?utm_source=itdadao&utm_medium=referral Collections是一个工具类,sort是其中的静态方法,是用来对List类型进行排序的,它有两种参数形式: public static <T extends Comparable<? super T>> void sort(List<T> list) { list.sort(null); } public static <T> void sort(List<T> list, Comparator<? super T> c) { list.sort(c); } 首先使用基本类型(此处使用Integer)来演示第一个方法: static List<Integer> intList = Arrays.asList(2, 3, 1); Collections.sort(intList); 可以看到,默认的排序是正序,那么如何实现逆序呢,这就要使用第二种方式了,即通过实现Comparator接口的compare方法来完成自定义排序,代码如下: Collections.sort(intList,new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { // 返回值为int类型,大于0表示正序,小于0表示逆序 return o2-o1; } }); PrintUtil.showList(intList);} 可以看到,已经实现了逆序的排序了。 接下来看看自定义类的排序: public class Emp{ private int empno; private String ename;//省略getset} static List<Emp> empList; static { Emp emp1 = new Emp(2,"Guan YunChang"); Emp emp2 = new Emp(3,"Zhang Fei"); Emp emp3 = new Emp(1,"Liu Bei"); empList = Arrays.asList(emp1,emp2,emp3);} The method sort(List<T>) in the type Collections is not applicable for the arguments (List<Emp>) 意思是参数类型为List<Emp>时,sort方法无法执行,原因是泛型没有继承Comparable接口,这种方式稍后再说,我们先使用sort方法的第二种形式: Collections.sort(empList,new Comparator<Emp>() { @Override public int compare(Emp o1, Emp o2) { /*按员工编号正序排序*/ return o1.getEmpno()-o2.getEmpno(); /*按员工编号逆序排序*/ //return o2.getEmpno()-o1.getEmpno(); /*按员工姓名正序排序*/ //return o1.getEname().compareTo(o2.getEname()); /*按员工姓名逆序排序*/ //return o2.getEname().compareTo(o1.getEname()); }}); PrintUtil.showList(empList);} 接下来看看第一种形式的实现,首先让Emp类继承Comparable接口并重写compareTo方法(为了和上面的排序方式区别开,此次按照员工姓名逆序排列): public class Emp implements Comparable<Emp>{ /*属性、getter/setter方法、toString方法及构造方法略*/ @Override public int compareTo(Emp emp) { /*按员工编号正序排序*/ //return this.getEmpno()-emp.getEmpno(); /*按员工编号逆序排序*/ //return emp.getEmpno()-this.getEmpno(); /*按员工姓名正序排序*/ //return this.getEname().compareTo(emp.getEname()); /*按员工姓名逆序排序*/ return emp.getEname().compareTo(this.getEname()); }} 使用Collections.sor方法的第一种形式实现: Collections.sort(empList); 总结: 1.对于String或Integer这些已经实现Comparable接口的类来说,可以直接使用Collections.sort方法传入list参数来实现默认方式(正序)排序; 2.如果不想使用默认方式(正序)排序,可以通过Collections.sort传入第二个参数类型为Comparator来自定义排序规则; 3.对于自定义类型(如本例子中的Emp),如果想使用Collections.sort的方式一进行排序,可以通过实现Comparable接口的compareTo方法来进行,如果不实现,则参考第2点; 4.jdk1.8的Comparator接口有很多新增方法,其中有个reversed()方法比较实用,是用来切换正序和逆序的,代码如下: Collections.sort(empList,comparator.reversed()); 复写的compare方法定义的是按员工编号正序排序,在使用reversed翻转后结果如下:
83、单例模式两个特性:出口唯一,实例唯一 对外接口只有一个,实例只new一次,隐约记得是这样
85、转载链接:http协议(三)几种数据传输方式
转载链接:https://www.cnblogs.com/imyalost/p/5630940.html
说说转载链接:http协议的一些特点:
1)无状态
转载链接:http协议是一种自身不对请求和响应之间的通信状态进行保存的协议,即无状态协议。
这种设置的好处是:更快的处理更多的请求事务,确保协议的可伸缩性
不过随着web的不断发展,有时候,需要将这种状态进行保持,随即,就引入了cookie技术,cookie技术通过在请求和响应报文中写入cookie信息来控制客户端的状态。
有关cookie的内容后面我们再说。。。
2)持久性
正常在发送转载链接:http时,都需要建立TCP的连接,再发送报文。
如果每次想要发送转载链接:http报文都需要经过这个过程,那么时间大部分都会消耗在建立和断开连接的过程中。
因此转载链接:http中使用了connection属性,用于指定连接的方式。
当设置成keep-alive,转载链接:http就会建立一条持久化的连接,不需要每次都建立连接,再中断。
这样做的好处是:减轻了服务器端的负载,减少开销的那部分时间,使转载链接:http请求和响应都能更快的结束,相应的,web页面显示速度也就相对提升了。
3)管线化
如果一个转载链接:http请求,请求了大量的图片等大文件,那么其他的转载链接:http请求怎么办呢?
现在,管线化技术的出现,使得转载链接:http请求比持久性连接更要快;特点在于:请求数越多,时间差越明显。
4)内容编码
由于某些报文的内容过大,因此在传输时,为了减少传输的时间,会采取一些压缩的措施。
例如上面的报文信息中,Accept-Encoding就定义了内容编码的格式:gzip
有下面几种方式:
gzip:GNU压缩格式
compress:UNIX系统的标准压缩格式
deflate:是一种同时使用了LZ77和哈弗曼编码的无损压缩格式
identity:不进行压缩
5)多部分对象集合
有的时候传输的内容,不仅仅是一些字符串,还有可能是一些图片,字符,音乐二进制等混杂的内容。
这就需要使用多部分对象集合,multipart,例如在使用java编写web上传文件的代码时,需要在form中指定form的编码格式。
设置form的enctype属性的值为multipart/form-data。
这是因为默认的情况下form使用的编码格式是:applicatin/x-www-form-urlencoded,这种编码格式会把所有的内容进行编码,不适合上传文件这种情况。
这两种编码格式的区别主要是:
multipart/form-data 会以控件为基准,编码form中的内容。
application/x-www-form-urlencoded 会把form中的内容编码成键值对的形式。
6)范围请求
有些场景下,转载链接:http报文请求一些很大的图片,但是加载过程很慢。
比如我们登录一些大图片的网址,会发现有时候图片是一块一块加载的。
这就是因为设置了转载链接:http请求的长度,这样就可以分块的加载资源文件。
在请求报文中使用Range属性,在响应报文中使用Content-Type属性都可以指定一定字节范围的转载链接:http请求。
接下来,说说几种转载链接:http协议的数据传输方式
转载链接:http协议的传输方式有很多种,处于安全考虑,常用的一般都是GET和POST两种,先来介绍下这两种
1)GET:获取资源
GET方法用来请求访问已被URL识别的资源
2)POST:传输实体主体
POST方法用来请求服务器传输信息实体的主体
GET和POST的区别:
首先,使用目标不同:GET方法只是用来查询,不会对浏览器上的信息产生影响,每次GET的方法都是相同的
其次,大小不同:GET是放在URL首部,因此大小随着浏览器而定,而POST则是在报文中,只要没有具体限制,文件的大小是没限制的
然后,安全性不同:GET采用的是明文传输,而POST是放在报文内部,无法看到
从使用场景的角度来说,一般像用户注册登录这种信息都是私密的,采用POST,而针对查询等,为了快速,大多采用GET传输。
(关于关于GET和POST的区别,最近重新看了很多别人写的博客啊资料什么的,发现上面的解释比较模糊,我就在下面的评论区里面将区别清晰的描述一下,当然,后面的博客也会详细的解释)
接下来介绍其他几种数据传输方式:
3)PUT:传输文件
PUT要求在请求报文的主体中包含文件内容,然后保存到请求URL指定的位置
处于安全考虑,一般web网站不使用此方法,若配合web的安全验证机制,或者架构采用REST标准的网站,就可能开放使用此方法
4)HEAD:获得报文首部
HEAD和GET方法一样,只不过不返回报文主体部分,用于确认URI的有效性及资源更新的日期时间等
DELETE是与PUT相反的方法,是按请求URI删除指定的资源
处于安全考虑,一般web网站不使用此方法,若配合web的安全验证机制,或者架构采用REST标准的网站,就可能开放使用此方法
6)OPTIONS:询问支持的方法
用来查询针对请求URI指定的资源支持的方法
7)TRACE:追踪路径
是让web服务器端将之前的请求通信还回给客户端的方法
发送请求时,在Max-Frowards首部字段中填入数值,每经过一个服务器端就-1,当数值为0时,停止传输,最后收到服务器返回状态码200 OK的响应
但是,这种方法基本很少使用,而且很容易引起XST(跨站追踪)攻击,就更不会用到了。
8)CONNECT:要求采用隧道协议连接代理
该方法要求在于代理服务器通信时建立隧道,实现用隧道协议进行TCP通信,主要使用SSL(安全套接层)和TLS(传输层安全)协议把通信内容加密后经过网络传输。
最后,附上一张转载链接:http1.1和转载链接:http1.0版本各自支持的方法,另外,注意用大写。。。。。。
其中,LINK和UNLINK已被转载链接:HTTP1.1废弃,不再支持!
86、linux上装tomcat
转载链接:https://blog.csdn.net/yerenyuan_pku/article/details/72635908?locationNum=13&fps=1
tar -xvf apache-tomcat-7.0.57.tar.gz -C /usr/local/tomcat命令将root目录下的apache-tomcat-7.0.57.tar.gz文件解压到/usr/local/tomcat目录下
需要把它的防火墙设置一下,让它对tomcat的8080端口号放行。
/sbin/iptables -I INPUT -p tcp --dport 8080 -j ACCEPT
/etc/rc.d/init.d/iptables save 命令是将这个设置永久地保存到Linux的防火墙中
安装jdk
1. 登录Linux,切换到root用户
su root 获取root用户权限,当前工作目录不变(需要root密码)
或sudo -i 不需要root密码直接切换成root(需要当前用户密码)
2. 在usr目录下建立java安装目录
cd /usr
mkdir java
3.将jdk-8u60-linux-x64.tar.gz拷贝到java目录下
cp /mnt/hgfs/linux/jdk-8u60-linux-x64.tar.gz /usr/java/
4.解压jdk到当前目录
tar -zxvf jdk-8u60-linux-x64.tar.gz
得到文件夹 jdk1.8.0_60
个人:最后修改tomcat配置文件catlina.sh里面的环境变量
87、
线程会不会把本地的内存里的东西比如那些地市列表静态数据拉到线程的内存里面,是不是每个
线程都会copy一份过去。 个人暂时理解:应该有线程内存,只是复制一份数据到线程中,不会影响源数据
方法区、堆都是线程共享,栈就算不是线程共享也不安全的。所以应该是copy一份到线程内,但是要更新的话应该是跟方法区做数据交换(乐观锁)
91、系统设计的两个重大问题.
第一条要满足未来的业务需求的不断变化和增加. 也就是可扩展性.
第二条要满足性能的可伸缩性. 也就是可集群性…通过增加机器能处理更多的请求
第三条要解耦合. 如果不解耦合, 未来业务增加或变更的时候你还在修改3年前写的代码.试问你有多大的把握保证升级好系统不出问题? 如何可以
写新的代码而不用修改老代码所带来的好处谁都知道…
第四条简单易懂.
2、进程&线程 进程三种状态:就绪、执行、阻塞 线程四种状态:运行、就绪、挂起、结束 sleep waite start run 是线程的 win32环境中线程有3中基本模式:单线程、单元线程、自有线程 6、synchronized synchronized锁的是对象或者类,只要不访问同一个对象,其他线程还是可以访问同一个方法。 每个对象只有一个锁(Lock)与之关联 实现同步会是以很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。 public class Test{ public static void main(String[] args){ SellThread sell = new SellThread(); Tread sell1 = new Thread(sell,"sellname1"); Tread sell2 = new Thread(sell,"sellname2"); Tread sell3 = new Thread(sell,"sellname3"); sell1.start(); sell2.start(); sell3.start(); } } class SellThread implement Runnable{ private int i = 20; String a = "now ok"; public void run(){ while(true){ synchronized(a){ if(i>0){ try{ Thread.sleep(100); }catch(Exception e){ } System.out.println(Thread.currentThread.getName()+" sell "+i--); } } } } } synchronized()括号中需要的是一个class对象,所以不能直接在括号中写上i,于是这里定义了一个String 对象a。a可以认为是一个标志位,a标志位默认任何人都能使用,这样售票员sellman1的卖票线程拿到了a以后 就开始卖票了,并且把a这个对象标志位置为不可用。然后其他线程发现他们拿不到a这个对象,就只能先搁置了。 一直到sellman1的卖票线程释放了a,a的标志位就又变成可用。不过a喝卖票没什么关系,所以我们用this来代替 synchronized()中的a,它和a的效果一样表示谁拿到了this对象才能执行。 两个容易误解的地方 (1)、一个线程拿到synchronized括号中的对象之后,其他也需要拿到这个对象才能运行的线程不能被执行了。 其实其他线程也是可以执行的,但他们执行到了需要synchronized中对象的时候,发现对象的标志位不可用, 只能又被搁置了,所以syn是以牺牲效率为代价的。 (2)、一个线程拿到syn括号中的对象之后,其他任何线程都不能执行了,假如其他不需要syn的对象才能继续 执行的线程,还是可以和拿到syn括号中的对象的线程一起运行的。
91、实例变量&局部变量
实例变量保存在所属的对象中,位于堆上
java实例变量怎样都会有默认值,局部变量没有默认值,如果变量在被初始前就被调用,会出现编译错误
92、继承:
定义:被设计代表共同状态和行为的类。在行为程序被多个相同基本类型类所共享时。
作用:如果有共同的部分需要修改,就只需要修改一个地方。
用继承来防止子类出现重复的代码
通过继承来定义相关类间的共同协议,
通过多态就可以编写出引进新型子类时也不必修改的程序
如果没有办法看到类的源程序代码,但又想改变该类的方法,是否可以用子类的方式来做呢,用你自己设计好的代码覆盖掉它们的方法。
prv:就跟建立同个路径下的同名类一样可以直接覆盖掉jar包中的类。
多态:通过声明为父类型的对象引用来引用它的子型对象
Dog dog = new Dog();
Animal mydog = new Dog();//这两者的类型不相同,引用变量的类型被声明为Animal,但对象是Dog
在多态下,引用与对象可以是不同类型
运用多态时,引用类型可以是实际对象类型的父类,这样子你就可以做出多态数组这一类东西
Animal []animals = new Aniamls[5];
animals[0] = new Dog();
animals[0] = new Cat();
animals[0] = new Wolf();
animals[0] = new Hippo();
animals[0] = new Lion();
for(int i=0;i<animals.length;i++){
animals[i].eat();//这就是多态最强的地方,你可以将数组的元素逐个调出来当animal来操作,可以调dog的eat(),cat的roam()
}
class Vet{
public void giveShot(Animal A){
a.makeNoise();
}
}//参数可以用任何Animal的类型对象来传入,不管它引用的对象到底是什么,该对象都会执行makeNoise()
prv:跟设计模式一样,传入一个大类型的多个子类型对象,由子类型对象来决定行为或指引一段逻辑。
特性:子类会继承所有父类的public属性和方法,但不会继承父类所有private的属性和方法
当某个方法在子类被覆盖过,调用这个方法时会调用覆盖过的版本
防继承:有3个方法可以防止一个类被继承
1、存取控制,虽然类不能被标记为私有,但是还是可以不标记为公有,非公有的类只能被同一个包的类继承
2、final修饰符,表示它是继承树的末端,不能被继承
3、让类只拥有private的构造函数
一般来说你不会标记出final,但如果你需要安全-确保方法都是你写的版本,此时就需要final
93、docker、eureka
docker其实相当于在虚拟机里面启动了一个小的虚拟机,然后在小虚拟机里面跑程序服务。当然是虚拟机就有指定的ip跟端口
eureka会读取程序里面yml配置的一个ip地址跟端口,向eureka注册一个小虚拟机的ip地址,但是不特定设置这个ip地址的话一般这个地址都会是
127.0.0.1,所以貌似要在yml里面设定大虚拟机的ip地址跟端口;当外部访问服务时,eureka会指向配置的ip,如果eureka跟程序所处的大
虚拟机不在同一个服务下,直接去找127.0.0.1就找不到服务,所以如果配置了大虚拟机的ip,eureka就能找到大虚拟机,然后根据端口来找到
对应的docker。
docker run ip 端口1-端口2 就是将ip 端口1指向ip端口2。docker是个小虚拟机,当没有jenkins时,重启就需要再启动一个docker服务,然后
把旧的docker服务干掉。
rabbitMQ:消息队列,spring的配置信息可以抽离出来,然后需要更新的时候由rabbitMQ推向docker,docker不用重新打包,貌似需要重启。
95、RPC AMQP
prv:分布式用的是rpc,springcloud用的是restful
远程过程调用、Remote Procedure Calls 、远程通信机制
高级消息队列协议 、Advanced Message Queuing Protocol,跟转载链接:HTTP协议一样最后都有个P Protocol,都是协议的一种,只是它是基于rpc来的。
96、session共享
session共享可以通过spring框架结合redis设置,在spring里面配置就好了,redis单机或者redis-cluster都可以配置。根据
spring-data-session-redis配置,还有过滤器就可以将session转换存储到redis。方便单点登录还有集群的session共享问题
待看:-- 转载链接:https://www.cnblogs.com/aflyun/p/8532210.html
百度搜索 spring 配置 session 共享 阿飞往下
97、sessionid
session是在访问tomcat的转载链接:HttpServletRequest的getSession()的时候创建的,随机数+时间+jvmid,在创建session同时,服务器会为该
session创建唯一的sessionid
98、基础
虚拟机内存只是个概念,你用了2g才算真正占用了多少,分配的20g只是个概念,别人要用还是有18g
空引用就是让对象失效,当你把对象引用设为null对象就失效了
DateUtils.pattern 或者add 可以用这个来编辑日期,好过用simpledateformart
100、多继承或多实现
多继承会导致致命方块的问题,子类不知道使用哪个父类的方法,所以不能
多实现,如果两个接口中有重名的方法,ide首先就会报错,
解决这个方法:实现类里写个内部类,分别实现两个接口
java规范里,方法名+参数 唯一确定一个方法(不含返回值类型)
jdk1.8接口可以自定义默认实现的方法,如果实现两个接口中有同样的名字,必须要指定覆盖哪一个方法
101、构造函数
编译器一定会帮你写出没有参数的构造函数吗?
没有的事,编译器只会在你完全没有设定构造函数时才会调用
如果已经写了一个有参数的构造函数,并且你需要一个没有参数的构造函数,则你必须自己手动写!
如果类上有一个以上的构造函数,则参数一定要不一样。(prv跟方法定义一样,需要方法名跟参数不同才算不同方法)
构造函数是个会在新建对象的时候执行的代码
构造函数必须与类同名并且没有返回类型
最好有无参数的构造函数让人可以选择使用默认值
小孩能在父母之前出生吗?父类构造函数必须在子类构造函数之前结束,
104、注解
类似接口:@Target表示该注解可以用于什么地方(CONSTRUCTOR:FIELD:LOCAL_VARIABLE、METHOD、PACKAGE:包声明
PARAMETER、TYPE)
@Retention表示需要在什么级别保存该注解信息。SOURCE:注解将被编译器丢弃、CLASS、RUNTIME:VM
转载链接:https://www.cnblogs.com/huajiezh/p/5263849.html
1、定义一个注解类: @Target @Retention 定义参数d
2、在调用过程类中定义一个入口,传入调用类,将类中的方法循环出来并操作方法上通过注解定义的具体参数
entry(Class c,other params){(for(Method m : c.getDeclaredMethods()){注解类A a = m.getAnnotation(A.class)} 取出参数a.d}
3、在目标类中使用注解,为注解加上具体参数
116、回调机制
转载链接:https://www.cnblogs.com/xrq730/p/6424471.html
类A的a()方法调用类B的b()方法
类B的b()方法执行完毕主动调用类A的callback()方法
119、回调
回调的思想是:
类A的a()方法调用类B的b()方法
类B的b()方法执行完毕主动调用类A的callback()方法
这样一种调用方式组成了上图,也就是一种双向的调用方式。
122、红黑树
红黑树 它一种特殊的二叉查找树。红黑树的每个节点上都有存储位表示节点的颜色,可以是红(Red)或黑(Black)。
左旋:想象轮盘的左旋,自然会把右边的给带上来变成父节点,右旋反之
1\节点是红色或黑色。
2\根是黑色。
3\所有叶子都是黑色(叶子是NIL节点)
4\每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)
5\从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。
prv:也就是-根黑、null黑、节点到叶子路径上的黑色节点数量相同、红黑节点交替、不行就左旋或者右旋变色
AVL在计算机科学中是最先发明的自平衡二叉查找树。
TreeMap就是基于红黑树实现的
124、spring注解
转载链接:https://mp.weixin.qq.com/s/nSIyS35N6KpnFCWdI43THA
@Service用于标注业务层组件,@Controller用于标注控制层组件(如struts中的action),@Repository用于标注数据访问组件,
即DAO组件,而@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
bean默认是单例的,如果想改变,可以使用@Service(“beanName”) @Scope(“prototype”)来改变
1.声明bean的注解
@Component 组件,没有明确的角色
@Service 在业务逻辑层使用(service层)
@Repository 在数据访问层使用(dao层)
@Controller 在展现层使用,控制器的声明(C)
最后发现是这样的:@repository跟@Service,@Compent,@Controller这4种注解是没什么本质区别,都是声明作用,取不同的名字只是为了更
好区分各自的功能.
@configuration
转载链接:https://blog.csdn.net/u012260707/article/details/52021265
prv:类似spring的xml配置的bean,针对外部引用的工具需要将他们配置成bean才能以注解来使用才能注解到
spring容器里。也可以用来将自定义的类加入bean容器。
@Repository
转载链接:https://blog.csdn.net/f45056231p/article/details/81676039
用来注解接口的,如果mybatis xml中配置了这个bean,就可以不用这个注解了,就像在mybatisPlus中配置了@MapperScan
@Configuration
@EnableTransactionManagement //开启事务
@MapperScan(“com.evergrande.eim.mapper”)
public class MybatisPlusConfigiration {
@AutoWired@Resource autowired默认按照byType,resource默认按照byName,resource有两个属性name/type,
定name找不到就抛异常,指定type找到多个也会抛异常。resource还可以为其他bean注入name,@Resource(name=“xxx”),
相当于为该属性注入一个名称为xxx的bean。 转载链接:https://www.cnblogs.com/zhangxj/p/3970608.html
autowired是spring的resource是jdk的
1.声明bean的注解 转载链接:https://mp.weixin.qq.com/s/nSIyS35N6KpnFCWdI43THA @Component 组件,没有明确的角色 @Service 在业务逻辑层使用(service层) @Repository 在数据访问层使用(dao层) @Controller 在展现层使用,控制器的声明(C) 2.注入bean的注解 @Autowired:由Spring提供 @Inject:由JSR-330提供 @Resource:由JSR-250提供 都可以注解在set方法和属性上,推荐注解在属性上(一目了然,少写代码)。 3.java配置类相关注解 @Configuration 声明当前类为配置类,相当于xml形式的Spring配置(类上) @Bean 注解在方法上,声明当前方法的返回值为一个bean,替代xml中的方式(方法上) @Configuration 声明当前类为配置类,其中内部组合了@Component注解,表明这个类是一个bean(类上) @ComponentScan 用于对Component进行扫描,相当于xml中的(类上) @WishlyConfiguration 为@Configuration与@ComponentScan的组合注解,可以替代这两个注解 4.切面(AOP)相关注解 Spring支持AspectJ的注解式切面编程。 @Aspect 声明一个切面(类上) 使用@After、@Before、@Around定义建言(advice),可直接将拦截规则(切点)作为参数。 @After 在方法执行之后执行(方法上) @Before 在方法执行之前执行(方法上) @Around 在方法执行之前与之后执行(方法上) @PointCut 声明切点 在java配置类中使用@EnableAspectJAutoProxy注解开启Spring对AspectJ代理的支持(类上) 5.@Bean的属性支持 @Scope 设置Spring容器如何新建Bean实例(方法上,得有@Bean) 其设置类型包括: Singleton (单例,一个Spring容器中只有一个bean实例,默认模式), Protetype (每次调用新建一个bean), Request (web项目中,给每个转载链接:http request新建一个bean), Session (web项目中,给每个转载链接:http session新建一个bean), GlobalSession(给每一个 global 转载链接:http session新建一个Bean实例) @StepScope 在Spring Batch中还有涉及 @PostConstruct 由JSR-250提供,在构造函数执行完之后执行,等价于xml配置文件中bean的initMethod @PreDestory 由JSR-250提供,在Bean销毁之前执行,等价于xml配置文件中bean的destroyMethod 6.@Value注解 @Value 为属性注入值(属性上) 7.环境切换 @Profile 通过设定Environment的ActiveProfiles来设定当前context需要使用的配置环境。(类或方法上) @Conditional Spring4中可以使用此注解定义条件话的bean,通过实现Condition接口,并重写matches方法,从而决定该bean是否被实例化。(方法上) 8.异步相关 @EnableAsync 配置类中,通过此注解开启对异步任务的支持,叙事性AsyncConfigurer接口(类上),点击这里了解使用详情。 @Async 在实际执行的bean方法使用该注解来申明其是一个异步任务(方法上或类上所有的方法都将异步,需要@EnableAsync开启异步任务) 9.定时任务相关 @EnableScheduling 在配置类上使用,开启计划任务的支持(类上) @Scheduled 来申明这是一个任务,包括cron,fixDelay,fixRate等类型(方法上,需先开启计划任务的支持) 10.@Enable*注解说明 这些注解主要用来开启对xxx的支持。 @EnableAspectJAutoProxy 开启对AspectJ自动代理的支持 @EnableAsync 开启异步方法的支持 @EnableScheduling 开启计划任务的支持 @EnableWebMvc 开启Web MVC的配置支持 @EnableConfigurationProperties 开启对@ConfigurationProperties注解配置Bean的支持 @EnableJpaRepositories 开启对SpringData JPA Repository的支持 @EnableTransactionManagement 开启注解式事务的支持 @EnableTransactionManagement 开启注解式事务的支持 @EnableCaching 开启注解式的缓存支持 11.测试相关注解 @RunWith 运行器,Spring中通常用于对JUnit的支持 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration 用来加载配置ApplicationContext,其中classes属性用来加载配置类 @ContextConfiguration(classes={TestConfig.class}) 12.SpringMVC相关注解 @EnableWebMvc 在配置类中开启Web MVC的配置支持,如一些ViewResolver或者MessageConverter等,若无此句,重写WebMvcConfigurerAdapter方法(用于对SpringMVC的配置)。 @Controller 声明该类为SpringMVC中的Controller @RequestMapping 用于映射Web请求,包括访问路径和参数(类或方法上) @ResponseBody 支持将返回值放在response内,而不是一个页面,通常用户返回json数据(返回值旁或方法上) @RequestBody 允许request的参数在request体中,而不是在直接连接在地址后面。(放在参数前) @PathVariable 用于接收路径参数,比如@RequestMapping(“/hello/{name}”)申明的路径,将注解放在参数中前,即可获取该值,通常作为Restful的接口实现方法。 @RestController 该注解为一个组合注解,相当于@Controller和@ResponseBody的组合,注解在类上,意味着,该Controller的所有方法都默认加上了@ResponseBody。 @ControllerAdvice 通过该注解,我们可以将对于控制器的全局配置放置在同一个位置,注解了@Controller的类的方法可使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上, 这对所有注解了 @RequestMapping的控制器内的方法有效。 @ExceptionHandler 用于全局处理控制器里的异常 @InitBinder 用来设置WebDataBinder,WebDataBinder用来自动绑定前台请求参数到Model中。 @ModelAttribute 本来的作用是绑定键值对到Model里,在@ControllerAdvice中是让全局的@RequestMapping都能获得在此处设置的键值对。
125、IO模式和IO多路复用
转载链接:https://www.cnblogs.com/zingp/p/6863170.html
1、用户空间&内核空间
32位寻址位4g(2的32位),最多划分最高的1g字节给内核作为内核空间防止用户改动,其他给各个进程使用
2、进程上下文切换(进程切换)
2.1、保存当前进程A的上下文(内核再次唤醒进程所需要的状态,由一些对象的值组成(程序计数器状态寄存器用户栈等))
2.2.切换页全局目录以安装一个新的地址空间
2.3.恢复进程B的上下文
3、进程的阻塞(期待的某些事情未发生,当进程进入阻塞时是不占cpu资源的)
4、文件描述符:指向文件的引用的抽象化概念
5、直接I/O和缓存I/O
缓存IO:数据都是从磁盘拷贝到-内存缓冲区-进程缓冲区-进程
直接IO:数据都是从磁盘拷贝到-内存缓冲区-进程
二、I/O模式
当一个read操作发生时,它会经历两个阶段1、等待数据准备2、将数据从内核拷贝到进程中
linux产生了五中网络模式的方案:
阻塞:(block)数据没准备好就等
非阻塞:(不block)数据没准备好就like返回一个error,用户收到一个error就又立刻发起read请求。prv这个时候多线程就有用了,
可以去解决别的线程的问题了,单个进程内多个线程可以轮流执行一小段
IO多路复用:(block):用户进程调用select,block进程,内核监视所有select负责的socket,任何一个socket数据准备好,
select就会返回,用户进程再调用read,将数据从内核拷贝到用户进程
信号驱动(一般不用)、
异步IO:不会阻塞进程,数据好了之后内核直接把数据写进用户进程,并发一个通知给用户
IO多路复用属于异步阻塞,prv多个线程异步(可以支持多个线程),进程block阻塞了。监听select()
操作,并立刻给线程回复,当内核处理完通知select有结果时,调用用户进程发起read请求,将数据读取回去。
128、区块链
每一台都是主机,只不过有个一管理者的身份,每次会广播消息,也是通过选举机制来选出管理者的,选举机制跟服务的响应时间有关系,
性能越好响应时间越快。
132、C/C++、JAVA、C#之间的关系和区别?
转载链接:https://blog.csdn.net/yuxiangaaaaa/article/details/77869079
其中C++则一般看作是对C语言的扩展
Java语言是一种完全的面向对象语言,虽然它的底层(运行时库)是用C语言开发的,可是并不依赖于C。
C#是微软开发的一种编程语言,语法类似Java,几乎就是从Java的翻版。
Java是c++的简化 Java:无可争辩地具有C++所有的精华
133、网络基础知识(一)半双工与全双工
半双工:收发不能同时进行(对讲机)。全双工:收发能同时进行(电话)
半双工:在半双工模式(half-duplex mode)下,通信双方都能収送和接收数据,但丌能同时进行。当一台设备収送时,另一台只能接收,反之亦然。对讲机是半双工系统的典型例子。
全双工:在全双工模式(full-duplex mode)下,通信双方都能同时接收和収送数据。电话网络是典型的全双工例子。
以太网上的通信模式包括半双工和全双工两种:半双工模式下,共享物理介质的通信双方必须采用CSMA/CD机制来避免冲突。例如,10BASE5以太网的通信模式就必须是半双工模式。
全双工模式下,通信双方可以同时实现双向通信,这种模式不会产生冲突,因此不需要使用CSMA/CD机制。例如,10BASE-T以太网的通信模式就可以是全双工模式。
134、SMTP、POP3和IMAP之间的区别和联系
转载链接:https://blog.csdn.net/qq877507054/article/details/71249272
SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议
POP(Post Office Protocol)邮局通讯协定
IMAP全称是Internet Mail Access Protocol,即交互式邮件存取协议
简单地说,SMTP管‘发’,POP3/IMAP管‘收’。
POP3协议允许电子邮件客户端下载服务器上的邮件,但是在客户端的操作(如移动邮件、标记已读等),不会反馈到服务器上,比如通过客户端收取了邮箱中的3封邮件并移动到其他文件夹,邮箱服务器上的这些邮件是没有同时被移动的 。
而IMAP提供webmail 与电子邮件客户端之间的双向通信,客户端的操作都会反馈到服务器上,对邮件进行的操作,服务器上的邮件也会做相应的动作。
136、springcloud
springcloud是一个微服务框架,相比dubbo等RPC框架,sc提供了一个全套的分布式系统解决方案。
Spring Cloud对微服务基础框架Netflix的多个开源组件进行了封装,同时又实现了和云端平台以及和Spring Boot开发框架的集成。
Spring Cloud为微服务架构开发涉及的配置管理,服务治理,熔断机制,智能路由,微代理,控制总线,一次性token,全局一致性锁,leader选举,分布式session,集群状态管理等操作提供了一种简单的开发方式。
Spring Cloud 为开发者提供了快速构建分布式系统的工具,开发者可以快速的启动服务或构建应用、同时能够快速和云平台资源进行对接
138、聊聊QPS/TPS/并发量/系统吞吐量的概念
转载链接:https://blog.csdn.net/cainiao_user/article/details/77146049
QPS: 每秒钟处理完请求的次数
TPS:每秒钟处理完的事务次数
139、jetty&tomcat
架构上jetty简单,
tomcat:适用于处理少数繁忙的连接上,也就是说连接生命周期如果短,tomcat的总体性能更高。采用BIO,处理静态资源时性能较差
jetty:可以同时处理大量连接而且可以长时间保持这些连接。使用NIO处理IO请求上更占优势
Jetty是一个Web服务器(转载链接:HTTP),与Tomcat等类似,但比大多数servlet容器更轻。这更接近传统的Java服务器应用程序(servlet,WAR文件)的方式。像Netty一样,它足够轻量级以嵌入到Java应用程序中。
Netty是一款NIO客户端服务器框架,可以快速轻松地开发协议服务器和客户端等网络应用程序。它极大地简化并简化了TCP和UDP套接字服务器等网络编程。因此Netty专注于帮助编写NIO /非阻塞异步网络程序。
Jetty是一个轻量级的servlet容器,易于嵌入到Java应用程序中,还有一个易于使用的jetty客户端。
Netty是一个异步事件驱动的网络应用框架。例如,您可以在Netty框架的帮助下编写自己的servlet容器或转载链接:http客户端应用程序。
jetty 8和Apache Tomcat 7支持servlet 3.0规范,但netty不支持。因为它不是一个servlet容器。
140、arraylist&linkedlist
在随机查询上arraylist快,linkedlist慢,时间复杂度上
在空间复杂度上,arraylist为了添加新元素不用对数组进行重新分配,定义了多余的空间造成空间浪费。linkedlist将上一个元素跟下一个元素存储为entity键值对,这也导致了很大的空间开销
ArrayList 是线性表(数组)
get() 直接读取第几个下标,复杂度 O(1)
add(E) 添加元素,直接在后面添加,复杂度O(1)
add(index, E) 添加元素,在第几个元素后面插入,后面的元素需要向后移动,复杂度O(n)
remove()删除元素,后面的元素需要逐个移动,复杂度O(n)
LinkedList 是链表的操作
get() 获取第几个元素,依次遍历,复杂度O(n)
add(E) 添加到末尾,复杂度O(1)
add(index, E) 添加第几个元素后,需要先查找到第几个元素,直接指针指向操作,复杂度O(n)
remove()删除元素,直接指针指向操作,复杂度O(1)
141、安卓应用赚钱项目(这个人的其他博客也都可以看看)
转载链接:https://www.cnblogs.com/aspirant/p/5350387.html
144、ThreadLocal(线程变量副本)
空间换时间,数据库读写分离的时候用到,当线程使用的数据不与其他线程冲突的时候更没影响。
synchronize:时间换空间,阻塞
ThreadLocal是什么呢。
每一个ThreadLocal能够放一个线程级别的变量,可是它本身能够被多个线程共享使用,并且又能够达到线程安全的目的,且绝对线程安全。
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。
所以,在Java中编写线程局部变量的代码相对来说要笨拙一些,因此造成线程局部变量没有在Java开发者中得到很好的普及。
可用于放置数据库连接给各个线程共享使用
155、equals、hashcode
hashcode默认比较的是object的全属性,
如果两个对象,出于业务考虑,他们个别属性相等就认为他们相等了,那么就要重写hashcode,hashcode跟着equals,不然如果这两
个“相等”的对象放hashmap中,他们就放不到同一个地方了。
156、锁
转载链接:https://www.cnblogs.com/aspirant/p/6930436.html
1.可重入锁
基于线程的。定义:重进入是指任意线程在获取到锁之后,再次获取该锁而不会被该锁所阻塞。关联一个线程持有者+计数器,重入意味着锁操作的颗粒度为“线程”。
需要解决两个问题:
线程再次获取锁:锁需要识别获取锁的现场是否为当前占据锁的线程,如果是,则再次成功获取;
锁的最终释放:线程重复n次获取锁,随后在第n次释放该锁后,其他线程能够获取该锁。要求对锁对于获取进行次数的自增,计数器对当前锁被重复获取的次数进行统计,当锁被释放的时候,计数器自减,当计数器值为0时,表示锁成功释放。
重入锁实现重入性:每个锁关联一个线程持有者和计数器,
2.可中断锁
在Java中,synchronized就不是可中断锁,而Lock是可中断锁。
3.公平锁
公平锁即尽量以请求锁的顺序来获取锁
4.读写锁
读写锁将对一个资源(比如文件)的访问分成了2个锁,一个读锁和一个写锁。
正因为有了读写锁,才使得多个线程之间的读操作不会发生冲突。
ReadWriteLock就是读写锁,它是一个接口,ReentrantReadWriteLock实现了这个接口。
可以通过readLock()获取读锁,通过writeLock()获取写锁。
5、自旋锁
首先是一种锁,与互斥锁相似,基本作用是用于线程(进程)之间的同步。与普通锁不同的是,一个线程A在获得普通锁后,如果再有线程B试图获取锁,那么这个线程B将会挂起(阻塞);试想下,如果两个线程资源竞争不是特别激烈,而处理器阻塞一个线程引起的线程上下文的切换的代价高于等待资源的代价的时候(锁的已保持者保持锁时间比较短),那么线程B可以不放弃CPU时间片,而是在“原地”忙等,直到锁的持有者释放了该锁,这就是自旋锁的原理,可见自旋锁是一种非阻塞锁。
二、自旋锁可能引起的问题:
1.过多占据CPU时间:如果锁的当前持有者长时间不释放该锁,那么等待者将长时间的占据cpu时间片,导致CPU资源的浪费,因此可以设定一个时间,当锁持有者超过这个时间不释放锁时,等待者会放弃CPU时间片阻塞;
2.死锁问题:试想一下,有一个线程连续两次试图获得自旋锁(比如在递归程序中),第一次这个线程获得了该锁,当第二次试图加锁的时候,检测到锁已被占用(其实是被自己占用),那么这时,线程会一直等待自己释放该锁,而不能继续执行,这样就引起了死锁。因此递归程序使用自旋锁应该遵循以下原则:递归程序决不能在持有自旋锁时调用它自己,也决不能在递归调用时试图获得相同的自旋锁。
JAVA中一种自旋锁的实现: CAS是Compare And Set的缩写
转载链接:https://blog.csdn.net/z69183787/article/details/79344382
用lock来保证原子性(this.count++这段代码称为临界区)
什么是原子性,就是不可分,从头执行到尾,不能被其他线程同时执行。
可通过CAS来实现原子操作
CAS(Compare and Swap):
CAS操作需要输入两个数值,一个旧值(期望操作前的值)和一个新值,在操作期间先比较下旧值有没有发生变化,如果没有发生变化,才交换成新值,发生了变化则不交换。
自从Synchronized引入了偏向锁,轻量级锁(自旋锁)后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用synchronized,其实synchronized的优化我感觉就借鉴了ReenTrantLock中的CAS技术。都是试图在用户态就把加锁问题解决,避免进入内核态的线程阻塞。
功能区别:
便利性:很明显Synchronized的使用比较方便简洁,并且由编译器去保证锁的加锁和释放,而ReenTrantLock需要手工声明来加锁和释放锁,为了避免忘记手工释放锁造成死锁,所以最好在finally中声明释放锁。
锁的细粒度和灵活度:很明显ReenTrantLock优于Synchronized
ReenTrantLock独有的能力:
1. ReenTrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。
2. ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。
3. ReenTrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。
ReenTrantLock实现的原理:
ReenTrantLock的实现是一种自旋锁,通过循环调用CAS操作来实现加锁。它的性能比较好也是因为避免了使线程进入内核态的阻塞状态。想尽办法避免线程进入内核的阻塞状态是我们去分析和理解锁设计的关键钥匙。
什么情况下使用ReenTrantLock:
答案是,如果你需要实现ReenTrantLock的三个独有功能时。
158、CAS(乐观锁)
转载链接:https://www.tuicool.com/articles/zuui6z
CAS(Compare And Swap) 无锁算法: CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,
只有其中一个线程能更新变量的
,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。CAS有3个操作数
,内存值V,旧的预期值A,
要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
高并发环境下优化锁或无锁(lock-free)的设计思路
prv:concurrenthashmap:桶力度锁区别于hashtable锁整个表,它只锁单个桶
高并发环境下要实现高吞吐量和线程安全,两个思路:一个是用优化的锁实现,一个是lock-free的无锁结
构。但非阻塞算法要比基于锁的算法复杂得多。开发非阻塞算法是相当专业的训练,而且要证明算法的正确
也极为困难,不仅和具体的目标机器平台和编译器相关,而且需要复杂的技巧和严格的测试。虽然Lock-Free
编程非常困难,但是它通常可以带来比基于锁编程更高的吞吐量。所以Lock-Free编程是大有前途的技术。
它在线程中止、优先级倒置以及信号安全等方面都有着良好的表现。
优化锁实现的例子 :Java中的ConcurrentHashMap,设计巧妙,用桶粒度的锁和锁分离机制,避免了put
和get中对整个map的锁定,尤其在get中,只对一个HashEntry做锁定操作,性能提升是显而易见的。
Lock-free无锁的例子 :CAS(CPU的Compare-And-Swap指令)的利用和LMAX的 disruptor 无锁消息队列
数据结构等。
160、springboot内置tomcat跟独立部署tomcat有什么区别
启动方式不同,内置是通过main方法启动,独立部署的是读取web.xml配置信息进行启动的。
本地访问springboot项目不用加项目名称,独立部署的要加项目名称
版本: tomcat:8.5.20 springboot:1.5.8 mysql:5.1.44 oracle:11g
163、session共享
spring的session共享可以利用redis,在spring配置文件中配置spring-session-data-redis把session存取改到redis中来实现
164、hashmap&hashtable
hashmap:线程不安全\允许有null的键和值\有containsvalue和containsKey方法,HashMap 继承于AbstractMap类
hashtable\线程安全\不允许有null的键和值\方法是是Synchronize的\有contains方法方法\、Hashtable 继承于Dictionary 类
165、hashmap取模(对key取hash然后分配)
取模就是取余数,初始长度是16,任何key的hash值取模16,只好是0-15,有16个
167、构造函数
名称跟类名一致,不能有返回值,如果没有定义,那么类加载器在加载的时候就会给一个默认的无参构造函数,如果定义了一个就不会有无
参的构造函数,在生成对象的时候调用的,如果有继承父类则先加载父类构造函数,先有爸爸才能有儿子
169、redis
Redis数据结构: String—字符串(key-value 类型)
Hash—字典(hashmap) Redis的哈希结构可以使你像在数据库中更新一个属性一样只修改某一项属性值
List—列表 实现消息队列
Set—集合 利用唯一性
Sorted Set—有序集合 可以进行排序 可以实现数据持久化
170、RPC
180、银行家算法
在银行中,客户申请贷款的数量是有限的,每个客户在第一次申请贷款时要声明完成该项目所需的最大资金量,在满足所有贷款要求时,客户应及时归还。银行家在客户申请的贷款数量不超过自己拥有的最大值时,都应尽量满足客户的需要。在这样的描述中,银行家就好比操作系统,资金就是资源,客户就相当于要申请资源的进程。
银行家算法是一种最有代表性的避免死锁的算法。在避免死锁方法中允许进程动态地申请资源,但系
银行家算法
银行家算法
统在进行资源分配之前,应先计算此次分配资源的安全性,若分配不会导致系统进入不安全状态,则分配,否则等待。为实现银行家算法,系统必须设置若干数据结构。
要解释银行家算法,必须先解释操作系统安全状态和不安全状态。
安全序列是指一个进程序列{P1,…,Pn}是安全的,即对于每一个进程Pi(1≤i≤n),它以后尚需要的资源量不超过系统当前剩余资源量与所有进程Pj (j < i )当前占有资源量之和。
银行家算法的基本思想是分配资源之前,判断系统是否是安全的;若是,才分配。它是最具有代表性的避免死锁的算法。
185、包装类
一是为了在各种类型间转化,通过各种方法的调用。否则 你无法直接通过变量转化。比如,现在int要转为String
int a=0;String result=Integer.toString(a);
再举例下。比如我现在要用泛型.List nums;这里<>需要类。如果你用int。它会报错的。
186、HashMap 和 ConcurrentHashMap & 各种线程
转载链接:http://www.cnblogs.com/wojiaochuichui/p/9505096.html
集合
List 和 Set 区别
List,Set都是继承自Collection接口
List特点:元素有放入顺序,元素可重复
Set特点:元素无放入顺序,元素不可重复,重复元素会覆盖掉
(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的,加入Set 的Object必须定义equals()方法 ,另外list支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。)
Set和List对比:
Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。
List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。
List 和 Map 区别
List是对象集合,允许对象重复。
Map是键值对的集合,不允许key重复。
Arraylist 与 LinkedList 区别
Arraylist:
优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。
缺点:因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。
LinkedList:
优点:LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景
缺点:因为LinkedList要移动指针,所以查询操作性能比较低。
适用场景分析:
当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。
ArrayList 与 Vector 区别
public ArrayList(int initialCapacity)//构造一个具有指定初始容量的空列表。
public ArrayList()//构造一个初始容量为10的空列表。
public ArrayList(Collection<? extends E> c)//构造一个包含指定 collection 的元素的列表
Vector有四个构造方法:
public Vector()//使用指定的初始容量和等于零的容量增量构造一个空向量。
public Vector(int initialCapacity)//构造一个空向量,使其内部数据数组的大小,其标准容量增量为零。
public Vector(Collection<? extends E> c)//构造一个包含指定 collection 中的元素的向量
public Vector(int initialCapacity,int capacityIncrement)//使用指定的初始容量和容量增量构造一个空的向量
ArrayList和Vector都是用数组实现的,主要有这么三个区别:
Vector是多线程安全的,线程安全就是说多线程访问同一代码,不会产生不确定的结果。而ArrayList不是,这个可以从源码中看出,Vector类中的方法很多有synchronized进行修饰,这样就导致了Vector在效率上无法与ArrayList相比;
两个都是采用的线性连续空间存储元素,但是当空间不足的时候,两个类的增加方式是不同。
Vector可以设置增长因子,而ArrayList不可以。
Vector是一种老的动态数组,是线程同步的,效率很低,一般不赞成使用。
适用场景分析:
Vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用ArrayList效率比较高。
如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector有一定的优势。
HashMap 和 Hashtable 的区别
1.hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。
2.hashTable同步的,而HashMap是非同步的,效率上逼hashTable要高。
3.hashMap允许空键值,而hashTable不允许。
注意:
TreeMap:非线程安全基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态。
Treemap:适用于按自然顺序或自定义顺序遍历键(key)。
参考:转载链接:http://blog.csdn.net/qq_22118507/article/details/51576319
HashSet 和 HashMap 区别
set是线性结构,set中的值不能重复,hashset是set的hash实现,hashset中值不能重复是用hashmap的key来实现的。
map是键值对映射,可以空键空值。HashMap是Map接口的hash实现,key的唯一性是通过key值hash值的唯一来确定,value值是则是链表结构。
他们的共同点都是hash算法实现的唯一性,他们都不能持有基本类型,只能持有对象
HashMap 和 ConcurrentHashMap 的区别
ConcurrentHashMap是线程安全的HashMap的实现。
(1)ConcurrentHashMap对整个桶数组进行了分割分段(Segment),然后在每一个分段上都用lock锁进行保护,相对于HashTable的
syn关键字锁的粒度更精细了一些,并发性能更好,而HashMap没有锁机制,不是线程安全的。
(2)HashMap的键值对允许有null,但是ConCurrentHashMap都不允许。
HashMap 的工作原理及代码实现
参考:转载链接:https://tracylihui.github.io/2015/07/01/Java集合学习1:HashMap的实现原理/
ConcurrentHashMap 的工作原理及代码实现
HashTable里使用的是synchronized关键字,这其实是对对象加锁,锁住的都是对象整体,当Hashtable的大小增加到一定的时候,
性能会急剧下降,因为迭代时需要被锁定很长的时间。
ConcurrentHashMap算是对上述问题的优化,其构造函数如下,默认传入的是16,0.75,16。
ConcurrentHashMap引入了分割(Segment),可以理解为把一个大的Map拆分成N个小的HashTable,在put方法中,会根据
hash(paramK.hashCode())来决定具体存放进哪个Segment,如果查看Segment的put操作,我们会发现内部使用的同步机制是基于
lock操作的,这样就可以对Map的一部分(Segment)进行上锁,这样影响的只是将要放入同一个Segment的元素的put操作,保证同
步的时候,锁住的不是整个Map(HashTable就是这么做的),相对于HashTable提高了多线程环境下的性能,因此HashTable已经被
淘汰了。
线程
创建线程的方式及实现
Java中创建线程主要有三种方式:
一、继承Thread类创建线程类
(1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务。因此把run()方法称为执行体。
(2)创建Thread子类的实例,即创建了线程对象。
(3)调用线程对象的start()方法来启动该线程。
public class FirstThreadTest extends Thread{
new FirstThreadTest().start();
上述代码中Thread.currentThread()方法返回当前正在执行的线程对象。getName()方法返回调用该方法的线程的名字。
二、通过Runnable接口创建线程类
(1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体。
(2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
(3)调用线程对象的start()方法来启动该线程。
public class RunnableThreadTest implements Runnable
RunnableThreadTest rtt = new RunnableThreadTest();
new Thread(rtt,“新线程1”).start();
三、通过Callable和Future创建线程
(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
(3)使用FutureTask对象作为Thread对象的target创建并启动新线程。
(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableThreadTest implements Callable
CallableThreadTest ctt = new CallableThreadTest();
FutureTask ft = new FutureTask<>(ctt);
@Override
public Integer call() throws Exception
创建线程的三种方式的对比
采用实现Runnable、Callable接口的方式创见多线程时,优势是:
线程类只是实现了Runnable接口或Callable接口,还可以继承其他类。
在这种方式下,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码
和数据分开,形成清晰的模型,较好地体现了面向对象的思想。
劣势是:
编程稍微复杂,如果要访问当前线程,则必须使用Thread.currentThread()方法。
使用继承Thread类的方式创建多线程时优势是:
编写简单,如果需要访问当前线程,则无需使用Thread.currentThread()方法,直接使用this即可获得当前线程。
劣势是:
线程类已经继承了Thread类,所以不能再继承其他父类。
set
转载链接:https://www.cnblogs.com/xiaxj/p/7891963.html
prv:都是继承collections接口,c接口有个iterator方法,返回Iterator结构对象,所以Iterator遍历可以这么写,所以还是
看源码重要啊方便理解跟直接理解底层印象也深一些。
Set集合的特点:
不能存储相同的元素。
同时因为其是一个抽象的接口:所以不能直接实例化一个set对象。(Set s = new Set() )错误
该接口主要继承于Collections接口,所以具有Collection的一些常见的方法。
常见的方法:
add( ) 向集合中添加元素
clear( ) 去掉集合中所有的元素
contains( ) 判断集合中是否包含某一个元素
isEmpty( ) 判断集合是否为空
iterator( ) 主要用于递归集合,返回一个Iterator()对象
remove( ) 从集合中去掉特定的对象
size( ) 返回集合的大小
Set接口最长用的两大实现:HashSet TreeSet
TreeSet:会将里面的元素默认排序。
Set test = new TreeSet<>();
int a = 1;
test.add(a);
//遍历集合test 利用foreach遍历 //输出结果:1 3 8
for (Integer value : test) {
System.out.print(value+" “);
}
//利用Iterator实现遍历
Iterator value = test.iterator();
while (value.hasNext()) {
int s = value.next();
System.out.print(s+” ");
} //输出结果:1 3 8
191、ThreadLocal
虽然ThreadLocal能够解决上面说的问题,但是由于在每个线程中都创建了副本,所以要考虑它对资源的消耗,比如内存的占用会比不使用
ThreadLocal要大。最常见的ThreadLocal使用场景为 用来解决 数据库连接、Session管理等。
转载链接:https://www.cnblogs.com/dolphin0520/p/3920407.html
195、注意反模式设计
转载链接:http://blog.jobbole.com/87413/
1 过早优化
优化之前分析。避免为了效率而牺牲简洁性,除非效率被验证了的确是有必要的。
2 单车车库
避免花费太多时间在琐碎的事情上。
3 分析瘫痪
只想要预见性,不情愿去做简单有效的事,缺乏清晰的思考,建议混乱……这些构成了历史上无休止重复的特点。—— Winston Churchill, 《国会辩论》
做也许好过不做。—— Tim Peters, 《The Zen of Python》
宁愿迭代,也不要过度分析和猜测。
4 上帝类
简单胜过复杂。—— Tim Peters,《 The Zen of Python》
避免有着太多责任和依赖的庞大的类。
5 新增类恐惧症
稀少胜于繁杂。—— Tim Peters, 《The Zen of Python》
类的数量多,并不能说明设计很糟糕。
6 内部平台效应
那些不理解Unix的人会因为他们的重复发明而遭到谴责。—— Henry Spencer
避免重新发明你的操作系统或开发平台已经做得很多的功能。
7 魔法数和字符串
明了胜于晦涩。—— Tim Peters,《 The Zen of Python》
避免在代码中出现未注释、未命名的数字和字符串字面量。
8 数字管理
用代码行数来衡量开发进度,无异于用重量来衡量制造飞机的进度。—— Bill Gates
用数字来得出你的决策,但不是用数字来做决定。
9 无用的(幽灵)类
要达到完美,不是没有东西可加,而是没有东西可减。—— Antoine de Saint Exupéry
避免没有真正责任的类。
196、sql优化
转载链接:https://blog.csdn.net/jie_liang/article/details/77340905
转载链接:https://blog.csdn.net/u011277123/article/details/72627011
sql优化的几种方法
在sql查询中为了提高查询效率,我们常常会采取一些措施对查询语句进行sql优化,下面总结的一些方法,有需要的可以参考参考。
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num is null
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num=0
3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or num=20
可以这样查询:
select id from t where num=10
union all
select id from t where num=20
5.in 和 not in 也要慎用,否则会导致全表扫描,如:
select id from t where num in(1,2,3)
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
6.下面的查询也将导致全表扫描:
select id from t where name like ‘%abc%’
7.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where num/2=100
应改为:
select id from t where num=1002
8.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where substring(name,1,3)=‘abc’–name以abc开头的id
应改为:
select id from t where name like ‘abc%’
9.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
10.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,
否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。
11.不要写一些没有意义的查询,如需要生成一个空表结构:
select col1,col2 into #t from t where 1=0
这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:
create table #t(…)
12.很多时候用 exists 代替 in 是一个好的选择:
select num from a where num in(select num from b)
用下面的语句替换:
select num from a where exists(select 1 from b where num=a.num)
13.并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,
如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。
14.索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,
因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。
一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
15.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。
这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
16.尽可能的使用 varchar 代替 char ,因为首先变长字段存储空间小,可以节省存储空间,
其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
17.任何地方都不要使用 select * from t ,用具体的字段列表代替“”,不要返回用不到的任何字段。
18.避免频繁创建和删除临时表,以减少系统表资源的消耗。
19.临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。
20.在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,
以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。
21.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。
22.尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。
23.使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。
24.与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。
在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。
25.尽量避免大事务操作,提高系统并发能力。26.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
197、工厂模式跟抽象工厂
这两种设计模式主要的区别在于产品,工厂模式是用来创建同一个产品的不同类型的(详情请看上一篇博客中卖包子的案例,大肉包和牛
肉包它们都是包子的不同类型展示),但是抽象工厂模式是用来创建不同类的产品,比如包子店还卖豆浆油条。一般来说,产品种类单一
,适合用工厂模式;如果有多个种类,各种类型时,通过抽象工厂模式来进行创建是很合适的。
199、转载链接:https和转载链接:http的主要区别:
一、转载链接:https协议需要到ca机构申请ssl证书(如沃通CA),另外沃通CA还提供3年期的免费ssl证书,高级别的ssl证书需要一定费用。
二、转载链接:http是超文本传输协议,信息是明文传输,转载链接:https 则是具有安全性的ssl加密传输协议。
三、转载链接:http和转载链接:https使用的是完全不同的连接方式,用的端口也不一样,转载链接:http是80端口,转载链接:https是443端口。
四、转载链接:http的连接很简单,是无状态的;转载链接:https协议是由ssl+转载链接:http协议构建的可进行加密传输、身份认证的网络协议,比转载链接:http协议安全。
转载链接:https://www.cnblogs.com/bellkosmos/p/5237146.html
正文:转载链接:http协议无状态中的【状态】到底指的是什么?! 每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求是无直接关系的
先来看这句话的另外两个概念:(标准的转载链接:http协议是无状态的,无连接的)
标准的转载链接:http协议指的是不包括cookies, session,application的转载链接:http协议,他们都不属于标准协议,虽然各种网络应用提供商,实现语言、web容器等,都默认支持它
无连接指的是什么
每一个访问都是无连接,服务器挨个处理访问队列里的访问,处理完一个就关闭连接,这事儿就完了,然后处理下一个新的
无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接
协议对于事务处理没有记忆能力【事物处理】【记忆能力】
对同一个url请求没有上下文关系【上下文关系】
每次的请求都是独立的,它的执行情况和结果与前面的请求和之后的请求是无直接关系的,它不会受前面的请求应答情况直接影响,也不会直接影响后面的请求应答情况【无直接联系】【受直接影响】
服务器中没有保存客户端的状态,客户端必须每次带上自己的状态去请求服务器【状态】
200、tcp udp的区别
转载链接:https://blog.csdn.net/xiaobangkuaipao/article/details/76793702
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
Tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。
滑动窗口也就是告诉接收方还有多少空间可以接收,让接收方可以自我调整发送的数据
3、UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
4.每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP对系统资源要求较多,UDP对系统资源要求较少。
滑动窗口(Sliding window)是一种流量控制技术。早期的网络通信中,通信双方不会考虑网络的拥挤情况直接发送数据。由于大家不知道
网络拥塞状况,同时发送数据,导致中间节点阻塞掉包,谁也发不了数据,所以就有了滑动窗口机制来解决此问题。参见滑动窗口如何根据
网络拥塞发送数据仿真视频。
滑动窗口协议是用来改善吞吐量的一种技术,即容许发送方在接收任何应答之前传送附加的包。接收方告诉发送方在某一时刻能送多少包
(称窗口尺寸)。
TCP中采用滑动窗口来进行传输控制,滑动窗口的大小意味着接收方还有多大的缓冲区可以用于接收数据。发送方可以通过滑动窗口的大小
来确定应该发送多少字节的数据。当滑动窗口为0时,发送方一般不能再发送数据报,但有两种情况除外,一种情况是可以发送紧急数据,
例如,允许用户终止在远端机上的运行进程。另一种情况是发送方可以发送一个1字节的数据报来通知接收方重新声明它希望接收的下一
字节及发送方的滑动窗口大小
2、为什么UDP有时比TCP更有优势?
UDP以其简单、传输快的优势,在越来越多场景下取代了TCP,如实时游戏。
(1)网速的提升给UDP的稳定性提供可靠网络保障,丢包率很低,如果使用应用层重传,能够确保传输的可靠性。
(2)TCP为了实现网络通信的可靠性,使用了复杂的拥塞控制算法,建立了繁琐的握手过程,由于TCP内置的系统协议栈中,极难对其进行改进。
采用TCP,一旦发生丢包,TCP会将后续的包缓存起来,等前面的包重传并接收到后再继续发送,延时会越来越大,基于UDP对实时性要求较
为严格的情况下,采用自定义重传机制,能够把丢包产生的延迟降到最低,尽量减少网络问题对游戏性造成影响。
202、事务的隔离性跟传播性
转载链接:https://www.cnblogs.com/zhishan/p/3195219.html
传播行为
propagation:传播 nested:嵌套 mandatory:强制 ISOLATION:隔离
requires(默认)、requires_new、supports、not_supports、mandatory、nested、neve、
PROPAGATION_MANDATORY 表示该方法必须运行在一个事务中。如果当前没有事务正在发生,将抛出一个异常
PROPAGATION_NESTED 表示如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于封装事务进行
提交或回滚。如果封装事务不存在,行为就像PROPAGATION_REQUIRES一样。
PROPAGATION_NEVER 表示当前的方法不应该在一个事务中运行。如果一个事务正在进行,则会抛出一个异常。
PROPAGATION_NOT_SUPPORTED 表示该方法不应该在一个事务中运行。如果一个现有事务正在进行中,它将在该方法的运行期间被挂起。
PROPAGATION_SUPPORTS 表示当前方法不需要事务性上下文,但是如果有一个事务已经在运行的话,它也可以在这个事务里运行。
PROPAGATION_REQUIRES_NEW
表示当前方法必须在它自己的事务里运行。一个新的事务将被启动,而且如果有一个现有事务在运行的话,则将在这个方法运行期间被挂起。
PROPAGATION_REQUIRES表示当前方法必须在一个事务中运行。如果一个现有事务正在进行中,该方法将在那个事务中运行,否则就要开始一个新事务
传播规则回答了这样一个问题,就是一个新的事务应该被启动还是被挂起,或者是一个方法是否应该在事务性上下文中运行。
隔离级别
Read-Uncommitted0导致脏读
Read-Committed1避免脏读,允许不可重复读和幻读
Repeatable-Read2避免脏读,不可重复读,允许幻读
声明式事务的第二个方面是隔离级别。隔离级别定义一个事务可能受其他并发事务活动活动影响的程度。另一种考虑一个事务的隔离级别的方式,是把它想象为那个事务对于事物处理数据的自私程度。
在一个典型的应用程序中,多个事务同时运行,经常会为了完成他们的工作而操作同一个数据。并发虽然是必需的,但是会导致一下问题:
脏读(Dirty read)-- 脏读发生在一个事务读取了被另一个事务改写但尚未提交的数据时。如果这些改变在稍后被回滚了,那么第一个事务读取的数据就会是无效的。
不可重复读(Nonrepeatable read)-- 不可重复读发生在一个事务执行相同的查询两次或两次以上,但每次查询结果都不相同时。这通常是由于另一个并发事务在两次查询之间更新了数据。
幻影读(Phantom reads)-- 幻影读和不可重复读相似。当一个事务(T1)读取几行记录后,另一个并发事务(T2)插入了一些记录时,幻影读就发生了。在后来的查询中,第一个事务(T1)就会发现一些原来没有的额外记录。
在理想状态下,事务之间将完全隔离,从而可以防止这些问题发生。然而,完全隔离会影响性能,因为隔离经常牵扯到锁定在数据库中的记录(而且有时是锁定完整的数据表)。侵占性的锁定会阻碍并发,要求事务相互等待来完成工作。
考虑到完全隔离会影响性能,而且并不是所有应用程序都要求完全隔离,所以有时可以在事务隔离方面灵活处理。因此,就会有好几个隔离级别。
隔离级别
含义
ISOLATION_DEFAULT 使用后端数据库默认的隔离级别。
ISOLATION_READ_UNCOMMITTED 允许读取尚未提交的更改。可能导致脏读、幻影读或不可重复读。
ISOLATION_READ_COMMITTED 允许从已经提交的并发事务读取。可防止脏读,但幻影读和不可重复读仍可能会发生。
ISOLATION_REPEATABLE_READ对相同字段的多次读取的结果是一致的,除非数据被当前事务本身改变。可防止脏读和不可重复读但幻影读仍可能发生
ISOLATION_SERIALIZABLE 完全服从ACID的隔离级别,确保不发生脏读、不可重复读和幻影读。这在所有隔离级别中也是最慢的,因为它通常是通过完全锁定当前事务所涉及的数据表来完成的。
203、设计模式,有没有使用过 状态模式
转载链接:https://www.cnblogs.com/ysw-go/p/5404918.html
Java设计模式系列之状态模式
状态模式(State)的定义
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类
状态模式(State)适用性
1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
2.一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。
这个状态通常用一个或多个枚举常量表示。
通常,有多个操作包含这一相同的条件结构。
State模式将每一个条件分支放入一个独立的类中。
这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。
状态模式(State)的参与者
1.Context
定义客户感兴趣的接口。
维护一个ConcreteState子类的实例,这个实例定义当前状态。
2.State
定义一个接口以封装与Context的一个特定状态相关的行为。
3.ConcreteStatesubclasses
每一子类实现一个与Context的一个状态相关的行为。
接下来我们用Java编程思想中的一个例子来讲解一下状态模式
我们学习了多态,看起来似乎所有的东西都可以去继承,因为多态是一个如此巧妙的工具。事实上,当我们使用现成的类建立新类时,如果首先考虑使用继承技术,反倒会加重我们的设计负担,使得事情变得复杂起来。
更好的设计思想是首先选择"组合",尤其是不能十分确定应该使用哪一种方式的时候。组合不会强制我们的程序设计进入继承的层次结构中。而且,组合更加灵活,因为它可以动态选择类型(因此也就选择了行为),想法,继承在编译时就需要知道确定的类型,下面是具体代码体现:
状态模式和策略模式的区别和联系(取自知乎网友的回答,很精辟):
区别:
状态模式将各个状态所对应的操作分离开来,即对于不同的状态,由不同的子类实现具体操作,不同状态的切换由子类实现,当发现传入参数不是自己这个状态所对应的参数,则自己给Context类切换状态;而策略模式是直接依赖注入到Context类的参数进行选择策略,不存在切换状态的操作练习
联系:
状态模式和策略模式都是为具有多种可能情形设计的模式,把不同的处理情形抽象为一个相同的接口,符合对扩展开放,对修改封闭的原则。还有就是,策略模式更具有一般性一些,在实践中,可以用策略模式来封装几乎任何类型的规则,只要在分析过程中听到需要在不同实践应用不同的业务规则,就可以考虑使用策略模式处理,在这点上策略模式是包含状态模式的功能的,策略模式是一个重要的设计模式。
演员的状态切换才是状态模式的精髓啊!
204、spring
转载链接:http://www.cnblogs.com/wojiaochuichui/p/9505096.html
BeanFactory和ApplicationContext的区别
转载链接:https://blog.csdn.net/qq_36074233/article/details/76153039
转载链接:https://blog.csdn.net/qq_38071755/article/details/80907153
描述
BeanFactory:
是Spring里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能;
ApplicationContext:
应用上下文,继承BeanFactory接口,它是Spring的一各更高级的容器,提供了更多的有用的功能;
1) 国际化(MessageSource)
2) 访问资源,如URL和文件(ResourceLoader)
3) 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
4) 消息发送、响应机制(ApplicationEventPublisher)
5) AOP(拦截器)
两者装载bean的区别
BeanFactory:
BeanFactory在启动的时候不会去实例化Bean,中有从容器中拿Bean的时候才会去实例化;
ApplicationContext:
ApplicationContext在启动的时候就把所有的Bean全部实例化了。它还可以为Bean配置lazy-init=true来让Bean延迟实例化;
我们该用BeanFactory还是ApplicationContent
延迟实例化的优点:(BeanFactory)
应用启动的时候占用资源很少;对资源要求较高的应用,比较有优势;
不延迟实例化的优点: (ApplicationContext)
1. 所有的Bean在启动的时候都加载,系统运行的速度快;
2. 在启动的时候所有的Bean都加载了,我们就能在系统启动的时候,尽早的发现系统中的配置问题
3. 建议web应用,在启动的时候就把所有的Bean都加载了。(把费时的操作放到系统启动中完成)
spring注解
@Required 必须要注入一般放set上面
@Autowired 自动注入 一般按类型
@Qualifier 预选 用来对同名的甄别,按名称注入
@Resource @PostConstruct @PreDestroy
@Autowired默认为by Type的 所以有两个相同类型的bean 如果不使用 @Qualifier指定具体的bean就会抛出异常
Spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、@PostConstruct以及@PreDestroy。
@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入罢了。
JSR-250 为初始化之后/销毁之前方法的指定定义了两个注释类,分别是 @PostConstruct 和@PreDestroy,这两个注释只能应用于方法上。
标注了 @PostConstruct 注释的方法将在类实例化后调用,而标注了@PreDestroy 的方法将在类销毁之前调用
Spring Bean 作用域之间的区别?
Spring 容器中的 bean 可以分为 5 个范围。所有范围的名称都是自说明的,但是为了避免混淆,
还是让我们来解释一下:
1.singleton:这种 bean 范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个 bean 的实例,单例的模式由 bean factory 自身来维护。
2.prototype:原形范围与单例范围相反,为每一个 bean 请求提供一个实例。
3.request:在请求 bean 范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后,bean 会失效并被垃圾回收器回收。
4.Session:与请求范围类似,确保每个 session 中有一个 bean 的实例,在 session 过期后,bean 会随之失效。
5.global-session:global-session 和 Portlet 应用相关。当你的应用部署在 Portlet 容器中作时,它包含很多 portlet。如果你想要声明让所有的 portlet 共用全局的存储变量的话,那么这全局变量需要存储在 global-session 中。全局作用域与 Servlet 中的 session 作用域效果相同。
注解@SpringCloudApplication包括:
@SpringBootApplication、@EnableDiscoveryClient、@EnableCircuitBreaker[ˈsɜ:kɪt],分别是SpringBoot注解、注册服务中心Eureka注解、断路器注解
Spring 框架中的单例 Beans 是线程安全的么?
Spring 框架并没有对单例 bean 进行任何多线程的封装处理。关于单例 bean 的线程安全和并发问题需要开发者自行去搞定。但实际上,
大部分的 Spring bean 并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。
如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。
最浅显的解决办法就是将多态 bean 的作用域由“singleton”变更为“prototype”。
请解释各种自动装配模式的区别?
在 Spring 框架中共有 5 种自动装配,让我们逐一分析。
1.no:这是 Spring 框架的默认设置,在该设置下自动装配是关闭的,开发者需要自行在 bean定义中用标签明确的设置依赖关系。
2.byName:该选项可以根据 bean 名称设置依赖关系。当向一个 bean 中自动装配一个属性时,容器将根据 bean 的名称自动在在配置文件中查询一个匹配的 bean。如果找到的话,就装配这个属性,如果没找到的话就报错。
3.byType:该选项可以根据 bean 类型设置依赖关系。当向一个 bean 中自动装配一个属性时,容器将根据 bean 的类型自动在在配置文件中查询一个匹配的 bean。如果找到的话,就装配这个属性,如果没找到的话就报错。
4.constructor:造器的自动装配和 byType 模式类似,但是仅仅适用于与有构造器相同参数的bean,如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
5.autodetect:该模式自动探测使用构造器自动装配或者 byType 自动装配。首先,首先会尝试找合适的带参数的构造器,如果找到的话就是用构造器自动装配,如果在 bean 内部没有找到相应的构造器或者是无参构造器,容器就会自动选择 byTpe 的自动装配方式。
在 Spring 中可以注入 null 或空字符串吗?
完全可以。
Spring 框架中有哪些不同类型的事件?
Spring 的 ApplicationContext 提供了支持事件和代码中监听器的功能。
我们可以创建 bean 用来监听在 ApplicationContext 中发布的事件。ApplicationEvent 类和在 ApplicationContext 接口中处理的事件,如果一个 bean 实现了 ApplicationListener 接口,当一个 ApplicationEvent 被发布以后,bean 会自动被通知。
public class AllApplicationEventListener implements ApplicationListener {
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent){//process event}}
Spring 提供了以下 5 中标准的事件:
1.上下文更新事件(ContextRefreshedEvent):该事件会在 ApplicationContext 被初始化或者更新时发布。也可以在调用 ConfigurableApplicationContext 接口中的 refresh()方法时被触发。
2.上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的 Start()方法开始/重新开始容器时触发该事件。
3.上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的 Stop()方法停止容器时触发该事件。
4.上下文关闭事件(ContextClosedEvent):当 ApplicationContext 被关闭时触发该事件。容器被关闭时,其管理的所有单例 Bean 都被销毁。
5.请求处理事件(RequestHandledEvent):在 Web 应用中,当一个 转载链接:http 请求(request)结束触发该事件。
除了上面介绍的事件以外,还可以通过扩展 ApplicationEvent 类来开发自定义的事件。
FileSystemResource 和 ClassPathResource 有何区别?
在 FileSystemResource 中需要给出 spring-config.xml 文件在你项目中的相对路径或者绝对路径。在 ClassPathResource 中 spring 会在 ClassPath 中自动搜寻配置文件,所以要把ClassPathResource 文件放在 ClassPath 下。
如果将 spring-config.xml 保存在了 src 文件夹下的话,只需给出配置文件的名称即可,因为 src文件夹是默认。
简而言之,ClassPathResource 在环境变量中读取配置文件FileSystemResource 在配置文件中读取配置文件。
Spring 框架中都用到了哪些设计模式?
Spring 框架中使用到了大量的设计模式,下面列举了比较有代表性的:
1、代理模式—在 AOP 和 remoting 中被用的比较多。
2、单例模式:在 spring 配置文件中定义的 bean 默认为单例模式。
3、模板模式:用来解决代码重复的问题。
比如. RestTemplate, JmsTemplate, JpaTemplate。
4、委派模式:Spring 提供了 DispatcherServlet 来对请求进行分发。
5、工厂模式:BeanFactory 用来创建对象的实例,贯穿于 BeanFactory / ApplicationContext
接口的核心理念。
6、代理模式:AOP 思想的底层实现技术,Spring 中采用 JDK Proxy 和 CgLib 类库
Spring5 新特性
1、依赖 JDK 8+和 Java EE7+以上版本
2、首次采用反应式编程模型
3、支持使用注解进行编程
4、新增函数式编程lambda
5、支持使用 REST 断点执行反应式编程
6、支持 转载链接:HTTP 2.0
7、新增 Kotlin 和 Spring WebFlux
8、可使用 Lambda 表达式注册 Bean
9、Spring WebMVC 支持最新的 API
10、使用 JUnit5 执行条件和并发测试
11、使用 Spring WebFlux 执行集成测试
12、核心容器优化
反应式编程与Java8提供的Streams有众多相似之处(尤其是API上),且提供了相互转化的API。但是反应式编程更加强调异步非阻塞,通过onComplete等注册监听的方式避免阻塞,同时支持delay、interval等特性。而Streams本质上是对集合的并行处理,并不是非阻塞的。
MyBatis 会把0当null,如果mapper里的<if status!=null && status != ‘’>有这个判断,那么就尴尬了,要么用INteger要么不用0改成1,2
源码:
AtomicInteger:i++跟++i是线程不安全的,递增的时候用getAndIncrement()方法。利用private volatile int value的volatile共享变量值,调用getAndAddInt,底层
线程池里面就用到很多lock,unlock。
其实是调用compareAndSwapInt这个本地native方法
跟读源码,发现看源码揣摩细节的意图能让自己思考更加全面,比如判断线程当前线程数是否大于核心线程池数,明明外层判断了一次,里层lock之后又判断了一次,原因是因为外层没加锁,判断的结果不是最准确的,可能另一个线程同时操作过,还有一种情况是判断线程数是否为0,为0表示线程池被关闭,这时就需要确保即将处理的操作要能持续下去,不被线程池意外关闭影响到。
从大的方面考虑,有种做法是当检测到有空的线程时用空的线程去加载任务,但是这样就多了一个监管的步骤,但是线程池源码采用的是当一个线程执行完任务之后自动去队列里面加载任务,加载不到就循环该操作,这样就省去了监管的额外动作,跟锁sync和CAS的对比同理。
205、[操作系统]页式、段式、段页式存储管理
转载链接:https://blog.csdn.net/lady_lili/article/details/52623870
内存空间(物理空间或绝对空间):由一系列存储单元所限定 的地址范围。
逻辑地址空间(地址空间):由程序中逻辑地址组成的地址范围。
相对地址(逻辑地址):用户程序经编译后每个目标木块都以0为基地址顺序编址,这种地址称为相对地址。
绝对地址(物理地址):内存中各物理存储单元的地址是从统一的基地址顺序编址,这种地址称为绝对地址。
离散的存储管理方式:页式、段式、段页式,为获得一条指令或数据,分别需要访问内存二次,二次,三次。
页式:逻辑空间分页,内存空间分块,页的大小=块的大小,地址空间一维
逻辑地址=页号&偏移量(&是连接符)
物理地址:先由逻辑地址和固定的页面大小,求出页号,在根据页表由页号求出块号,然后用块号&偏移量就得出物理地址。
段式:逻辑空间分成若干段,每个段的长度不等,地址空间二维
逻辑地址:段号&段内地址
物理地址:基址+段内地址,由段号结合段表求出基址,然后用基址加上段内地址就可求出,此时是+ 不是&。
段页式存储:先分段,段内再分页
逻辑地址:段号&段内页地址&页内地址
由段表寄存器求出段表始址,由段表始址和段号求出页表始址,页表始址和段内页号求出存储块号,块号和页内偏移求出物理地址
206、虚拟内存&虚拟地址
1、windows下的虚拟内存指的是在硬盘上建一个文件,用来放置系统非活跃性内存数据或交换数据(怎么放,放多少由操作系统决定)。
2、虚拟地址空间,指windows下每个进程的私有内存空间,大小是4G,能访问的是不到2G的空间,其余是系统保留的.这2G是能访问的,但并不是立即分配的,当进程使用多少时,才从物理内存中划分给它多少,划分的的方式是"映射",操作系统将虚拟内存的起始地址做个标记,标记成对应的物理内存的某个地址上.在这里,只有操作系统知道,进程是没有任何办法知道的。
虚拟内存:系统放不活跃数据的地方
虚拟地址:进程的物理地址对应的虚拟内存地址
207、抢占式&非抢占式
非抢占式(Nonpreemptive) 让进程运行直到结束或阻塞的调度方式 容易实现 适合专用系统,不适合通用系统
抢占式(Preemptive) 允许将逻辑上可继续运行的在运行过程暂停的调度方式 可防止单一进程长时间独占CPU 系统开销大(降低途径:硬件实现进程切换,或扩充主存以贮存大部分程序)
prv:现在电脑都是抢占式的。非抢占活不下去。没人买。支持多线程或单线程、同步或异步
cpu高是因为cpu时间分片的原因
208、
Sun JDK监控和故障处理命令有jps jstat jmap jhat jstack jinfo
jps,JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。
jstat,JVM statistics Monitoring是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、
JIT编译等运行数据。
jmap,JVM Memory Map命令用于生成heap dump文件
jhat,JVM Heap Analysis Tool命令是与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的转载链接:HTTP/HTML服务器,
生成dump的分析结果后,可以在浏览器中查看
jstack,用于生成java虚拟机当前时刻的线程快照。
jinfo,JVM Configuration info 这个命令作用是实时查看和调整虚拟机运行参数。
常见对象: 表 视图 函数 索引 触发器 存储过程 用户。
210、
redis的key跟value大小限制都是512M
TODO
商品超扣
把所有商品的放redis,滑锁,如果只有10个商品已经有10个订单了,后面的订单直接打回
mq是异步的
怎么做购物车
redis 持久化方式:rdb快照 aof日志
key过期策略
211、策略模式代替ifelse
其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换
转载链接:https://blog.csdn.net/SkipperKevin/article/details/77370880?utm_source=blogxgwz3
212、redis事务
转载链接:https://www.cnblogs.com/kyrin/p/5967620.html
TODO后续补充
1. MULTI
用于标记事务块的开始。Redis会将后续的命令逐个放入队列中,然后才能使用EXEC命令原子化地执行这个命令序列。
2. EXEC 在一个事务中执行所有先前放入队列的命令,然后恢复正常的连接状态。
EXEC
这个命令的返回值是一个数组,其中的每个元素分别是原子化事务中的每个命令的返回值。当进程使用多少时使用使用WATCH命令时,如果事务执行中止,那么EXEC命令就会返回一个Null值。
3. DISCARD
清除所有先前在一个事务中放入队列的命令,然后恢复正常的连接状态。
DISCARD
这个命令的返回值是一个简单的字符串,总是OK。
4. WATCH
当某个事务需要按条件执行时,就要使用这个命令将给定的键设置为受监控的。
5. UNWATCH
213、mysql行级锁是怎么实现的
直接语句后面加for update
转载链接:https://blog.csdn.net/liujie379908/article/details/80517818
214、幂等 resf put/delete/post
转载链接:https://blog.csdn.net/m0_37837382/article/details/64122835
215、springboot内嵌容器几种,tomcat版本是几
转载链接:https://blog.csdn.net/lonelymanontheway/article/details/79562512
tomcat/jetty 可知 spring boot 1.5.7 的内置 tomcat 版本是 8.5.20。
转载链接:https://blog.csdn.net/dutianqi110/article/details/79501031
负载均衡还要监控服务性能,对性能好的分配多一些请求,轮询:对台数取幂
216、
异步非阻塞,一个是socket处理,一个是跟内存的io处理,一个是请求一个是处理
springboot底层main方法加载
怎么断点续传
mina粘包怎么解决
217、基础
是否可以在static环境中访问非static变量
static变量属于类,它在所有实例中的值是一样的。当类被java虚拟机载入时,会对static变量进行初始化。如果你的代码
尝试不用实例来访问非静态的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。
自动拆装箱就是引用类型和基本类型之间的转换,至于为什么要转换,因为基本类型转换为引用类型之后,就可以new对象,
从而调用包装类中封装好的方法进行基本类型之间的转换或者toString,还有如果集合中想存放基本类型,泛型的限定类型
只能是对应的包装类型。
方法重写的原则:
重写方法的方法名称、参数列表必须与原方法的相同,返回类型可以相同也可以是原类型的子类型(从Java SE5开始支持)。
重写方法不能比原方法访问性差(即访问权限不允许缩小)。
重写方法不能比原方法抛出更多的异常。
被重写的方法不能是final类型,因为final修饰的方法是无法重写的。
被重写的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行重写。
被重写的方法不能为static。如果父类中的方法为静态的,而子类中的方法不是静态的,但是两个方法除了这一点外其他都满足重写条件,那么会发生编译错误;反之亦然。即使父类和子类中的方法都是静态的,并且满足重写条件,但是仍然不会发生重写,因为静态方法是在编译的时候把静态方法和类的引用类型进行匹配。
重写是发生在运行时的,因为编译期编译器不知道并且没办法确定该去调用哪个方法,JVM会在代码运行的时候作出决定。
方法重载的原则:
方法名称必须相同。
参数列表必须不同(个数不同、或类型不同、参数类型排列顺序不同等)。
方法的返回类型可以相同也可以不相同。
仅仅返回类型不同不足以成为方法的重载。
重载是发生在编译时的,因为编译器可以根据参数的类型来选择使用哪个方法。
重写和重载的不同:
方法重写要求参数列表必须一致,而方法重载要求参数列表必须不一致。
方法重写要求返回类型必须一致(或为其子类型),方法重载对此没有要求。
方法重写只能用于子类重写父类的方法,方法重载用于同一个类中的所有方法。
方法重写对方法的访问权限和抛出的异常有特殊的要求,而方法重载在这方面没有任何限制。
父类的一个方法只能被子类重写一次,而一个方法可以在所有的类中可以被重载多次。
重载是编译时多态,重写是运行时多态。
=对于基本数据类型来说改变的是值,对于引用类型来说赋值运算符会改变引用中保存的地址,原来的地址被覆盖掉,但是原来的对象不会被改变。
进程&线程
进程是执行着的应用程序,线程是进程内部的一个执行序列。
地址空间和其他资源:进程间相互独立,同一进程的各线程间共享。某进程内的线程其他进程不可见
进程间通信IPC(Inter-Process Communication):
线程间可以直接读写进程数据段(如全局变量)来进行通信,需要进程同步和互斥手段的辅助,以保证数据的一致性。
调度和切换:线程上下文切换比进程上下文切换要快得多
在多线程OS中,进程不是一个可执行的实体
saas paas
PAAS平台即(Platform-as-a-Service:平台即服务),把应用服务的运行和开发环境作为一种服务提供的商业模式。
SaaS是Software-as-a-Service(软件即服务)的简称,它是一种通过Internet提供软件的模式
218、applicatonContext继承自BeanFactory
转载链接:https://blog.csdn.net/it_beecoder/article/details/74206628
转载链接:https://baike.baidu.com/item/ApplicationContext/1129418
prv:
有三种方式加载applicationContext,xmlapplicationcontext,filesystemapplication,classpathapplication
beanfactory只能加载bean还会延迟加载
applicationContext会立刻加载bean,还有文件读取,国际化等工具方法
IOC容器里面包含beanFactory以及bean池
jvm加载完类以及静态信息过滤器等之后才会轮到spring去加载spring的容器
spring加载bean的时候也把bean的依赖关系都装配在bean上了,也就是比如一个bean里面包含另一个bean,这个依赖关系
也会包含在里面。
所以过滤器里面无法注入bean,因为连beanfactory都还没初始化,不过可以调用xmlapplicationContext方法来初始化beanFactory
从而来生成bean顺便注入bean。
当然静态类里面也是不能有autowired的,因为spring无法更改jvm加载流程。
219、java.util.concurrent包下的几个常用类
转载链接:https://blog.csdn.net/lh87522/article/details/45973373
1.Callable
Callable与Runnable类似,理解Callable可以从比较其与Runnable的区别开始:
1)从使用上:实现的Callable的类需要实现call()方法,此方法有返回对象V;而Runnable的子类需要实现run()方法,但没有返回值;
2)如果直接调用Callable的子类的call()方法,代码是同步顺序执行的;而Runnable的子类是线程,是代码异步执行。
3)将Callable子类submit()给线程池去运行,那么在时间上几个Callable的子类的执行是异步的。
即:如果一个Callable执行需要5s,那么直接调用Callable.call(),执行3次需要15s;
而将Callable子类交个线程执行3次,在池可用的情况下,只需要5s。这就是基本的将任务拆分异步执行的做法。
4)callable与future的组合用法:
(什么是Future?Future 表示异步计算的结果。其用于获取线程池执行callable后的结果,这个结果封装为Future类。详细可以参看Future的API,有示例。)
一种就像上面所说,对一个大任务进行分制处理;
另一种就是对一个任务的多种实现方法共同执行,任何一个返回计算结果,则其他的任务就没有执行的必要。选取耗时最少的结果执行。
2.Semaphore
一个计数信号量,主要用于控制多线程对共同资源库访问的限制。
典型的实例:1)公共厕所的蹲位……,10人等待5个蹲位的测试,满员后就只能出一个进一个。
2)地下车位,要有空余才能放行
3)共享文件IO数等
与线程池的区别:线程池是控制线程的数量,信号量是控制共享资源的并发访问量。
实例:Semaphore avialable = new Semaphore(int x,boolean y);
x:可用资源数;y:公平竞争或非公平竞争(公平竞争会导致排队,等待最久的线程先获取资源)
用法:在获取工作资源前,用Semaphore.acquire()获取资源,如果资源不可用则阻塞,直到获取资源;操作完后,用Semaphore.release()归还资源
由1.1)和1.2)的示例很好理解,ReetantLock也就是一个锁,线程执行某段代码时,需要争用此类实例的锁,用完后要显示的释放此锁。
至于具体区别,后面在说……
3.Condition:此类是同步的条件对象,每个Condition实例绑定到一个ReetrantLock中,以便争用同一个锁的多线程之间可以通过Condition的状态来获取通知。
注意:使用Condition前,首先要获得ReentantLock,当条件不满足线程1等待时,ReentrantLock会被释放,以能让其他线程争用,其他线程获得reentrantLock,然后满足条件,唤醒线程1继续执行。
这与wait()方法是一样的,调用wait()的代码块要被包含在synchronized块中,而当线程r1调用了objectA.wait()方法后,同步对象的锁会释放,以能让其他线程争用;其他线程获取同步对象锁,完成任务,调用objectA.notify(),让r1继续执行。代码示例如下。
4.BlockingQueue
简单介绍。这是一个阻塞的队列超类接口,concurrent包下很多架构都基于这个队列。BlockingQueue是一个接口,此接口的实现类有:ArrayBlockingQueue, DelayQueue, LinkedBlockingDeque, LinkedBlockingQueue, PriorityBlockingQueue, SynchronousQueue 。每个类的具体使用可以参考API。
这些实现类都遵从共同的接口定义(一目了然,具体参考api):
抛出异常 特殊值 阻塞 超时
插入 add(e) offer(e) put(e) offer(e, time, unit)
移除 remove() poll() take() poll(time, unit)
检查 element() peek() 不可用 不可用
5.CompletionService
1.CompletionService是一个接口,用来保存一组异步求解的任务结果集。api的解释是:将新生产的异步任务与已完成的任务结果集分离开来。
2.CompletionService依赖于一个特定的Executor来执行任务。实际就是此接口需要多线程处理一个共同的任务,这些多线程由一个指定的线程池来管理。CompletionService的实现类ExecutorCompletionService。
3.api的官方代码示例参考ExecutorCompletionService类的api(一个通用分制概念的函数)。
4.使用示例:如有时我们需要一次插入大批量数据,那么可能我们需要将1w条数据分开插,异步执行。如果某个异步任务失败那么我们还要重插,那可以用CompletionService来实现。下面是简单代码:
(代码中1w条数据分成10份,每次插1000条,如果成功则返回true,如果失败则返回false。那么忽略数据库的东西,我们假设插1w条数据需10s,插1k条数据需1s,那么下面的代码分制后,插入10条数据需要2s。为什么是2s呢?因为我们开的线程池是8线程,10个异步任务就有两个需要等待池资源,所以是2s,如果将下面的8改为10,则只需要1s。)
5.CompletionService与Callable+Future的对比:
在上面的Callable中说过,Callable+Future能实现任务的分治,但是有个问题就是:不知道call()什么时候完成,需要人为控制等待。
而jdk通过CompetionService已经将此麻烦简化,通过CompletionService将异步任务完成的与未完成的区分开来(正如api的描述),我们只用去取即可。
CompletionService有什么好处呢?
如上所说:1)将已完成的任务和未完成的任务分开了,无需开发者操心;2)隐藏了Future类,简化了代码的使用。真想点个赞!
6.CountDownLatch
1.CountDownLatch:api解释:一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。个人理解是CountDownLatch让可以让一组线程同时执行,然后在这组线程全部执行完前,可以让另一个线程等待。
就好像跑步比赛,10个选手依次就位,哨声响才同时出发;所有选手都通过终点,才能公布成绩。那么CountDownLatch就可以控制10个选手同时出发,和公布成绩的时间。
CountDownLatch 是一个通用同步工具,它有很多用途。将计数 1 初始化的 CountDownLatch 用作一个简单的开/关锁存器,或入口:在通过调用 countDown() 的线程打开入口前,所有调用 await 的线程都一直在入口处等待。用 N 初始化的 CountDownLatch 可以使一个线程在 N 个线程完成某项操作之前一直等待,或者使其在某项操作完成 N 次之前一直等待。
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(N);
7.CyclicBarrier
1.一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点。也就是说,这一组线程的执行分几个节点,每个节点往下执行,都需等待其他线程,这就需要这种等待具有循环性。CyclicBarrier在这样的情况下就很有用。
2.CyclicBarrier与CountDownLacth的区别:
1)CountDownLacth用于一个线程与一组线程之间的相互等待。常用的就是一个主线程与一组分治线程之间的等待:主线程发号令,一组线程同时执行;一组线程依次执行完,再唤醒主线程继续执行;
CyclicBarrier用于一组线程执行时,每个线程执行有多个节点,每个节点的处理需要相互等待。如:对5个文件进行处理,按行将各个文件数字挑出来合并成一行,排序,并输出到另一个文件,那每次处理都需要等待5个线程读入下一行。(api示例可供参考)
2)CountDownLacth的处理机制是:初始化一个值N(相当于一组线程有N个),每个线程调用一次countDown(),那么cdLatch减1,等所有线程都调用过countDown(),那么cdLatch值达到0,那么线程从await()处接着玩下执行。
CyclicBarrier的处理机制是:初始化一个值N(相当于一组线程有N个),每个线程调用一次await(),那么barrier加1,等所有线程都调用过await(),那么barrier值达到初始值N,所有线程接着往下执行,并将barrier值重置为0,再次循环下一个屏障;
3)由2)可以知道,CountDownLatch只可以使用一次,而CyclicBarrier是可以循环使用的。
4.参考api的示例。
api的示例自己看,就是加深印象。
但是api中有一点描述:如果屏障操作在执行时不依赖于正挂起的线程,则线程组中的任何线程在获得释放时都能执行该操作。为方便此操作,每次调用 await() 都将返回能到达屏障处的线程的索引。然后,您可以选择哪个线程应该执行屏障操作,例如:
if (barrier.await() == 0) {
// log the completion of this iteration
}
就是说,barrier.await()还会返回一个int值。这个返回值到底是什么呢?不是返回的线程的索引,返回的是:N-进入等待线程数,如5个线程,5线程都进入等待,那返回值就是0(具体可以参看源码)。那么barrier.await()==0也可以看做是一个N线程都达到公共屏障的信号,然后在此条件下处理原本需要放在Runnable参数中的逻辑。不用担心多线程会多次执行此逻辑,N个线程只有一个线程barrier.await()==0。
8.Exchanger
1.Exchanger可以在对中对元素进行配对和交换的线程的同步点。api上不是太好理解,个人理解说白了就是两个线程交换各自使用的指定内存数据。
2.场景:
api中有示例,两个线程A、B,各自有一个数据类型相同的变量a、b,A线程往a中填数据(生产),B线程从b中取数据(消费)。具体如何让a、b在内存发生关联,就由Exchanger完成。
api中说:Exchanger 可能被视为 SynchronousQueue 的双向形式。怎么理解呢?传统的SynchronousQueue存取需要同步,就是A放入需要等待B取出,B取出需要等待A放入,在时间上要同步进行。而Exchanger在B取出的时候,A是同步在放入的。即:1)A放入a,a满,然后与B交换内存,那A就可以操作b(b空),而B可以操作a;2)等b被A存满,a被B用完,再交换;3)那A又填充a,B又消费b,依次循环。两个内存在一定程度上是同时被操作的,在时间上不需要同步。
再理解就是:如果生产需要5s,消费需要5s。SynchronousQueue一次存取需要10s,而Exchanger只需要5s。4.注意事项:
目前只知道Exchanger只能发生在两个线程之间。但实际上Exchanger的源码是有多个插槽(Slot),交换是通过线程ID的hash值来定位的。目前还没搞懂?待后续。
如果一组线程aGroup操作a内存,一组线程bGroup操作b内存,如何交换?能不能交换?
4.注意事项:
目前只知道Exchanger只能发生在两个线程之间。但实际上Exchanger的源码是有多个插槽(Slot),交换是通过线程ID的hash值来定位的。目前还没搞懂?待后续。
如果一组线程aGroup操作a内存,一组线程bGroup操作b内存,如何交换?能不能交换?
9.Phaser
Phaser是jdk1.7的新特性。其功能类似CyclicBarrier和CountDownLatch,但其功能更灵活,更强大,支持动态调整需要控制的线程数。不重复了。参考链接:
220、 ConcurrentHashMap1.7和1.8的不同实现
转载链接:https://www.cnblogs.com/chengxiao/p/6842045.html
segment+HashEntry node+CAS+synchronized
221、 AQS实现原理
prv:实现对线程的获取、释放。
涉及三大关键操作:同步器的状态变更、线程的阻塞释放、插入和移出队列
三个基本组件:同步器原子性管理,线程阻塞和接触阻塞,队列管理
state被声明为volatile,并且通过使用CAS指令来实现compareAndSetState。tryAcquire和tryRelease
j.u.c.locks包提供了LockSupport类来解决这个问题。方法LockSupport.park阻塞当前线程直到有个LockSupport.unpark方法被调用
相比MCS,CLH更容易实现取消和超时,所以同步队列选择了CLH作为实现的基础。CLH队列是FIFO队列
转载链接:https://www.cnblogs.com/fengzheng/p/9153720.html
1、AQS 分为独占模式和共享模式,CountDownLatch 使用了它的共享模式。
2、AQS 当第一个等待线程(被包装为 Node)要入队的时候,要保证存在一个 head 节点,这个 head 节点不关联线程,也就是一个虚节点。
3、当队列中的等待节点(关联线程的,非 head 节点)抢到锁,将这个节点设置为 head 节点。
4、第一次自旋抢锁失败后,waitStatus 会被设置为 -1(SIGNAL),第二次再失败,就会被 LockSupport 阻塞挂起。
5、如果一个节点的前置节点为 SIGNAL 状态,则这个节点可以尝试抢占锁。
转载链接:http://ifeve.com/introduce-abstractqueuedsynchronizer/
转载链接:https://www.cnblogs.com/waterystone/p/4920797.html
转载链接:http://www.cnblogs.com/iou123lg/p/9464385.html
同步器是实现锁的关键,利用同步器将锁的语义实现,然后在锁的实现中聚合同步器。可以这样理解:锁的API是面
向使用者的,它定义了与锁交互的公共行为,而每个锁需要完成特定的操作也是透过这些行为来完成的(比如:
可以允许两个线程进行加锁,排除两个以上的线程),但是实现是依托给同步器来完成;同步器面向的是线程访
问和资源控制,它定义了线程对资源是否能够获取以及线程的排队等操作。锁和同步器很好的隔离了二者所需要关
注的领域,
还记得概述里讲的AQS只是一个框架,具体资源的获取/释放方式交由自定义同步器去实现吗?就是这里了!
AQS这里只定义了一个接口,具体资源的获取交由自定义同步器去实现了(通过state的get/set/CAS)!
至于能不能重入,能不能加塞,那就看具体的自定义同步器怎么去设计了!当然,自定义同步器在进行资源访
问时要考虑线程安全的影响。
JCP(Java Community Process) 是一个开放的国际组织,主要由Java开发者以及被授权者组成,职能是发展和更新。
AQS产生背景
通过JCP的JSR166规范,Jdk1.5开始引入了j.u.c包,这个包提供了一系列支持并发的组件。这些组件是一系列的
同步器,这些同步器主要维护着以下几个功能:内部同步状态的管理(例如表示一个锁的状态是获取还是释放),同步
状态的更新和检查操作,且至少有一个方法会导致调用线程在同步状态被获取时阻塞,以及在其他线程改变这个同步
状态时解除线程的阻塞。上述的这些的实际例子包括:互斥排它锁的不同形式、读写锁、信号量、屏障、Future、事件指
示器以及传送队列等。
jion会挂起当前线程,并且加塞在主线程的前面,相当于
如果线程被生成了,但还未被起动,调用它的 join() 方法是没有作用的,将直接继续向下执行
Join方法实现是通过wait(小提示:Object 提供的方法)。 当main线程调用t.join时候,main线程会获得线程对象
t的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程 ,
比如退出后。这就意味着main 线程调用t.join时,必须能够拿到线程t对象的锁。
223、linkedhashmap
转载链接:https://blog.csdn.net/justloveyou_/article/details/71713781
hashmap+linkedlist 双向链表结构
224、oom排查
转载链接:https://www.cnblogs.com/webster1/p/7977466.html
转载链接:http://www.cnblogs.com/AloneSword/p/3584289.html
打印堆栈信息,jmap,
在服务器内存溢出时拿到当时的堆栈信息,并且使用MemoryAnalyzer进行分析
jmap -dump:format=b,file=fileName.hprof pid
拿到生成的二进制dump文件,丢进MemoryAnalyzer工具去分析
栈内存溢出:递归最容易导致内存溢出,如果是死递归会导致层次太深,栈空间存储的引用太多
225、线程安全queue
转载链接:https://blog.csdn.net/bieleyang/article/details/78027032
226、spring aop的五种通知类型
spring aop通知(advice)分成五类:
前置通知[Before advice]:在连接点前面执行,前置通知不会影响连接点的执行,除非此处抛出异常。
正常返回通知[After returning advice]:在连接点正常执行完成后执行,如果连接点抛出异常,则不会执行。
异常返回通知[After throwing advice]:在连接点抛出异常后执行。
返回通知[After (finally) advice]:在连接点执行完成后执行,不管是正常执行完成,还是抛出异常,都会执行返回通知中的内容。
环绕通知[Around advice]:环绕通知围绕在连接点前后,比如一个方法调用的前后。这是最强大的通知类型,能在方法调用前后自定义一些操作。环绕通知还需要负责决定是继续处理join point(调用ProceedingJoinPoint的proceed方法)还是中断执行。
227、Mina断包粘包
转载链接:https://blog.csdn.net/u012151597/article/details/78870719
228、
prv:一串有规律的数,其中有一个是错的,把它挑出来 利用数组下标
1024个字母,取出重复个数最多的,定义一个200的数组,利用数组将字母转数字,然后在对应下标上加1,然后再两两比较取出最大的,这个时间复杂度是o(1)
2g数据怎么排序快,按照随机取十个基准,然后把数据放到这些区段里面再在这里面各自排序
spring框架怎么外接接口,连接外部的接口
自定义启动顺序?
springboot启动顺序
redis锁
数据库设计三大范式
转载链接:http://www.cnblogs.com/linjiqin/archive/2012/04/01/2428695.html
数据库设计三大范式
为了建立冗余较小、结构合理的数据库,设计数据库时必须遵循一定的规则。在关系型数据库中这种规则就称为范式。范式是符合某一种设计要求的总结。要想设计一个结构合理的关系型数据库,必须满足一定的范式。
在实际开发中最为常见的设计范式有三个:
1.第一范式(确保每列保持原子性)
第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。
2.第二范式(确保表中的每列都和主键相关)
第二范式在第一范式的基础之上更进一层。第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。
3.第三范式(确保每列都和主键列直接相关,而不是间接相关)
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
mybatis延迟加载
转载链接:https://blog.csdn.net/qq_35242910/article/details/78136435
一般而言,动态代理分为两种,一种是JDK反射机制提供的代理,另一种是CGLIB代理。在JDK代理,必须提供接口,
而CGLIB则不需要提供接口,在Mybatis里两种动态代理技术都已经使用了,在Mybatis中通常在延迟加载的时候才会用到
CGLIB动态代理。
transient:(防止变量被序列化)
java语言的关键字,变量修饰符,如果用transient声明一个实例变量,当对象存储时,它的值不需要维持。换句话来说就是,用transient关键字标记的成员变量不参与序列化过程。
constraint:约束
主键:唯一非空 唯一索引:唯一可空
建唯一索引两种方式
alter table department add constraint idx_xx unique(xx);
create unique index idx_xx on department(xx);
快速排序:排序:转载链接:https://www.cnblogs.com/hjy9420/p/5032309.html
书名:java虚拟机规范(第2版)
转载链接:https://www.cnblogs.com/bluestorm/p/5712238.html
进程可以简单分为系统进程和用户进程
转载链接:https://www.cnblogs.com/yiRain1992/p/9079989.html
转载链接:https://www.cnblogs.com/sooj/p/3229637.html
转载链接:https://blog.csdn.net/m0_37814112/article/details/78633136
MYISAM&innodb区别以及应用场景
安全方面-行表锁,事务 读写阻塞(也就是表锁行锁的表现) 缓存索引或数据 。单写单读大量也可以用ayisam,如果读写都大量就innodb
转载链接:https://blog.csdn.net/moran_lei/article/details/79700264 一般高并发不用外键,省得还要判断关联外键列的规范性
tomcat一般默认250个线程,但是能支持子线程就可以达到瞬时一千多个并发量了 websphere跟weblogic一样是web容器,自身占用的线程就有几百。
230、springcloud原理 待加载TODO
转载链接:https://blog.csdn.net/shinlyzsljay/article/details/79162270
Dashboard:仪表盘 hystrix [hɪst’rɪks] [医] 高起[鱼]鳞癣;Turbine 英 [ˈtɜ:baɪn] 涡轮机; 汽轮机; 透平机;
Ribbon,客户端负载均衡,重试机制。
Hystrix,客户端容错保护,服务熔断、请求缓存、请求合并、依赖隔离。
Feign,声明式服务调用,本质上就是Ribbon+Hystrix(优化代码,避免直接使用RestTemplate的混乱)
Bus,消息总线,配合Config仓库修改的一种Stream实现,
独自启动不需要依赖其它组件。
Eureka,服务注册中心,特性有失效剔除、服务保护。
Dashboard,Hystrix仪表盘,监控集群模式和单点模式,其中集群模式需要收集器Turbine配合。
Zuul,API服务网关,功能有路由分发和过滤
231、springboot原理
转载链接:https://blog.csdn.net/liutong123987/article/details/79415492 TODO 自动加载待看
启动流程主要分为三个部分,第一部分进行SpringApplication的初始化模块,配置一些基本的环境变量、资源、构造器、监听器,
第二部分实现了应用具体的启动方案,包括启动流程的监听模块、加载配置环境模块、及核心的创建上下文环境模块,
第三部分是自动化配置模块,该模块作为springboot自动配置核心
Springboot的启动,主要创建了配置环境(environment)、事件监听(listeners)、应用上下文(applicationContext),
并基于以上条件,在容器中开始实例化我们需要的Bean,
232、 main方法启动流程
转载链接:https://www.cnblogs.com/trgl/p/7353782.html
SpringBoot启动类
首先进入run方法
run方法中去创建了一个SpringApplication实例,在该构造方法内,我们可以发现其调用了一个初始化的initialize方法
这里主要是为SpringApplication对象赋一些初值。构造函数执行完毕后,我们回到run方法
该方法中实现了如下几个关键步骤:
1.创建了应用的监听器SpringApplicationRunListeners并开始监听
2.加载SpringBoot配置环境(ConfigurableEnvironment),如果是通过web容器发布,会加载StandardEnvironment,其最终也是继承了ConfigurableEnvironment,类图如下
可以看出,Environment最终都实现了PropertyResolver接口,我们平时通过environment对象获取配置文件中指定Key对应的value方法时,就是调用了propertyResolver接口的getProperty方法
3.配置环境(Environment)加入到监听器对象中(SpringApplicationRunListeners)
4.创建run方法的返回对象:ConfigurableApplicationContext(应用配置上下文),我们可以看一下创建方法:
方法会先获取显式设置的应用上下文(applicationContextClass),如果不存在,再加载默认的环境配置(通过是否是web environment判断),默认选择AnnotationConfigApplicationContext注解上下文(通过扫描所有注解类来加载bean),最后通过BeanUtils实例化上下文对象,并返回,ConfigurableApplicationContext类图如下:
主要看其继承的两个方向:
LifeCycle:生命周期类,定义了start启动、stop结束、isRunning是否运行中等生命周期空值方法
ApplicationContext:应用上下文类,其主要继承了beanFactory(bean的工厂类)
5.回到run方法内,prepareContext方法将listeners、environment、applicationArguments、banner等重要组件与上下文对象关联
6.接下来的refreshContext(context)方法(初始化方法如下)将是实现spring-boot-starter-(mybatis、redis等)自动化配置的关键,包括spring.factories的加载,bean的实例化等核心工作。
refresh方法
配置结束后,Springboot做了一些基本的收尾工作,返回了应用环境上下文。回顾整体流程,Springboot的启动,主要创建了配置环境(environment)、事件监听(listeners)、应用上下文(applicationContext),并基于以上条件,在容器中开始实例化我们需要的Bean,至此,通过SpringBoot启动的程序已经构造完成,接下来我们来探讨自动化配置是如何实现。
233、排序
转载链接:https://blog.csdn.net/zuoluoboy/article/details/4123943
234、未归类
栈是链式存储的、先进后出、对栈的插入删除操作,不需要改变栈底指针
线程优先级,在创建线程后的任意时刻都可以设置
jdk新特性 1.71.8对比
unicode是用16位来表示一个字的
IDEA 类图功能使用方法
转载链接:https://www.cnblogs.com/imsoft/p/6972612.html
IDEA 类图功能使用方法 1. Ctrl+Shift+Alt+U显示类图
idea uml类图
转载链接:https://www.cnblogs.com/LDZZDL/p/9061603.html
形参可以有修饰符,抽象方法不能有方法体,
clone是list的深拷贝、数组copyOf深拷贝
system.arraycopy一维数组是深拷贝,二维数组是浅拷贝
transient 排除被序列化字段,放在属性前面
236、union和union all
union去重,union all 不去重
union和union all的区别是,union会自动压缩多个结果集合中的重复结果,而union all则将所有的结果全部显示出来,不管是不是重复。
union 和 union all都可以将多个结果集合并,而不仅仅是两个,你可以将多个结果集串起来。
使用union和union all必须保证各个select 集合的结果有相同个数的列,并且每个列的类型是一样的。但列名则不一定需要相同,oracle会
将第一个结果的列名作为结果集的列名。
237、多个定时器怎么实现只执行一个
用mysql行级锁是实现
直接语句后面加for update 就直接锁住了一行,而已定义一个参数,哪个定时器来修改就记录下修改的定时器信息,然后其他定时
器发现这个信息就不修改了
用springboot-redis实现
转载链接:https://blog.csdn.net/huyang1990/article/details/78551578
集群服务器下使用SpringBoot @Scheduled注解定时任务
SpringBoot提供了 Schedule模块完美支持定时任务的执行
在实际开发中由于项目部署在分布式或集群服务器上 会导致定时任务多次触发
因此,使用redis分布锁机制可以有效避免多次执行定时任务
核心方法是org.springframework.data.redis.core包下的
setIfAbsent() 方法 返回值为布尔类型
方法类似redis的SETNX命令 即”SET if Not Exists”
服务器在执行邮件定时发送任务之前会向redis缓存中写入lock_key即任务锁 表明此服务器正在执行定时任务
另一台服务器在写入锁时 由于锁已经存在就不做任何操作
执行定时任务的服务器在执行完成后需释放任务锁
转载链接:http://412887952-qq-com.iteye.com/blog/2369020
quartz也行,不过貌似配置麻烦
238、mybatis
3种缓存,session、mapper,redis等 mapperxml级别的,这个对于分布式有坏处,只在一台机器上使用,会导致脏数据。因为别的
机器没更新到。
继承。。重写statement&resultset
TODO
239、springboot远程调试服务器
test服务器:用这个命令启动 java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8090 -jar eim-web-1.0-SNAPSHOT.jar --spring.profiles.active=test
IDEA本地:Edit Configuration 添加一个Remote,在Host Port上配置响ip端口,直接点击debug模式就连上了test服务
webBrowser访问服务器test-test由于是xdebug模式启动的,而且本地idea连接上了test服务,本地会告诉test打了哪些断点,test
走到断点的地方就停下,并共享消息给本地服务。
240、新生代、生活区大小计算
-Xmx10240m -Xms10240m -Xmn5120m -XXSurvivorRatio=3,其最小内存值和Survivor区总大小分别是()
10240m,2048m
-Xmx10240m:代表最大堆
-Xms10240m:代表最小堆
-Xmn5120m:代表新生代
-XXSurvivorRatio=3:代表Eden:Survivor = 3 根据Generation-Collection算法(目前大部分JVM采用的算法),一般根据对象的生
存周期将堆内存分为若干不同的区域,一般情况将新生代分为Eden ,两块Survivor;计算Survivor大小, Eden:Survivor = 3,
总大小为5120,3x+x+x=5120 x=1024
241、跨域
转载链接:https://www.cnblogs.com/alvinwei1024/p/4626054.html
浏览器为了保证资源安全,访问同源的资源是被浏览器允许的,但是如果访问不同源的资源,浏览器默认是不允许的。访问不同源的资源那就是我们所说的跨域
如果不限制跨域,页面发生混乱,甚至信息被获取,包括服务器端发来的session
域名,子域名,端口号,协议不同都属于不同源,当脚本被认为是来至不同源时,均被浏览器拒绝请求。
src可以跨域
在这里需要注意的是,文档中的所有带“src”属性的标签都可以跨域加载资源,而不受同源策略的限制。
如 ,对于页面来说,a.js是运行在b.com上的,因此对于当前页面来说,a.js的源(Origin)是b.com而不是a.com。
因此页面内存放的资源的域a.com并不重要,重要的是加载资源的页面所在的域b.com。
242、即时编译器JIT(JIT compiler,just-in-time compiler)
转载链接:https://www.sohu.com/a/169704040_464084
解析器跟编译器混合。编译器把所有代码都编译一遍,解析器能即时解析每一行代码,编译全部导致启动慢,解析每一行又缺少代码编译优化。
243、idea破解网址
转载链接:http://baijiahao.baidu.com/s?id=1577366184628834141&wfr=spider&for=pc
转载链接:http://39.106.193.3:1027
245、String.intern()
转载链接:https://www.cnblogs.com/Kidezyq/p/8040338.html
是否真正理解了String的不可变性、String常量池的设计以及String.intern方法所做的事情。
上面是jdk源码中对intern方法的详细解释。简单来说就是intern用来返回常量池中的某字符串,如果常量池中已经存在该字符串,则直接返回常量池中该对象的引用。否则,在常量池中加入该对象,然后 返回引用。下面的一个例子详细的解释了intern的作用过程:
How—String.intern方法在jdk1.7之前和之后的区别:
简单的说其实就一个:在jdk1.7之前,字符串常量存储在方法区的PermGen Space。在jdk1.7之后,字符串常量重新被移到了堆中。
Back—重回String设计的初衷:
Java中的String被设计成不可变的,出于以下几点考虑:
1. 字符串常量池的需要。字符串常量池的诞生是为了提升效率和减少内存分配。可以说我们编程有百分之八十的时间在处理字符串,而处理
的字符串中有很大概率会出现重复的情况。正因为String的不可变性,常量池很容易被管理和优化。
2. 安全性考虑。正因为使用字符串的场景如此之多,所以设计成不可变可以有效的防止字符串被有意或者无意的篡改。从java源码中String
的设计中我们不难发现,该类被final修饰,同时所有的属性都被final修饰,在源码中也未暴露任何成员变量的修改方法。(当然如果我们想
,通过反射或者Unsafe直接操作内存的手段也可以实现对所谓不可变String的修改)。
3. 作为HashMap、HashTable等hash型数据key的必要。因为不可变的设计,jvm底层很容易在缓存String对象的时候缓存其hashcode,这样
在执行效率上会大大提升。
String的intern()方法会查找在字符串常量池中是否存在一份equals相等的字符串,如果有则返回该字符串在常量池中的引用,如果没有则
添加自己的字符串进入常量池,然后再返回该字符串在字符串常量池中的引用。
运行时常量池相对于CLass文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预
置入CLass文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用比较多的就
是String类的intern()方法。
总结:jdk1.6的环境下使用intern()方法后,String对象只会引用或创建在字符串常量池中的对象。
jdk1,7的环境下使用intern()方法后,String对象需要注意所引用的是字符串常量池中的还是堆中的对象。
然后intern()方法的作用上,用一句话概括的话就是:intern()方法设计的初衷就是为了重用String对象,以节省内存消耗。
jdk1.8估计也是跟1.6一样的,这个方法只会引用常量池中的对象
246、快速排序及优化
转载链接:https://blog.csdn.net/Yexiaofen/article/details/78018204
转载链接:http://www.cnblogs.com/noKing/archive/2017/11/29/7922397.html
prv:定义一个低位i一个高位j,以最低位作为基数位(key),将比key小的放key左边,比key大的放key右边,最后把基准值放中间。
然后将左边跟右边同理各自按这种方式排序一遍。
从左往右找比key大的,从右往左找比key小的,交换两者位置,继续比较直到i>=j,交换key跟i的位置,也就是把基准值放中间。
int[] a = {1, 2, 4, 5, 7, 4, 5 ,3 ,9 ,0};
quickSort(a, 0 , a.length-1);
private static void quickSort(int[] a, int low, int high) {
//1,找到递归算法的出口
if( low > high) { return; }
//2, 存
int i = low; int j = high;
//3,key
int key = a[ low ];
//4,完成一趟排序
while( i< j) {
//4.1 ,从右往左找到第一个小于key的数
while(i<j && a[j] > key){ j–; }
// 4.2 从左往右找到第一个大于key的数
while( i<j && a[i] <= key) { i++; }
//4.3 交换
if(i<j) { int p = a[i]; a[i] = a[j]; a[j] = p; }
}
// 4.4,调整key的位置
int p = a[i]; a[i] = a[low]; a[low] = p;
//5, 对key左边的数快排
quickSort(a, low, i-1 );
//6, 对key右边的数快排
quickSort(a, i+1, high);
}
}
247、top命令
转载链接:http://www.cnblogs.com/nanqiang/p/8116888.html
显示内容解释:
第一行top分别为:当前时间;系统运行天数;使用者个数;系统负载的平均值,后面的三个值分别为1分钟前、5分钟前、15分钟前进程的平均数,这个数值超过 CPU 数目时,说明负载过高
第二行Tasks分别为:进程总数;运行进程数;睡眠进程数;被停止的进程数;被复原的进程数
第三行CPU(s)分别为:cpu使用率;
第四行Mem分别为:总内存;已用内存;空闲内存;缓冲使用中内存
第五行(Swap):类似第四行,但反映着交换分区(Swap)的使用情况。交换分区(Swap)被频繁使用,可以看作物理内存不足而造成的
中间是内部命令提示行:
h - 显示帮助
l - 关闭或开启第一部分第一行 top 信息的表示
t - 关闭或开启第一部分第二行 Tasks 和第三行 Cpus 信息的表示
m - 关闭或开启第一部分第四行 Mem 和 第五行 Swap 信息的表示
N - 以 PID 的大小的顺序排列表示进程列表
P - 以 CPU 占用率大小的顺序排列进程列表
M - 以内存占用率大小的顺序排列进程列表
s - 内容更新频率
n - 设置在进程列表所显示进程的数量
q - 退出 top
配合使用pmap -d + 进程号;查看进程占用内存情况
或者ps -e -o ‘pid,comm,args,pcpu,rsz,vsz,stime,user,uid’
free命令:
free命令参数:
-t 显示total行;
-b,-k,-m显示单位分别为B,KB,MB
-s,实时更新,如:free -m -s2(每2秒更新一次,显示单位Mb)
248、datasource配置&最大连接数&参数优化
maxActive最大连接池数量默认是8,最大貌似是可以设置到500
转载链接:https://blog.csdn.net/baiducheng/article/details/77973225
转载链接:https://blog.csdn.net/xingkong22star/article/details/48730823
MySQL默认的最大连接数为100,MySQL服务器允许的最大连接数16384
比如一台MySQL服务器最大连接数是650,没有达到服务器连接数上限650,应该不会出现oo many connections(1040)错误,比较理想
的设置是:Max_used_connections / max_connections * 100% ≈ 85%
最大连接数占上限连接数的85%左右,如果发现比例在10%以下,MySQL服务器连接上限就设置得过高了。
max_connections = 768
#指定MySQL允许的最大连接进程数。如果在访问论坛时经常出现Too Many Connections的错误提 示,则需要增大该参数值。
MYSQL参数优化:BACK_LOG
* 修改back_log参数值:由默认的50修改为500.(每个连接256kb, 占用:125M)
back_log=500
查看mysql 当前系统默认back_log值,命令:
show variables like ‘back_log’;
back_log值指出在MySQL暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中。也就是说,如果MySql的连接数达到
max_connections时,新来的请求将会被存在堆栈中,以等待某一连接释放资源,该堆栈的数量即back_log,如果等待连接的数量
超过back_log,将不被授予连接资源。将会报:
unauthenticated user | xxx.xxx.xxx.xxx | NULL | Connect | NULL | login | NULL 的待连接进程时.
back_log值不能超过TCP/IP连接的侦听队列的大小。若超过则无效,查看当前系统的TCP/IP连接的侦听队列的大小命令:cat /proc
/sys/net/ipv4/tcp_max_syn_backlog,目前系统为1024。对于Linux系统推荐设置为大于512的整数。
修改系统内核参数,可以编辑/etc/sysctl.conf去调整它。如:net.ipv4.tcp_max_syn_backlog = 2048,改完后执行sysctl -p
让修改立即生效。
249、Tomcat调优总结
转载链接:https://www.cnblogs.com/ddcoder/articles/8284073.html
Tomcat 优化分为系统优化,Java虚拟机调优,Tomcat本身的优化。
1.如何调整tomcat的占用内存
A: 方法如下:
1. linux 下编辑tomcat安装目录下的bin目录下的catalina.sh文件,windows下为catalina.bat
vi catalina.sh
2. 查找到tomcat内存参数一行:/ JAVA_OPTS,如果找不到则在第一行写上
3. 将JAVA_OPTS="-Xms 1024m –Xmx 1520m"一行的两个参数依据服务器实际内存数量分别进行更改:
- Xms为tomcat启动初始内存,一般为服务器开机后可用空闲内存减去100M
- Xmx为tomcat最大占用内存,一般为服务器开机后可用空闲内存减去50M
一般说来,您应该使用物理内存的 80% 作为堆大小。
说明:以上两个参数关系到tomcat承受的访问性能,但也要根据服务器实际内存情况设定。
有人建议Xms和Xmx的值取成一样比较好,说是可以加快内存回收速度。但未经本人验证过。有兴趣可以试试。
这两个值的大小一般根据需要进行配置。初始化堆的大小执行了虚拟机在启动时向系统申请的内存的大小。一般而言,这个参数不重要
。但是有的应用程式在大负载的情况下会急剧地占用更多的内存,此时这个参数就是显得很重要,假如虚拟机启动时配置使用的内存比
较小而在这种情况下有许多对象进行初始化,虚拟机就必须重复地增加内存来满足使用。由于这种原因,我们一般把-Xms和-Xmx设为
相同大,而堆的最大值受限于系统使用的物理内存。一般使用数据量较大的应用程式会使用持久对象,内存使用有可能迅速地增长。当
应用程式需要的内存超出堆的最大值时虚拟机就会提示内存溢出,并且导致应用服务崩溃。因此一般建议堆的最大值配置为可用内存的
最大值的80%。
Tomcat默认能够使用的内存为128MB,在较大型的应用项目中,这点内存是不够的,需要调大。
Windows下,在文档/bin/catalina.bat,Unix下,在文档/bin/catalina.sh的前面,增加如下配置:
JAVA_OPTS=’-Xms【初始化内存大小】 -Xmx【能够使用的最大内存】’
需要把这个两个参数值调大。例如:
JAVA_OPTS=’-Xms256m -Xmx512m’
表示初始化内存为256MB,能够使用的最大内存为512MB。
另外需要考虑的是Java提供的垃圾回收机制。虚拟机的堆大小决定了虚拟机花费在收集垃圾上的时间和频度。收集垃圾能够接受的速度
和应用有关,应该通过分析实际的垃圾收集的时间和频率来调整。假如堆的大小很大,那么完全垃圾收集就会很慢,但是频度会降低。
假如您把堆的大小和内存的需要一致,完全收集就很快,但是会更加频繁。调整堆大小的的目的是最小化垃圾收集的时间,以在特定的
时间内最大化处理客户的请求。在基准测试的时候,为确保最好的性能,要把堆的大小设大,确保垃圾收集不在整个基准测试的过程中
出现。
假如系统花费很多的时间收集垃圾,请减小堆大小。一次完全的垃圾收集应该不超过 3-5 秒。假如垃圾收集成为瓶颈,那么需要指定
代的大小,检查垃圾收集的周详输出,研究 垃圾收集参数对性能的影响。一般说来,您应该使用物理内存的 80% 作为堆大小。当增
加处理器时,记得增加内存,因为分配能够并行进行,而垃圾收集不是并行的。
2.如何调整tomcat的线程参数
A: 方法如下:
5.编辑tomcat安装目录下的conf目录下的server.xml文件
在tomcat配置文件server.xml中的配置中,和连接数相关的参数有:
maxThreads=“150” 表示最多同时处理150个连接,Tomcat使用线程来处理接收的每个请求。这个值表示Tomcat可创建的最大的
线程数。默认值200。
minSpareThreads=“25” 表示即使没有人使用也开这么多空线程等待
maxSpareThreads=“75” 表示如果最多可以空75个线程,例如某时刻有80人访问,之后没有人访问了,则tomcat不会保留80
个空线程,而是关闭5个空的。 (一旦创建的线程超过这个值,Tomcat就会关闭不再需要的socket线程。默认值50。
)
acceptCount=“100” 当同时连接的人数达到maxThreads时,还可以接收排队的连接数量,超过这个连接的则直接返回拒绝连
接。(指定当任何能够使用的处理请求的线程数都被使用时,能够放到处理队列中的请求数,超过这个数的请求将不予处理。默认
值100。 )
其中和最大连接数相关的参数为maxThreads和acceptCount。如果要加大并发连接数,应同时加大这两个参数。
web server允许的最大连接数还受制于操作系统的内核参数设置,通常Windows是2000个左右,Linux是1000个左右。tomcat5中的
配置示例:
主要是调整maxThreads 和acceptCount的值
对于其他端口的侦听配置,以此类推。
在tomcat配置文档server.xml中的配置中,和连接数相关的其他参数有:
enableLookups:
是否反查域名,默认值为true。为了提高处理能力,应配置为false
connnectionTimeout:
网络连接超时,默认值60000,单位:毫秒。配置为0表示永不超时,这样配置有隐患的。通常可配置为30000毫秒。
maxKeepAliveRequests:
nginx动态的转给tomcat,nginx是不能keepalive的,而tomcat端默认开启了keepalive,会等待keepalive的timeout,默认
不设置就是使用connectionTimeout。
所以必须设置tomcat的超时时间,并关闭tomcat的keepalive。否则会产生大量tomcat的socket timewait。
maxKeepAliveRequests="1"就可以避免tomcat产生大量的TIME_WAIT连接,从而从一定程度上避免tomcat假死。
试试设置tomcat/conf/server.xml:
maxKeepAliveRequests=“1”
connectionTimeout=“20000”
maxKeepAliveRequests="1"表示每个连接只响应一次就关闭,这样就不会等待timeout了。
bufferSize:
输入流缓冲大小,默认值2048 bytes。
205、信号量使用
prv:控制多线程对有效资源的访问,感觉跟令牌算法有点像
转载链接:http://www.cnblogs.com/XHJT/p/3910406.html
java Semaphore 信号量的使用:
在java中,提供了信号量Semaphore的支持。
Semaphore类是一个计数信号量,必须由获取它的线程释放,
通常用于限制可以访问某些资源(物理或逻辑的)线程数目。
一个信号量有且仅有3种操作,且它们全部是原子的:初始化、增加和减少
增加可以为一个进程解除阻塞;
减少可以让一个进程进入阻塞。
信号量维护一个许可集,若有必要,会在获得许可之前阻塞每一个线程:
//从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞。
acquireUninterruptibly(int permits){}
每一个release()添加一个许可,从而可能释放一个正在阻塞的获取者。
Semaphore只对可用许可的号码进行计数,并采取相应的行动。
如何获得Semaphore对象?
public Semaphore(int permits,boolean fair)
permits:初始化可用的许可数目。
fair: 若该信号量保证在征用时按FIFO的顺序授予许可,则为true,否则为false;
如何从信号量获得许可?
public void acquire() throws InterruptedException
如何释放一个许可,并返回信号量?
public void release()
代码实例:
20个人去银行存款,但是该银行只有两个办公柜台,有空位则上去存钱,没有空位则只能去排队等待
复制代码
面试题思考:
在很多情况下,可能有多个线程需要访问数目很少的资源。假想在服务器上运行着若干个回答客户端请求的线程。这些线程需要连接到同一数据库,但任一时刻
只能获得一定数目的数据库连接。你要怎样才能够有效地将这些固定数目的数据库连接分配给大量的线程?
答:1.给方法加同步锁,保证同一时刻只能有一个人去调用此方法,其他所有线程排队等待,但是此种情况下即使你的数据库链接有10个,也始终只有一个处于使
用状态。这样将会大大的浪费系统资源,而且系统的运行效率非常的低下。
2.另外一种方法当然是使用信号量,通过信号量许可与数据库可用连接数相同的数目,将大大的提高效率和性能。
206、netstat
转载链接:http://www.cnblogs.com/wayne173/p/5652043.html
Linux使用netstat命令查看并发连接数
我们的网站部署在linux的服务器上,特别是web服务器,我们可能有时候做为运维人员,肯定是要查看网站的并发连接数是不是达到瓶
颈等,所以在linux下,我们如何查看服务器的并发连接数呢?使用以下命令即可分组查看各种连接状态哦:
netstat -n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’
复制代码
解释:
返回结果示例:
LAST_ACK 5 (正在等待处理的请求数)
SYN_RECV 30
ESTABLISHED 1597 (正常数据传输状态)
FIN_WAIT1 51
FIN_WAIT2 504
TIME_WAIT 1057 (处理完毕,等待超时结束的请求数)
状态:描述
CLOSED:无连接是活动的或正在进行
LISTEN:服务器在等待进入呼叫
SYN_RECV:一个连接请求已经到达,等待确认
SYN_SENT:应用已经开始,打开一个连接
ESTABLISHED:正常数据传输状态
FIN_WAIT1:应用说它已经完成
FIN_WAIT2:另一边已同意释放
ITMED_WAIT:等待所有分组死掉
CLOSING:两边同时尝试关闭
TIME_WAIT:另一边已初始化一个释放
LAST_ACK:等待所有分组死掉
复制代码
使用这上面的命令是可以查看服务器的种连接状态,其中ESTABLISHED 就是并发连接状态的显示数的了。如果你不想查看到这么多连接状态,而仅仅只是想查看并发连接数,可以简化一下命令,即:
netstat -nat|grep ESTABLISHED|wc -l
1164
这个返回的数字就是当前并发的连接数的了。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。