即将实习的应届毕业生 学习java SpringMVC 数据库 知识总结

即将实习的应届毕业生 学习java SpringMVC 数据库 知识总结

1、Java语言的优点:

1)Java是纯面向对象语言

2)与平台无关性,一次编译到处运行

3)Java提供了狠多内置类库

4)提供了对web应用的支持

5)具有较好的安全性(数组边界检测、Bytecode检测)和健壮性(强制型机制、垃圾回收器、异常处理)

6)去除c++难以理解的一些特性(头文件 指针 运算符重载 多重继承)

2、java与c++的异同:

1)Java为解释型语言,c++为编译型语言,java会慢但是跨平台

2)Jave为纯面向对象,c++既面向对象又能面向过程。Jave无全局变量和全局函数

3)Java没有指针,更安全

4)Java不支持多继承但是有接口概念

5)Java不需人工分配管理内存(申请 释放),提供垃圾回收器自动回收。当堆栈或静态存储区没有对这个对象的引用时,就会被回收。没有析构函数,但是有finalize()方法。

6)Java没有运算符重载,没有预处理功能。

3、public static void main(String [] args)是程序的入口。

4、java可有多个main()文件,但只有与文件名相同的用public修饰的类的main()才能作为程序的入口。注:有且仅有一个类被public修饰并与文件同名。

5、静态快在main函数之前执行。初始化执行顺序:父静态变量 父静态代码块 子静态代码变量 子静态代码块 父非静态变量 父非静态代码块 父类构造函数 子非静态变量 子非静态代码块 子类构造函数

6、构造函数:

1)与类同名,无返回值

2)可以有多个,根据参数不同

3)总是伴随new操作一起调用

4)主要用来初始化对象

5)不能被继承

6)可用super来显示调用父类构造函数

7、浅复制仅仅复制考虑的对象,不复制它引用的对象。深复制两者都复制

8、面向对象和面向过程有什么不同:

1)面向对象是用符合常规思维的方式去处理客观世界的问题,面向过程是则重以事件为中心,模块化。

2)面向对象是使计算机世界向客观世界靠拢,使问题的处理更清晰。面向过程是清晰准确表达过程的模块,把客观世界的问题抽象成计算机可以处理的过程。

9、面向对象的特征和优点:抽象 继承 封装 多态有较高的开发效率,代码可重用。较高的可维护性,代码更清晰明了。

10、java只支持单根继承,extends继承是 is a 关系,组合是 has a关系。

在java语言中能用到组合的尽量不要用继承。

11、多态:

重载(同个类中有多个同名方法) 水平关系

重写(子类重写父类,方法名和参数列表相同) 垂直关系

12、抽象类和接口的异同:

1)只要包含一个抽象方法都是抽象类,接口的方法全部是抽象方法,称为纯抽象类。

2)抽象类的子类需实现父类的抽象方法。

3)接口中的变量都默认为:static final 必须赋初值。

4)接口实现用implements。一个类可以实现多个接口实现类似多继承的关系。

5)接口被运用于常用的功能,如:添加删除。抽象类用于生活公共类的角色,不适用经常对代码修改的情况

13、this和super的区别:

This用来指向当前实例对象

Super用来访问父类的方法和成员变量

子类继承父类时,子类构造函数中super()必须放第一句。

14、break continue return 的区别:

Break 用于直接强行跳出当前循环,不执行剩余代码

Continue 用于停止当次循环,回到起始处进行下次循环。

Return 跳转 用来表示从一个方法中返回。

Break out跳出多重循环

15、static的作用:

a 为对象分配单一的存储空间,与创建对象个数无关

b 实现某个方法或属性和类而不是与对象关联在一起

C 变量可达到全局的效果,在内存中只有一个复制

16、不可变类的实现:

类中的所有成员变量被private修饰

没有写set方法

类定义final

17、值传递和引用传递的区别:

值传递:实参会把它的值传递给形参

引用传递:传递的是对象,形参和实参指向同个存储单元。

18、有八种基本数据类型,类型转换的优先级:byte不能与booleam互换。

19、round 表示四舍五入 ceil表示向上取整 floor表示向下取整,i++表示先执行后加

一,++i表示先加一后执行。

20、String s1=”abc”是存放在常量区

String s2=”abc”s2应用常量区的对象,不会创建新的对象。

String s3=new String(“abc”)是在堆中创建对象,

String s4=new String(“abc”)又必须在堆中创建新对象。

21、“==”与“equals”

“==”用来比较两个变量的值是否相等,如果一个变量指向饿数据是对象(引用类型),就有两块内存。对象本身占用一块内存(堆内存),变量也占用一块内存。String s4 = new String(“abc”)。变量s所对应的内存中存储的数值就是对象占用那块内存的首地址。如果想看两个变量是否指向同一个对象,即要看他们对应内存中的数值(首地址)是否相同。

equals比较的不是引用,而是数值内容,即比较的是abc。

22、数组也是对象。数组提供length属性来获取数组的长度,而String是通过length()计算。

23、异常处理

1)try catch finally模式

2)Finally块中的代码一定会被执行,除非这两种情况:当程序在try之前就遇到异常或者在try中通过exit()强制退出。

3)jvm将错误表示为一个异常并抛出,通过catch来捕获,然后进行处理。安全性和鲁棒性。

4)异常分为两大类:错误(error)和异常(Excetion)

异常分为:检查异常和运行异常。

检查异常又称为编译异常。

比如:IO异常、SQL异常

运行异常为:空指针异常、类型转换异常、算术异常、数组越界异常、数组存储异常、缓存区溢出异常。

先捕获子类后捕获父类,尽早抛出异常,能处理就处理,不处理就抛出,运行时异常实际不必处理,直接抛出。

24、Java IO:字节流(8位)不会用到缓存 字符流(16位)用到缓存

25、Socket称为套接字。用来实现不同虚拟机或不同计算机之间的通信。

分为两种类型:面向连接的TCP,可靠。无面向连接的UDP,不可靠。

任何一个Socket都是由一个IP地址和端口号唯一确定。

26、java平台独立性是指一个平台上编写和编译程序,而在其他平台上运行。有JVM和java API。

Java语言是一种动态解释型语言,类class只有被加载到JVM上才能运行。不会一次加载全部类后执行,而是先加载基类,其他类是需要时再加载。

27、垃圾回收GC:回收不会再使用的内存。三个任务:分配内存;确保被引用的内存不被错误地回收;回收不再被引用的对象的内存。

28、java中内存泄露问题:

两种情况:

1)在堆中申请的空间没有得到释放

2)对象不再被使用,但是仍在内存中保留着

原因:静态集合类、各种连接、监听器、变量不合理的作用域

29、java中堆和栈的区别:

分配在栈:基本数据类型的变量、对象的引用变量

变量出了作用域就会被自动释放

分配在堆:引用类型变量、需要通过new创建的变量。主要为运行时创建的对象

JVM是基于堆栈的虚拟机,每个java程序都运行在一个单独的JVM实例上,所以一个java程序中的对个线程运行在,每个实例又唯一对应一个堆,所以这些线程之间会共享堆内存。

只需要申请堆空间,不需要考虑释放问题。

使用栈中的引用变量来访问堆中的数组和对象。

堆只要是用来存放对象的,栈主要是用来放执行程序的。

栈的速度快,但大小和生存期确定,缺乏灵活性。堆是动态分配内存,灵活性强但速度慢。

30、容器:java Collections框架:list 、Queue 、set 、stack 、map
list 、Queue 、set 、stack都继承Collection接口。

1)List是有序的Collection。按对象的进入顺序保存对象,可保存重复对象。

2)Set是集合的概念,集合中不能有重复的元素。

3)map是键映射到值得数据结构。值可以重复,但是键是唯一的,不能重复。

31、迭代器:是一个对象,一种访问一个容器对象的各个元素,而又不必暴露该对象内部的细节方法。

1)使用容器的iterator()方法返回一个Iterator,然后通过Iterator的next()方法返回一个元素。

2)使用Iterator的hasNext()方法判断容器中是否还有元素,如果有可以使用next()获取下一个元素。

3)通过remove()来删除迭代器返回的元素。

32、collection和collections的区别:

Collection:是一个集合接口,为各个具体集合提供最大化的统一操作。

Collections:是针对集合类的一个包装类。不能实例化,相当于一个工具类,服务于Collection框架。

33、多线程:

线程:执行代码的一个执行单元。

进程:一个正在执行的程序

各线程共享程序的内存空间(代码段、数据、堆空间)有独立的栈空间。

线程优点:

1)减少程序的响应时间

2)相比进程,创建个切换开销小

3)多CPU和多核本身就具有多线程能力

4)简化程序结构,便于理解和维护。

34、如何实现java多线程:

1)继承Thread类,重写run()方法

2)实现Runnable接口,并实现接口的run()方法。

3)实现Callable接口,重写call()方法。

35、同步

要想实现同步操作,必须获得每个线程对象的锁,获得它可以保证同一时刻只有一个线程能够进入临界区,并且在这个锁被释放之前,其他线程就能再进入临界区,如果还有其他线程想要获得该对象的锁,只能进入等待队列等待。

36、多进程同步的实现方法:

1)synchronized关键字

2)Wait()方法与notify()方法

3)Lock

37、终止线程的方法:stop()方法与suspeng()方法。

Java提供两种线程:守护线程(服务进程)、用户进程。

38、如何通过JDBC来访问数据库:

1)加载JDBC驱动器,将JDBC驱动 jar包复制到lib下

2)加载JDBC驱动

3)创建数据库连接

4)建立Statement对象或是PrepareStatement对象。用于对数据库操作

5)执行SQL语句

6)访问结果集ReaultSet对象

7)依次关闭ReaultSet Statement Connection。

39、Class.forName()方法的作用是把类加载到JVM中。

在使用JDBC连接数据库之前,一般会调用Class.forName(“com.mysql.jdbc.Driver”)方法来加载驱动。
Statement用于执行不带参数的简单SQL语句,并返回它所生成结果的对象。每次执行SQL,数据库都会编译该SQL语句。
PrepareStatement可执行带参数的。效率更高,可读性,可维护性更高,安全性更好

40、JDBC提供了getString()、getInt()、getIData()等方法从ResultSet中获取数据。

41、在JDBC连接时连接池数目有限,所以一定要保证释放不再使用的连接。

createStatement和prepareStatement最好放在循环外面,而且使用statement后需要及时关闭。最好是执行一次executeQuery后马上关闭statement。

42、Hibernate是JDBC的封装。采用配置文件的形式将数据库的连接参数写到XML中,但
是最后对数据库的访问还是要通过JDBC来完成。

43、Hibernate是个持久层框架,它将表中的信息映射到XML中,再从XML文件映射到相应的持久化类中。

Java Web

1、浏览器的作用:

1)、完成与服务器端的交互。

2)、完成HTML的解析,实现用户需要看的内容以直观的信息展示出来。

2、HTTP的请求方法有:GET POST HEAD TRACE OPTIONS

GET:是最简单的请求方法,从服务器端获取用户所需的资源,并将其作为响应返回给客户端。获取服务器端的信息(查询)。若需上传数据则添加到URL后面。数据暴露安全不够,并且数量受限制。

POST:除了能够从服务器端获取资源外,同时还可以向服务器上传数据。上传的数据不是在URL中明文显示,可以上传大量数据,用户不可见

3、Servlet:

采用Java语言编写的服务器程序,运行于Web服务器中的Servlet容器中,主要功能是提供请求、响应的服务模式,可以生成动态的Web内容。

Web服务器获取到一个对servlet的请求时,会将其交给Tomcat容器进行处理,容器再通过调用Servlet的方法(doGet() doPost())来响应请求。

步骤:

发起servlet请求——>Web服务器交给容器处理——>容器创建两个对象HttpServletResponse HttpServletRequire——>创建单独线程,并将两个对象以参数形式传递进入线程——>线程容器调用Servlet的service()方法中的doGet()或doPost()完成响应——>容器将响应消息以HTML形式返回给客户。

4、Servlet的生命周期:

加载——>创建——> 初始化——> 处理客户请求——> 卸载

5、JSP的优点:

JSP:嵌入java代码的html文件。主要解决servlet与HTML的分离。实现业务逻辑与视图进行分离。

6、JSP与servlet的异同:

相同:

本质都是Servlet文件,只要是JSP能完成的工作,使用Servlet都能完成.JSP最终都是会转化为servlet来运行。

不同:

Servlet是处于控制层,主要是做流程控制和业务处理。JSP是处于视图层,主要用于显示。

Servlet没有内置对象,JSP中的内置对象主要是通过HttpServletResponse 对象、HttpServletRequire对象得到。

7、MVC模型:

模型层(M):实现系统业务逻辑。JavaBean或EJB

视图层(V):实现用户的交互。JSP

控制层(C): 实现视图与模型的逻辑控制。servlet

8、控制层:

控制器接收用户的输入并调用模型和视图去完成。

控制器本身不输出任何东西,也不执行任何处理。

只是接收请求并决定使用哪个模型去处理请求,决定使用哪个视图去显示模型处理返回数据

9、MVC的优点:

1)低耦合性,实现视图层与逻辑层分离。

2)高重用性和可适用性

3)部署迅速

4)容易维护

10、Servlet中的forward和redirect有什么区别:

Forward是服务器内部的重定向,服务器直接访问目标地址的url,地址不变。

Redirect:客户端的重定向,完全跳转,地址改变。

11、JSP的内置对象:

1)require(请求对象)

2)Response(响应对象)

3)pageContext(页面上下文对象)

4)Session(会话对象)

5)Application(应用程序对象)

6)Out(输出对象)

7)Config(配置对象)

8)Page(页面对象)

9)Exception(异常对象)

12、request对象的方法:

1)setAttribute(String name ,Object)设置name的属性值

2)getAttribute(String name )获取name的属性值

3)getParameter(String name )获取用户提交的数据,name与表单的name对应一致

4)getSession()用来获取与请求相关的会话

13、JSP中的动作:

1)JSP:include 用来页面请求时引进一个文件

2)Jsp:useBean 用来实例化一个javabean

3)Jsp:setProperty 用来设置已经实例化的bean对象的属性

4)Jsp:getProperty 用来获取已经实例化的bean对象的属性

5)Jsp:foward 用来将请求跳转到另外一个页面

14、JSP中include指令和include动作

指令:<% @include file =”test.jsp “%>

动作:

15、会话跟踪技术:

对同一个用户对服务器的连续请求和接收响应进行监视。

1)page一个页面

2)Request一个请求

3)Session 一个用户体验

4)Application 整个Web应用程序

16、字符串编码:GBK 、UTF-8

17、什么是Ajar

异步js与XML。

结合了java技术、js技术、xml技术。 客户端技术

功能:在不刷新页面的情况下通过与服务器进行少量的数据交互来提高页面的交互性,减少响应时间,改善用户体验

18、cookie和session的区别:

Session:指用来在客户端与服务器端之间保持状态的解决方案以及存储结构。

Cookie:由Web服务器保存在用户浏览器上的小文件。

19、web服务器:接收来自于客户端的请求,然后把对请求的处理结果反馈个客户端

两大web服务器:IIS Apache。

20、web容器:TomcatJBoss

负责给servlet提供http请求和响应对象,调用doGet()过doPost()方法来处理用户请求。

21、EJB的类别:

1)session Bean(会话Bean)实现服务器端的业务逻辑,协调Bean之间的交互

2)Entity Bean(实体Bean)资料组件 代表数据库中的记录

3)Message Bean(消息驱动 Bean)处理异步消息,一般不是由用户来调用的

22、EJB与Javabean的异同:

1)EJB:主要用于服务器端的开发,Javabean主要用在客户端的开发。

2)EJB组件可以部署在EJB容器中,不直接访问组件,而是通过容器访问,javabean不可部署

3)EJB是分布式对象,可以被远程调用,javabean不是,只能在内部被访问

23、EJB的角色:

1)Enterprise Bean Provider(企业级组件开发者)

2)Application Assembler(应用组合者)

3)EJB Deployer(EJB部署者)

4)EJB Sever Provider(EJB服务器提供者)

5)EJB Container Provider(EJV容器提供者)

6)System Administrator(系统管理员)

24、数据库连接池的工作机制:

原因:

1)建立数据库是非常耗时的操作

2)数据库连接个数是有限的

数据库连接池负责分配 管理 释放数据库连接。当客户需要访问数据库是,就可以直接从池中获取数据库的连接,而不用去创建连接,同时标志为忙状态。

25、JAVAEE开发的调优方法:

1)优化设计

2)尽可能使用数据库连接

3)使用框架

4)优化I/O

5)优化查询

26、struts框架的优点:

1)实现表现和逻辑的分离

2)提供页面导航功能

3)提供表单验证

4)提供数据库连接池

5)提供了异常处理机制

6)支持国际化

27、数据验证分为:

1)表单验证

2)业务逻辑验证

28、国际化:

程序在不修改内部代码的情况下,根据不同地区显示相应的界面

29、什么事控制反转:

也称依赖注入,一种降低对象之间耦合关系的设计思想。

使上层不仔依赖于下层的接口,调用者(子)决定被调用者(父)。通过注入一个实例化的对象来实现解耦和目的。

30、Spring框架

提供了对轻量级loc的良好支持,也提供对AOP技术的非常好的封装。

31、Hibernate框架,持久层框架

实现Java对象与关系数据库记录的映射,简化开发人员访问数据库的流程,提高软件开发的效率

任何使用到JDBC的都可以使用Hibernata

提高性能方法:

1)延迟加载

2)缓存技术

3)优化查询语句

32、实现分页:

1)Hibernate自带的分页机制

2)用SQL语句实现,使用limit关键字

33、SSH:

struts实现视图部分

Hibernate实现模型部分

Spring实现业务部分

采用SSH框架,不仅能实现视图、控制器与模型的彻底分离,而且还能实现业务逻辑与数据持久层的分离

1.JAVA的垮平台原理

JVM也是一个软件,不同的平台有不同的版本。我们编写的Java源码,编译后会生成一种 .class 文件,称为字节码文件。Java虚拟机就是负责将字节码文件翻译成特定平台下的机器码然后运行。也就是说,只要在不同平台上安装对应的JVM,就可以运行字节码文件,运行我们编写的Java程序。

而这个过程中,我们编写的Java程序没有做任何改变,仅仅是通过JVM这一”中间层“,就能在不同平台上运行,真正实现了”一次编译,到处运行“的目的。

JVM是一个”桥梁“,是一个”中间件“,是实现跨平台的关键,Java代码首先被编译成字节码文件,再由JVM将字节码文件翻译成机器语言,从而达到运行Java程序的目的。

注意:编译的结果不是生成机器码,而是生成字节码,字节码不能直接运行,必须通过JVM翻译成机器码才能运行。不同平台下编译生成的字节码是一样的,但是由JVM翻译成的机器码却不一样。

所以,运行Java程序必须有JVM的支持,因为编译的结果不是机器码,必须要经过JVM的再次翻译才能执行。即使你将Java程序打包成可执行文件(例如 .exe),仍然需要JVM的支持。

注意:跨平台的是Java程序,不是JVM。JVM是用C/C++开发的,是编译后的机器码,不能跨平台,不同平台下需要安装不同版本的JVM。

2.JAVA中INT占几个字节

char 占2个字节
boolean 一个字节(1位)

3.JAVA面向对象的特征

封装、抽象、继承和多态。

封装:在面向对象语言中,封装特性是由类来体现的,我们将现实生活中的一类实体定义成类,其中包括属性和行为(在Java中就是方法).例如电脑,

抽象:抽象就是将一类实体的共同特性抽象出来,封装在一个抽象类中,所以抽象在面向对象语言是由抽象类来体现的。比如人.
class Person{}

继承:继承就像是我们现实生活中的父子关系,儿子可以遗传父亲的一些特性,在面向对象语言中,就是一个类可以继承另一个类的一些特性,从而可以代码重用.
eg:class Zhangsan extends Person{};

多态:多态就是通过传递给父类对象引用不同的子类对象从而表现出不同的行为
eg:Person person=new Zhangsan();

4.装箱和拆箱

为什么需要装箱和拆箱:是java早年设计缺陷。基础类型是数据,不是对象,也不是Object的子类。

装箱就是自动将基本数据类型转换为包装器类型;拆箱就是自动将包装器类型转换为基本数据类型。

  1. Integer a = Integer.valueOf(123);//装箱
  2. int b = a.intValue(); //拆箱

5.==和EQUALS的区别

关于==
1.基本数据类型,也称原始数据类型。byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(),比较的是他们的值。
2.复合数据类型(类) 当他们用(
)进行比较的时候,比较的是他们在内存中的存放地

equals
Java 语言里的 equals方法其实是交给开发者去覆写的,让开发者自己去定义满足什么条件的两个Object是equal的。

6.String,StringBuilder,StringBuffer的区别

运行速度:StringBuilder >StringBuffer >String

String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。Java中对String对象进行的操作实际上是一个不断创建新的对象并且将旧的对象回收的一个过程,所以执行速度很慢。而StringBuilder和StringBuffer的对象是变量,对变量进行操作就是直接对该对象进行更改,而不进行创建和回收的操作,所以速度要比String快很多。

线程安全:StringBuilder是线程不安全的,而StringBuffer是线程安全的

如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。

使用场景

String:适用于少量的字符串操作的情况

StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况

StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况

7.讲一下JAVA中的集合

java中的集合分为value(Collection),和key-value(Map)两种;

存储value的有list和set两种:
list是有序的,可重复的
set是无序的,不可重复的

存储为key-value是map:HashMap,Hashtable,CurrentHashMap

8.ARRAYLIST, Vector和LINKEDLIST的区别

1.区别

Vector、ArrayList都是以类似数组的形式存储在内存中,LinkedList则以链表的形式进行存储。
Vector线程同步,ArrayList、LinkedList线程不同步。
LinkedList适合指定位置插入、删除操作,不适合查找;ArrayList、Vector适合查找,不适合指定位置的插入、删除操作。
Vector默认扩充为原来的两倍,(每次扩充空间的大小是可以设置的),而ArratList默认扩充为原来的1.5倍(查看之前的文章),因此ArrayList更节省空间。

2.联系

ArrayList,Vector、LinkedList类均在java.util包中都是可改变大小的.

ArrayList和Vector都是基于存储元素的Object[ ] array 来实现的,他们会在内存中开辟一块连续的空间来存储,由于数据存储是连续的,因此,他们支持用索引来访问元素,同时索引数据的速度比较快。但是在插入元素时需要移动容器中的元素,所以对数据的插入操作执行的比较慢。ArrayList和Vector都有一个初始化的容量大小,当里边存储的元素超过这个大小时就需要动态地扩充他们的存储空间。
9.HASHMAP和HASHTABLE的区别

相同:HashMap和Hashtable都可以使用来存储key-value的数据

区别:

基类不同:HashTable基于Dictionary类,而HashMap是基于AbstractMap。Dictionary是什么?它是任何可将键映射到相应值的类的抽象父类,而AbstractMap是基于Map接口的骨干实现,它以最大限度地减少实现此接口所需的工作。
线程安全:HashMap时单线程安全的,Hashtable是多线程安全的。
遍历不同:HashMap仅支持Iterator的遍历方式,Hashtable支持Iterator和Enumeration两种遍历方式。
null不同:HashMap可以允许存在一个为null的key和任意个为null的value,但是HashTable中的key和value都不允许为null。
多线程时,如何保障线程安全的同时也能保证效率?ConcurrentHashMap
通过把整个Map分为N个segment(类似Hashtable),这样既可以保障线程安全,也能使效率提高N倍,默认是16倍.
ConcurrentHashMap当中每个Segment各自持有一把锁。在保证线程安全的同时降低了锁的粒度,让并发操作效率更高。

10.实现一个拷贝文件的工具类要使用字节流还是字符串

使用字节流,因为我们要拷贝的文件,不好确定里面是否全是字符,如果文件中包含图片之类的字节时,就需要使用字节流.所以,我们一般是用字节流拷贝文件.

11.线程的的实现方式?怎么启动线程?怎么区分线程?

1.继承Thread类,不推荐

1.实现Runnable 接口

1.实现java.util.concurrent下的Callable接口

线程启动:调用start()方法;(调用start()方法,是使得线程处于可运行状态,线程并不一定会执行.如果start()方法是在main方法中调用的话,run()会执行.如果是在junit4下的话,线程不一定会执行)

怎么区分线程:给线程设置名字
1
2
3
12.线程并发库和线程池的作用

简单了解过,JDK5中增加了并发库,java.util.concurrent中提供了对线程优化.管理的各项操作,该包提供了线程的运行,线程池的创建,线程生命周期的控制.

线程池:java.util.concurrent.Executors创建四种线程池

newCachedThreadPool 创建非固定数量,可缓存的线程池,若线程池超过处理需要,可灵活回收空线程,若没有线程可回收,则建新线程
newFixedThreadPool固定线程池,底层是无界队列,可控制最大并发数,超出的线程会在队列中等待
newScheduledThreadPool定时执行线程池,支持定时及周期性任务执行
newSingleThreadExecutor单线程化的线程池,只会用唯一的工作线程来执行任务,保证所有任务按照顺序执行
线程池的好处:

限定线程的个数,不会导致由于线程过多导致系统运行缓慢或崩溃
线程池每次都不需要去创建和销毁,节约了资源
线程池不需要每次都去创建,相应时间更快.
13.设计模式和常用的设计模式(选择自己熟悉的说,最好能手写)

设计过程中可以反复使用的、可以解决特定问题的通用模板.

创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。
结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。
行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
14.HTTP GET POST请求的区别

1、GET请求,请求的数据会附加在URL之后,以?分割URL和传输数据,多个参数用&连接。URL的编码格式采用的是ASCII编码,而不是uniclde,即是说所有的非ASCII字符都要编码之后再传输。

POST请求:POST请求会把请求的数据放置在HTTP请求包的包体中。

因此,GET请求的数据会暴露在地址栏中,而POST请求则不会。

2、传输数据的大小

在HTTP规范中,没有对URL的长度和传输的数据大小进行限制。但是在实际开发过程中,对于GET,特定的浏览器和服务器对URL的长度有限制。因此,在使用GET请求时,传输数据会受到URL长度的限制。

对于POST,由于不是URL传值,理论上是不会受限制的,但是实际上各个服务器会规定对POST提交数据大小进行限制,Apache、IIS都有各自的配置。

3、安全性

POST的安全性比GET的高。这里的安全是指真正的安全,而不同于上面GET提到的安全方法中的安全,上面提到的安全仅仅是不修改服务器的数据。比如,在进行登录操作,通过GET请求,用户名和密码都会暴露再URL上,因为登录页面有可能被浏览器缓存以及其他人查看浏览器的历史记录的原因,此时的用户名和密码就很容易被他人拿到了。

15.说说你对SERVLET的理解

就是一个运行在WEB服务器上的小的Java程序,用来接收和响应从客户端发送过来的请求,通常使用HTTP协议.
使用:1、编写一个Java类,实现servlet接口。
  2、把开发好的Java类部署到web服务器中。
按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet

 Servlet            :接口
    |
 GenericServlet :通用的Servlet
    |
 HttpServlet        :HttpServlet

1
2
3
4
5

  • 编写一个类继承HttpServlet,重写doGet和doPost方法.
  • 配置

16.SERVLET的生命周期

用户第一次访问Servlet的时候,服务器会创建一个Servlet的实例,那么Servlet中init方法就会执行.任何一次请求服务器都会创建一个新的线程访问Servlet中的service的方法.在service方法内部根据请求的方式的不同调用doXXX的方法.(get请求调用doGet,post请求调用doPost).当Servlet中服务器中移除掉,或者关闭服务器,Servlet的实例就会被销毁,那么destroy方法就会执行.

17.SERVLET中FORWARD和REDIRECT的区别

重定向(redirect)其实是两次request,第一次,客户端request,A服务器响应,并response回来,告诉浏览器,你应该去B。这个时候IE可以看到地址变了,而且历史的回退按钮也亮了。重定向可以访问自己web应用以外的资源。在重定向的过程中,传输的信息会被丢失。
请求转发(forward)是服务器内部把对一个request/response的处理权,移交给另外一个.对于客户端而言,它只知道自己最早请求的那个A,而不知道中间的B,甚至C、D。传输的信息不会丢失。

18.JSP和SERVLET的相同点和不同点

联系:
JSP 是 Servlet 技术的扩展,本质上是 Servlet 的简易方式,更强调应用的外表表达。
JSP编译后是”类 servlet”。
不同点:

  • Servlet 的应用逻辑是在Java文件中,并且完全从表示层中的HTML里分离开来。Servlet如果要实现html功能,必须使用Writer输出对应的html.
  • JSP 的情况是Java和HTML可以组合成一个扩展名为.jsp 的文件。做界面展示比较方便,而嵌入逻辑复杂.
  • JSP 侧重于视图,Servlet 主要用于控制逻辑

19.jsp内置对象和四大作用域和页面传值

内置对象名 类型
request HttpServletRequest
response HttpServletResponse
config ServletConfig
application ServletContext
session HttpSession
exception Throwable
page Object(this)
out JspWriter
pageContext PageContext
域 范围
page域 只能在当前jsp页面使用
request域 只能在同一个请求中使用
session域 只能在同一个会话(session对象)中使用
context域 只能在同一个web应用中使用
20.SESSION和COOKIE的区别和使用场景

Session和cookie都是会话(session)跟踪技术.cookie通过在客户端记录信息确定用户身份,而session是通过在服务器端记录信息确定用户身份.但是session的实现依赖于cookie机制来保存JESESSIONID(session的唯一标识,需要存在客户端)

区别:

  1. cookie的数据存储在客户端,session的数据存储在服务器上
  2. cookie不是很安全,别人可以通过分析存放在本地的cookie并进行cookie欺骗,考虑到安全应该使用session
  3. session会在一定时间内保存在服务器上,当访问增多时,会影响服务器的性能.考虑到服务器性能,应当使用cookie.
  4. 单个cookie保存数据不能超过4k,很多浏览器显示一个站点最多保存20个cookie
  5. 将重要信息保存在session中(登陆),将其他需要保留的信心存放在cookie中(购物车,cookie是可以在客户端禁用的,这时候要使用cookie+数据库的方式实现购物车,当cookie中不能取出数据,就从数据库中取)

21.MVC模式和MVC各部分的实现

MVC的全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种软件设计典范.低耦合(m和v的分离)
struts2的mvc:jsp–>StrutsPrepareAndExecuteFilter(前端控制器,核心控制器)+action–>javabean–>result

22.数据库分类和常用数据库

  • 关系型:MySQL、 ORACLE、SQL Server、IBM DB2、Sybase
  • 非关系型:Redis,Memcached,MongoDB ,Hadoop

23.关系型数据库的三范式

范式就是规范,就是关系型数据库设计表时遵循的三个规范.要满足第二范式,必须先满足第一范式,要满足第三范式,必须先满足第二范式

第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。列数据的不可分割.
第二范式(2NF)要求数据库表中的每个实例或行必须可以被唯一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识.(主键)
第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。(外键)
反三范式:有时候为了效率,可以设置重复或者可推导出的字段.比如:订单(总价),订单项(单价)

24.事务的四大特征

事务是并发控制的单位,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位.例子:转账

事务的四大特性:ACID

原子性(Atomicity):表示事务内不可分割,要么都成功,要么都失败
一致性(Consistency):要么都成功,要么都失败.失败了,要对前面的操作进行回滚
隔离性(Isolation):一个事务开启了,不能受其它事务的影响
持久性(Durability):持续性,表示事务开始了,就不能终止.事务提交后,将数据序列化到数据库
25.MYSQL数据库最大连接数

数据库默认的最大连接数是100,在实际操作中,我们会去修改这个值:mysql安装文件–>my.ini文件

The maximum amount of concurrent sessions the MySQL server will

allow. One of these connections will be reserved for a user with

SUPER privileges to allow the administrator to login even if the

connection limit has been reached.

max_connections=100
1
2
3
4
5
26.MYSQL和ORACLE的分页语句

为什么要分页?很多数据不能完全展示出来,需要进行分段显示

mysql:是使用关键字limit来进行分页的.LIMIT [offset,] rows:offset指定要返回的第一行的偏移量(也就是从哪个索引开始),rows第二个指定返回行的最大数目。初始行的偏移量是0(不是1)
oracle:一般是使用rownum 加select 嵌套查询
27.触发器的使用场景?

触发器:触发器需要有触发条件,当条件满足后,做什么操作

应用场景:某些社交软件的日志更新,会通知好友; 一些论坛中,当插入新帖时,会更改当前帖子总数以及最后发帖时间.

CREATE [or REPLACE] TRIGGER 触发器名
BEFORE | AFTER
[DELETE ][[or] INSERT] [[or]UPDATE [OF 列名]]
ON 表名
[FOR EACH ROW ][WHEN(条件) ]
declare
……
begin
PLSQL 块
End ;
1
2
3
4
5
6
7
8
9
10
28.存储过程的优点

  1. 存储过程只在创建时进行编译,以后每次执行它都不会再重新编译.一般SQL语句每次执行都会编译.所以存储过程会大大提高数据库执行速度
  2. 通常复杂的业务逻辑需要多条SQL语句,这些语句要分别从客户机发送到服务器,当客户机和服务器之间的操作很多时,会产生大量的网络传输.如果将这些操作放在一个存储过程中,那么客户机和服务器之间的网络传输会大大减少,降低网络负载.
  3. 存储过程是可重复使用的,能减少数据库开发人员的工作量.
  4. 存储过程可以屏蔽对底层数据对象的直接访问,使用EXECUTE权限调用存储过程,无需拥有访问底层数据库对象的显示权限,安全性高.

CREATE [ OR REPLACE ] PROCEDURE 存储过程名称
(参数名 类型, 参数名 类型, 参数名 类型)
IS|AS
变量声明部分;
BEGIN
逻辑部分
[EXCEPTION
异常处理部分]
END;
1
2
3
4
5
6
7
8
9
29.JDBC调用存储过程

贾琏欲执事
加载驱
获取连接
设置参数
执行
释放连接

30.简单说一下你对JDBC的理解

Java database connection java数据库连接,数据库关系系统很多,每个数据库关系管理系统支持的命令是不一样的.
Java只定义接口,让数据库厂商自己实现接口,对于我们开发人员而言,只需要导入对应厂商开发的实现即可,然后以接口的方式进行调用(mysql+mysql驱动(实现)+jdbc)

31.写一个JDBC的访问ORACLE的列子

public class OracleUtils {
static {
try {
Class.forName(“oracle.jdbc.driver.OracleDriver”);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

//获取连接
public static Connection getConnection() throws SQLException {
Connection conn = DriverManager.getConnection(“jdbc:oracle:thin:@ip:1521:orcl”, “username”, “password”);
return conn;

}
//关闭资源
public static void close(ResultSet rs, Statement stmt, Connection conn) {
}
}

调用
Connection conn = OracleUtils.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery();
OracleUtils.close(rs, stmt, conn);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
32.JDBC中PREPAREDSTATEMENT比STATEMENT的好处

PreparedStatement可以防止sql注入攻击,它是预编译的,

33.数据库连接池的作用

限定数据库的连接个数,不会由于数据库连接过多导致系统运行缓慢或崩溃
数据库连接不需要每次都去创建或销毁,节约了资源
数据库连接不需要每次都去创建,响应时间更快.
34.简单说一下HTML,CSS,JAVASCRIPT在网页开发中的定位

Html 超文本标记语言,定义网页的结构
Css 层叠样式表,用来美化页面
Javascript 主要用来验证表单,做动态交互(其中ajax)

35.简单介绍了一下AJAX

什么是ajax?异步的javascript和xml
作用是什么?通过ajax与服务器进行数据交换,ajax可以使网页实现局部更新.这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新.
怎么实现?ajax xmlhttpRrqueset对象,使用这个对象可以异步向服务器发送请求,获取响应,完成局部更新,open send responseText/responseXml局部响应.
使用场景:登陆失败时不跳转页面,注册时提示用户名是否存在,二级联动等等.

36.JS和JQUERY的关系

JQuery是一个js框架,封装了js的属性和方法,并且增强了js的功能,让用户使用起来更加便利,并且增强了js的功能.
原来是使用js是要处理很多兼容性的问题(比如注册事件等),由JQuery封装了底层,就不用处理兼容性问题.
原生的js的dom和事件绑定和ajax等操作非常麻烦,JQuery封装了以后,操作非常方便.

37.JQUERY中的常用选择器

ID选择器
Class选择器
标签选择器
通用选择器
层次选择器
属性选择器

38.JQUERY中页面加载完毕事件

为什么需要页面加载事件?很多时候我们需要获取元素,但是必须等到该元素被加载后才能获取,我们可以把js代码放到该元素的后面,但是这样就会造成js在我们的body中存在不好管理.所有页面加载完毕后,所有的元素当然已经加载完毕,一般获取元素做操作都要在页面加载完毕后.
$(function{}表示的是页面结构被加载完毕
Window.onload表示的是页面被加载完毕

39.JQUERY中AJAX和原生JS实现AJAX的关系

JQuery中的ajax也是通过原生的js封装的,封装完成后让我们使用起来更加便利,不用考虑底层实现或兼容性等的处理.
如果采用原生js实现ajax是非常麻烦的,并且每次都是一样的.如果我们不适用JQuery,我们也要封装对象的方法和属性,有像JQuery这些已经封装完成,经过很多企业实践过的框架,比较可靠,我们不需要封装,直接使用成熟的框架(JQuery)即可.

40.BOOTSTRAP的是什么

Bootstrap是一个移动设备优先的UI框架.我们不用写任何的css和js代码就能实现比较漂亮的有交互性的页面.我们程序员对页面的编写是有硬伤的,所以要自己写页面的话,就要使用类似bootstrap这样的UI框架.
平时经常用的:
模态框
表单,表单项
布局
栅格系统

41.什么是框架

框架(Framework)是一个框子—–具有约束性,也是一个架子—-具有支撑性.
IT语境中的框架,特支为解决一个开放性问题而设计的具有一定约束性的支撑架构.在此结构上可以根据具体问题扩展.安插更多的组成部分.从而更迅速和更方便的构建完整的解决问题的方案.

框架本身一般不完整到可以解决特定问题,但是可以帮助我们快速解决特定问题
框架天生就是为了扩展而设计的
框架里面可以为后续扩展的组件提供很多辅助性,支撑性的方便易用的使用工具.也就是说框架时常配套; 一些帮助解决某类问题的库或工具.
42.简单介绍一下MVC模式

MVC全名是model view Controller,是模型(model)—视图(view)—控制器(Controller)的缩写,是一种软件设计典范.
最简单的,最经典的就是jsp(view)+servlet(Controller)+javabean(model)
1.当控制器收到来自用户的请求
2.控制器调用javabean完成业务
3.完成业务后通过控制器跳转jsp页面的方式给用户反馈信息
4.Jsp给用户做出响应

43.简单说一下对MVC框架的理解

是为了解决传统的MVC模式(jsp+servlet+javabean)问题而出现的框架.

传统MVC模式问题
1.所有的servlet和servlet映射都要配置在web.xml中,如果项目太大,web.xml就太庞大,并且不能实现模块化管理.
2.Servlet的主要功能就是接受参数,调用逻辑,跳转页面,比如像其他字符编码,文件上传等功能也要写在servlet中,不能让servlet功能单一.
3.接受参数比较麻烦,不能通过model接收,只能单个接收,接收完成后转换封装进model.
4.跳转页面方式比较单一(forward,redirect),并且当页面名称发生变化时,需要修改servlet源代码.

常用的MVC框架:struts2,springMVC

44.STRUTS2的执行流程或者STRUTS2的原理

1.浏览器发送请求,经过一系列的过filter,到达strutsPrepareAndExecuteFilter
2.strutsPrepareAndExecuteFilter通过ActionMapper判断当前的请求是否需要某个Action处理,如果不需要,则走原来的流程.如果需要,把请求交个ActionProxy来处理
3.ActionProxy通过Configuration Manager 询问框架的配置文件struts.xml,找到需要调用的Action类;
4.创建一个ActionInvocation实例,来调用Action的对应方法来获取结果集的name,在调用前后会执行相关拦截器
5/通过结果集的name找到对应的结果集来对浏览器进行响应

45.STRUTS2的拦截器是什么

通过动态配置方式,可以在执行Action的方法前后,加入相关逻辑,完成业务 .struts2中的功能, 都是通过系统拦截器实现的.比如:参数处理,文件上传,字符编码.当然,我们也可以自定义拦截器
使用场景:用户登陆判断,在执行Action的前面判断是否已经登陆,如果没有登陆则跳转到登陆页面;用户权限的判断,在执行Action的前面判断是否具有权限,如果没有给出提示信息;

46.SPRING MVC的执行流程

1.用户发送请求,被前端控制器(DispatcherServlet)捕获(捕获请求)
2.前端控制器进行解析,得到URI,通过URI调用HandlerMapping并获得该Handler配置的所有相关对象(查找Handler)
3.前端控制器根据得到的Handler,选择合适的HandlerAdapter,提取Request中的模型数据,填入Handler入参,开始执行Handler,最后返回一个ModelAndView对象.(执行Handler)
4.前端控制器根据返回的ModelAndViewm,选择合适的ViewResolver(选择ViewResolver)
5.通过ViewResolver结合Model和View来渲染视图,前端控制器将渲染结果返回给客户端(渲染并返回)

47.SPRINGMVC和STRUTS2的不同

核心控制器不同:springmvc是servlet,struts2是filter
控制器实例:springmvc会比struts快(理论上),springmvc是基于方法设计,struts是基于对象,每发一次请求都会实例一个action.springmvc只有一个实例,每次请求执行对应的方法即可,简单来说,springmvc是单例,是trust是多例
管理方式:springmvc是spring的一个模块,所以spring对于springmvc的控制管理更加简单方便.而struts需要使用xml配置很多参数来管理
参数传递:struts2中自身提供多种参数接收,其实都是通过valuestack进行传递和赋值.而springmvc是通过方法参数进行接收.
interceptor的实现机制:struts有自己的interceptor机制,springmvc用的是独立的aop方式.
Springmvc处理ajax请求,直接返回数据,方法中使用注解@ResponseBody,springmvc自动帮我们将数据转成json数据,而struts2是通过插件的方式进行处理
48.简单介绍一下SPRING或者SPRING的两大核心

Spring是什么?spring是j2ee应用程序框架,是轻量级的IOC和AOP的容器框架,主要针对javabean的生命周期进行管理的轻量级容器,可以单独使用,也可以跟其它框架组合使用.

IOC(inversion of control)或DI(dependency injection)控制反转
原来:我的service要调用Dao,我就在service中创建Dao对象,这时Dao对象的创建的控制权在我手中
Spring:spring发现我的service依赖于Dao,就给我的service注入Dao对象,这时Dao对象创建的控制权在spring手中
核心原理:工厂模式+反射+配置文件

AOP:面向切面编程
核心原理:使用动态代理的方式在执行前后或出现异常后做相关逻辑.
我们主要使用AOP来做:
事务处理
权限判断
日志记录

49.AOP是什么?都用它做什么?

AOP:面向切面编程
核心原理:使用动态代理的方式在执行前后或出现异常后做加入相关逻辑.
我们主要使用AOP来做:
事务处理 执行方法前,开启事务,执行方法后提交事务,出现异常后回滚事务
权限判断 在执行方法前,判断是否具有权限
日志记录 在执行方法前执行日志

50.SPRING事务的传播特性和隔离级别

事务的传播特性:多个事务存在是怎么处理的策略.

传播行为 意义
PROPAGATION_MANDATORY 表示该方法必须运行在一个事务中。如果当前没有事务正在发生,将抛出一个异常
PROPAGATION_NESTED 表示如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于封装事务进行提交或回滚。如果封装事务不存在,行为就像PROPAGATION_REQUIRES一样。
PROPAGATION_NEVER 表示当前的方法不应该在一个事务中运行。如果一个事务正在进行,则会抛出一个异常。
PROPAGATION_NOT_SUPPORTED 表示该方法不应该在一个事务中运行。如果一个现有事务正在进行中,它将在该方法的运行期间被挂起。
PROPAGATION_SUPPORTS 表示当前方法不需要事务性上下文,但是如果有一个事务已经在运行的话,它也可以在这个事务里运行。
PROPAGATION_REQUIRES_NEW 表示当前方法必须在它自己的事务里运行。一个新的事务将被启动,而且如果有一个现有事务在运行的话,则将在这个方法运行期间被挂起。
PROPAGATION_REQUIRES 表示当前方法必须在一个事务中运行。如果一个现有事务正在进行中,该方法将在那个事务中运行,否则就要开始一个新事务。
隔离级别 含义
ISOLATION_DEFAULT 使用后端数据库默认的隔离级别。
ISOLATION_READ_UNCOMMITTED 允许读取尚未提交的更改。可能导致脏读、幻影读或不可重复读。
ISOLATION_READ_COMMITTED 允许从已经提交的并发事务读取。可防止脏读,但幻影读和不可重复读仍可能会发生。
ISOLATION_REPEATABLE_READ 对相同字段的多次读取的结果是一致的,除非数据被当前事务本身改变。可防止脏读和不可重复读,但幻影读仍可能发生。
ISOLATION_SERIALIZABLE 完全服从ACID的隔离级别,确保不发生脏读、不可重复读和幻影读。这在所有隔离级别中也是最慢的,因为它通常是通过完全锁定当前事务所涉及的数据表来完成的。
51.ORM是什么?ORM框架是什么?

对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。简单来说,将程序中的兑现自动持久化到关系数据库中。那么,到底如何实现持久化呢?一种简单的反感是采用硬编码的方式(jdbc操作sql方式),为每一种可能的数据库访问操作提供单独的方法。这种方法存在很多缺陷,所以使用ORM框架(为了解决面型对象与关系数据库存在的互不匹配的现象的框架)来解决。

Java典型的ORM框架有:Hibernate,mybatits

52.MYBATIS和HIBERNATE有什么不同

相同:都是java中的orm框架,屏蔽jdbc的api底层访问细节,使我们不用域jdbc的挨批打交道,就可以完成对数据的持久化操作.jdbc的api编程流程固定,还将sql与java代码混在在一起,经常需要拼凑sql语句,细节繁琐,开发不方便.
Mybatis的好处:屏蔽jdbc api的底层访问细节,将sql语句域java代码分离,提供将结果集自动封装为实体对象和对象的集合的功能,queryForList返回对象集合.用queryForObject返回单个对象.提供自动将实体对象的属性传递给sql语句的参数
Hibernate的好处:hibernate是一个全自动的偶人吗映射工具,它可以自动生成sql语句,执行并返回java结果.

不同点:

  1. hibernate要比mybatis功能强大很多,因为hibernate自动生成sql语句.
  2. Mybatis需要我们自己在xml配置文件中写sql语句,hibernate我们无法直接控制该语句,我们就无法去写特定的高效的sql,对于一些不太复杂的sql查询,hibernate可以很好帮我们完成.但是,对于特别复杂的查询,hibernate就很难适应了,这时候用mybatis就是不错的选择,因为mybatis还是由我们自己写sql语句.mybatis可以处理复杂语句,而hibernate不能.
  3. Mybatis要比hibernate简单的多,mybatis是面向sql的,不用考虑对象间一些复杂的映射关系.

53.HIBERNATE对象状态及其转换

瞬时态:刚new的,没有持久化,不在session中
持久态:session中的持久化对象
脱管态:不在session中的持久化对象

54.HIBERNATE的缓存

缓存:为了提高访问速度,把磁盘或数据库访问变成内存访问.
一级缓存(session缓存):session缓存内置不能被卸载session:是事务范围的缓存(session对象的生命周期通常对应一个数据库事务或者一个应用事务).一级缓存中,持久化类的每个实例都具有唯一的oid
二级缓存(SessionFactory缓存):由于SessionFactory对象的生命周期和一个用程序的整个过程对应,因此hibernate二级缓存是进城范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别.二级缓存是可选的,是一个可配置的插件,默认下SessionFactory不会启用这个插件.

概括:hibernate中的缓存分一级缓存和二级缓存
一级缓存就是session级别的缓存, 在事务范围内是有效的,是内置的不能被卸载.二级缓存是SessionFactory级别的缓存,从应用启动到应用结束有效,是可选的,默认没有二级缓存,需要手动开启

保存数据库后,在内存中保存一份,如果更新了数据库就要同步更新缓存
什么样的数据适合放到缓存中(访问频率,读写比例,数据一致性):
很少被修改的数据
经常被查询的数据
不是很重要的数据,允许出现偶尔并发的数据
不会被并发访问的数据
常量数据

Hibernate的二级缓存默认是不支持分布式缓存的,使用memcache,redis等重要缓存来代替二级缓存

55.WEBSERVICE的使用场景

Webservice是一个SOA(面向服务的编程)的架构,它是不依赖于语言,不依赖于平台,可以实现不同的语言间的相互调用,通过Internet进行基于http协议的网络应用间的交互.

异构系统(语言)的整合
不同客户端的整合,浏览器 手机端 pc端等终端的访问
例子:
天气预报:可以通过实现webservice客户端调用远程天气服务实现的.
单点登录:一个服务器实现所有系统的登陆

56.ACTIVITI的简单介绍

Activiti是一个业务流程管理(BPM)和工作流系统,适用于开发人员和系统管理人员,其核心是超快速,稳定的BPMN2流程引擎,它易与spring集成使用.

主要用在OA中,把线下流程放到线上,把现实生活中的一些流程固话定义到系统中,然后通过输入表单数据完成业务.

57.LINUX的使用场景

Linux是一个长时间运行比较稳定的操作系统,所以我们一般会拿它作为服务器(web,db.app等).
Linux本身具有c的编译环境.我们的一些软件是没有软件包的(redis,nginx),需要在linux编译得到软件包

58.LINUX常用命令

Cd跳转到目录
Pwd 获取当前路径
Su 切换用户
Ll 查看当前目录下文件和目录
Tail 查看文件
Rm –rf 删除文件
Vi 修改文件
Mv 移动/重命名 文件或文件夹
Mkdir 创建文件夹
Rm –f 删除文件夹
Tar 打包/解压
Grep 查找想要的信息

59.怎么操作LINUX服务器

需要依赖于linux服务器安装ssh服务端,一般这个ssh服务的端口为22,
需要依赖于linux服务器安装sftp服务端,一般这个sftp服务的端口为25,

使用ssh客户端连接linux服务器,通过命令操作linux服务器
使用sftp客户端来连接sftp服务端,来上传和下载文件(安装包,修改文件上传)

60.有没有使用过云主机

使用过阿里云
云主机:就是一些云服务运营商(阿里,华为,新浪等)提供的远程服务器功能,我们公司只要付费就可以租用对应的服务器.

61.数据库优化方面的事情

定位:查找,定位慢查询,并优化
优化
1.创建索引:创建合适的索引,我们就可以在索引中查询,查询到以后直接找对应的额记录
2,分表:当一张表的数据比较多或者一张表的某些字段的值比较多并且很少使用时,采用水平分表或垂直分表来优化,比如spu表
3,读写分离:当一台服务器不能满足需要时,采用将读写分离的方式进行集群
4.缓存:使用redis来进行缓存

62.如果查询和定位慢查询

在项目自验或项目转测之前,在启动mysql数据库时开启慢查询,并且把执行慢的语句写到日志中,在运行一定的时间后,通过查看日志,找到对应的慢查询信息.

使用EXPLAIN +慢查询语句,来详细分析语句的问题.

63.数据库优化之数据库表设计遵循范式

三范式:首先符合1nf,才能满足2nf,进一步满足3nf
反三范式:没有冗余的数据库未必是最好的数据库,有事为了提高运行效率,就必须降低范式标准,适当保留冗余数据.具体做法是,在概念数据模型设计时遵守三范式,降低方式标准的工作放到物理数据模型设计时考虑,降低范式就是增加字段,允许冗余.订单和订单项,相册浏览次数和照片的浏览次数.

64.选择合适的数据库引擎

Myisam存储引擎:如果表对事物要求不高,同时是以查询和添加为主的,我们考虑使用myisam存储引擎,比如论坛中的发帖表,回复表

Innodb存储引擎:对事物要求高,保存的数据都是重要数据.我们建议使用innodb,比如订单表,账号表

Myisam和innodb的区别:

  1. 事务安全,myisam不支持使用,而innodb支持
  2. 查询和添加速度,myisam不用支持事务就不用考虑同步锁,查找和添加的速度快
  3. 支持全文索引,myisam支持,innodb不支持
  4. 锁机制:myisam支持表锁,innodb支持行锁
  5. 外键:myisam不支持外键,innodb支持外键

65.选择合适的索引

索引是帮助DBMS高效获取数据的数据结构.
分类:普通索引,唯一索引,主键索引,全文索引
1.普通索引:允许重复的值出现
2.唯一索引:除了不能有重复的记录外,其它和普通索引一样.(用户名;用户身份证;手机号)
3.主键索引:是随着设定主键而创建的;也就是把某个列设为主键的时候,数据库就会给该列创建索引;唯一且没有null值
4.全文索引:用来对表中文本域(char,varchar,text)进行索引,全文索引针对myisam

66.使用索引的一些技巧

索引弊端:

  1. 占用磁盘空间.
  2. 对dml(插入,修改.删除)操作有影响,变慢
    使用场景:
  3. 肯定在where条件经常使用,如果不做查询就没有意义
  4. 该字段的内容不是唯一的几个值(sex).
  5. 字段内容不是频繁变化

具体技巧:

  1. 对于创建的多列索引(复合索引),不是使用的第一部分就不会使用索引(最左匹配)
  2. 对于使用like查询,查询如果是”%aaa”不会使用到索引,而”aaa%”会使用到索引
  3. 如果条件中有or,有条件没有使用索引,即使其中有条件带索引,也不会使用.简单来说,就是要求使用的所有字段,都必须单独使用时才能使用索引.
  4. 如果列类型是字符串,拿一定要在条件中将数据使用引号引用起来,否则索引失效
  5. 如果mysql估计使用全表扫描要比索引快,则不适用索引.例子:表里只有一条记录

67.数据库优化之分表

分表分为水平分表(按行)和垂直分表(按列)

水平:在实际操作中,mysql表数据一般达到百万级别,查询效率会很低,容易造成表锁,甚至堆积很多连接,直接挂掉.水平分表能够很大程度的减少这些压力.

垂直:如果一张表中某个字段值非常多(长文本,二进制等),而且只有在很少的情况下会查询,比如商品的详情描述,这时候就可以把字段单个放到一个表,通过外键与原表关联起来

水平分表策略:

  1. 按时间分表:这种分表方式有一定的局限性,当数据有较强的时效性.如微博发布纪录,微信消息纪录等,这种数据很少会有用户查询几个月前的数据,这时可以按月分表
  2. 按区间范围分表:一般在有严格的自增id需求上,如按照user_id水平分表
  3. Hash分表(用的多):通过一个原始目标的id或者名称通过一定的hash算法计算出数据库存储表的表名,然后访问相应的表.

68.数据库的读写分离

一台数据库支持的最大并发连接数是有限的,如果用户并发访问太多,一台服务器满足不了要求时,可以集群处理.mysql的集群处理技术最常用的是读写分离,

1.主从同步:数据库最终会把数据持久化到磁盘,如果集群必须确保每个数据库服务器的数据时一致的.能改变数据库数据的操作都往主数据库去写,而其他的数据库从主数据库上同步数据
2.读写分离:使用负载均衡来实现写的操作都往主数据.而读的操作都往从数据库去

69.数据库优化之缓存

在持久层(dao)和数据库(db)之间添加一个缓存层,如果用户访问的数据已经缓存起来时,在用户访问数据时从缓存中获取,不用访问数据库,而缓存是在操作内存,访问速度快

作用:减少数据库服务器压力,减少访问时间

Java中常用的缓存:

  1. hibernate的二级缓存,这种缓存不支持分布式缓存
  2. 可以使用redis来作为中央缓存,对缓存的数据进行集中处理

70.SQL语句优化小技巧

DDL优化:

  1. 通过禁用索引来提供导入数据性能,这个操作主要针对有数据的表追加数据
  2. 关闭唯一校验
  3. 修改事务提交方式(导入)(变多次提交为一次)

DML优化: 把多条插入的语句合并为一条(变多次提交为一次)

DQL优化:

Order by 优化
多用索引排序
普通结果排序(非索引排序)
Group by 优化:如果对排序的结果没有排序的需求,可以考虑在其后面加上order by nul
子查询优化
Or优化:
1.or两边都是用索引字段做判读,性能好
2.or两边,有一边不用,性能差
3.如果name=”a” or name=”b”,这种方式,索引失效
Limit优化
71.批量插入几百万条数据

可以使用存储过程

72.有没有使用过REDIS

Redis是一个key-value的nosql数据库,先存到内存中,会根据一定的策略持久化到磁盘,即使断电也不会丢失数据,支持的数据类型比较多.

主要用来做缓存数据库的数据和web集群时当做中央缓存存放session

73.REDIS的使用场景

缓存:把经常需要查询很少修改的数据放到读速度很快的空间(内存),以便减少下次访问时间,减轻db压力,
计数器:redis中的计数器是原子性的内存操作,可以解决库存溢出问题,进销存,系统存溢出
Session缓存服务器:web集群时作为session的缓存服务器
74.REDIS存储对象的方式

Json字符串:需要把对象转换成json字符串,当做字符串处理,直接使用set和get来设置或获取/
优点:设置和获取比较简单
缺点:没有提供专门的方法,需要把对象转换成json

字节:需要做序列号,就是把对象序列化为字节保存.

如果是担心json转对象会消耗资源的情况,这个问题需要考量几个地方,

  1. 使用的json转换lib是否就会存在性能问题
  2. 数据的数据量级别,如果是存储百万级的大数据对象,建议采用存储序列化对象方式.如果是少量的数据级对象,或者是数据对象字段不多,还是建议采用json转换成string方式.毕竟redis对存储字符类型这部分优化的非常好.具体采用的方式与方法,还要看你所使用的场景

75.REDIS数据淘汰机制

在 redis 中,允许用户设置最大使用内存大小 server.maxmemory,在内存限定的情况下是很有用的。譬如,在一台 8G 机子上部署了 4 个 redis 服务点,每一个服务点分配 1.5G 的内存大小,减少内存紧张的情况,由此获取更为稳健的服务。

内存大小有限,需要保存有效的数据?
Redis内存数据集大小上升到一定大小的时候,就会施行平台策略.数据淘汰策略.redis提供6中数据淘汰策略:
1.volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
2.volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
3.volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
4.allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
5.allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
6.no-enviction(驱逐):禁止驱逐数据

76.JAVA访问REDIS级REDIS集群

Java访问redis:

  1. 使用jedisjava客户端来访问redis服务器,优点类似jdbc访问db一样
  2. 如果是spring进行集成时,可以使用springDataRedis来访问redis , springDataRedis 只是对jedis的二次封装

Redis集群:当一台数据无法满足要求,可以使用redis集群来出来,类似mysql的读写分离

77.项目的并发

1.需求:用户量,这个客户说了算,大概也就是1-5年内用户总量
2.根据pv(页面点击量,浏览量)和uv(ip数量)预估,大致能达到多大的并发量.我们的项目大概能达到1000-3000的并发量
3.确定我们的服务器数量,我们使用的是tomcat,tomcat的默认线程数150,我们可以将它优化调到400左右.而我们大致需要5台web服务器
4.重要的因素(硬件服务器水平—去IOE),我们没有做这个,因为我们没钱.

78.http协议

1.无状态,为了解决http无状态问题,引入cookie技术
2.http1.0是短连接,http1.1是长连接
3.http协议是基于B/S请求-应答模式

79.cookie和session

1.Cookie是由服务器创建的,通过response对象的addCookie(Cookie cookie)方法写回客户端,存储在客户端的会话技术.key-value的结构
2.session是基于cookie,session的创建是由服务器做,可以通过request.getSession()获取(要从你的请求中找一个cookie—Jessionid,如果能找到这个cookie,他会拿着这个cookie的值去跟服务器端的session的id比较,如果找到相应的session,就不创建session.如果找不到相应的session,会创建session).session一旦创建就会有一个id属性(唯一的),通过response以cookie的方式写回客户端(这个cookie就叫做就sessionid).

会话:会话就是简单的理解成打开浏览器(包含了一次请求或多次请求).

80.session共享的方案

1.广播:会造成内网网络风暴,大量占用内网宽带
2.IP_hash:在nginx中配置和,相同的ip找固定的同一台服务器,这种方案会造成服务能力差
3.使用第三方中间件(数据库,redis),我们是使用redis

81.solr相似度匹配原理(多关键字搜索)

solr将用户输入的内容使用分词器分词,然后将这些新词做成向量.
比如,用户输入:我是萝莉控
solr分词记过:我 , 萝莉 , 萝莉控
向量:向量a–我 ,向量b–萝莉, 向量c–萝莉控
接下来,solr会将索引库中所有包含这些关键字的记录数做成n维向量.这个时候,solr会根据n维向量夹角的余弦值的大小来判断相似度的大小.余弦值越低,相似度越大,排名越靠前.反之,余弦值越大,相似度越小,排名越靠后.

题外话:lucene的数据模型其实是n维向量.

82.高并发问题:索引库同步

1.硬编码:在相应的代码中增加索引库同步的代码。不过,这种方法耦合度太高,将原本不相关的系统耦合在了一起,容易造成不可预估的错误,是电商项目的大忌。
2.spring的aop:编写一个索引库同步的方法,利用aop的形式,将它和数据库数据更新的方法联系起来。这种方式也会造成耦合。
3.消息队列:不过,这个方法会造成一个问题,那就是消息消费失败问题。

:解决两个系统间的通信问题。
消息消费失败:集中同步索引库,做一个定时任务。在消息队列所在的服务器上加一个数据库,我们使用的是redis缓存。消息队列中每发一条信息,就将这条信息持久化进redis中。接着定时(我们是在晚上,用户量少的时候)从redis中将消息列表取出来,批量同步索引库。

83.页面静态化问题

当商品规格出现不同组合时,它的价格势必会不一样,这时怎么在静态页面中处理价格这样的数据?
像价格这样的数据,只有我们在生成静态页面时才会和数据库交互一次,查出所有的sku,将这些sku存进集合中。接着,我们在前端js中定义一个变量来存储集合的值,当以后用户每一次来访问我们的静态页面时,他都是从静态页面的js变量中自动获取价格这样的数据。

84.与app端对接时需要注意什么

和app端对接,需要知道对方需要什么样的数据,以及接口的请求方式,返回值类型等

85.为什么服务层之间调用的activeMq会是在controller层发消息?

因为事务!如果是在controller层发送消息,那么controller层调用的service一定是完成了事务提交操作的。如果是在service层发送消息,那么事务可能会没有提交,会造成空指针异常。

86.索引库同步时为什么使用activemq的queue方式?(使用queue的好处)

1.不需要考虑消息没有被消费问题
2.queue方式,自带持久化机制
3.业务更加单一,相对来说比较安全

87.消息队列问题:同步索引库时,传输的内容为什么是商品信息,而不适用商品id?

传送商品id:
好处:传送的是商品id,传输的内容少,效率相对较高,不会产生消息阻塞。
缺点:消费方需要再次查询数据库取出商品信息,和数据库多了一次交互。
传送商品信息:
好处:这样消费者就不需要再次从数据库中查询商品信息数据,减少了与数据库的交互。
缺点:传输的是商品信息,传输内容相对较少(原因:文本信息在网络传输中占用的网络资源最少),可能会产生消息阻塞的问题,但是由于我们的消息的发送不是连续的,不会有太高的并发量(原因:消息的发送时需要运营商平台审核通过后才发送的。)

88.秒杀

秒杀业务最主要的操作:减库存和添加订单
1.第一种方式:数据库(中小型网站)
Update goods set num=num-1 where id=id;
Insert orders values() where goods.id=goodsid

为了保持数据的一致性,需要使用事务

优化:
①数据库服务器和秒杀服务器在同一个机房
②避免使用事务,使用数据库的存储过程来完成业务单元
存储过程逻辑:避免使用事务
(1)判断库存(num)
(2)如果num>0,执行update和insert操作
(3)如果num<0,秒杀结束

2.第二种方式:缓存(redis)(中大型网站)
将秒杀商品和订单都存在redis中,用户下单时,num>0?下单(num-1):秒杀结束;

89.HashMap中链表长度大于8时,会怎么样(优化hashMap)

HashMap在JDK1.8及以后的版本中引入了红黑树结构,若桶中链表元素个数大于等于8时,链表转换成树结构;若桶中链表元素个数小于等于6时,树结构还原成链表。因为红黑树的平均查找长度是log(n),长度为8的时候,平均查找长度为3,如果继续使用链表,平均查找长度为8/2=4,这才有转换为树的必要。链表长度如果是小于等于6,6/2=3,虽然速度也很快的,但是转化为树结构和生成树的时间并不会太短。
还有选择6和8,中间有个差值7可以有效防止链表和树频繁转换。假设一下,如果设计成链表个数超过8则链表转换成树结构,链表个数小于8则树结构转换成链表,如果一个HashMap不停的插入、删除元素,链表个数在8左右徘徊,就会频繁的发生树转链表、链表转树,效率会很低

90.JSP中动态INCLUDE与静态INCLUDE的区别

动态INCLUDE用jsp:include动作实现 它总是会检查所含文件中的变化,适合用于包含动态页面,并且可以带参数。静态INCLUDE用include伪码实现,并不会检查所含文件的变化,适用于包含静态页面

91.1000个人来买100件商品

缓存架构(KyotoCabinet、Memcached等)的先进先出队列,
不能随便加锁,淘宝的双11活动。很明显的一点是商品没有提供一个非常即时的锁,即便商品实际没有了也是可以下单成功的。但是在支付的时候会提示你商品没有了。猜测只是在支付的时候才有即时的锁。

92 你们做移动端没有,如果没有移动端,你们为什么做单点登录?

单点登录并不是为移动端准备的,移动端有自己的登录方式。单点登录是解决在同一个公司
内部多个互信网站之间进行跳转时不需要多次登录,多个系统统一登录入口。

93.单点登录的核心是什么?

单点登录的核心是如何在多个系统之间共享身份信息

94.solr 的索引查询为什么比数据库要快。

Solr 使用的是 Lucene API 实现的全文检索。全文检索本质上是查询的索引。而数据库中并
不是所有的字段都建立的索引,更何况如果使用 like 查询时很大的可能是不使用索引,所以
使用 solr 查询时要比查数据库快。

95.solr 索引库个别数据索引丢失怎么办。

首先 Solr 是不会丢失个别数据的。如果索引库中缺少数据,那就向索引库中添加

96.IO和NIO

IO NIO
面向流 面向缓冲
阻塞IO 非阻塞IO
无 选择器

97.https和http

HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。

区别:
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

98.序列化

序列化一般是指把结构化的对象变成无结构的字节流,便于存储、传输

首先序列化并不是JAVA所独有的,基本所有编程语言都提供了序列化的方式,序列化是编程的一种解决问题的方式。JAVA序列化就是将对象按照某种协议格式(某种约定方式)放入一个buffer中,其目的是便于网络传输或持久存储。反序列化,就是将序列化后的buffer按照序列化时还原成原来的对象,这样程序就能直接使用还原的对象了。

99.安全性问题(别的网站使用爬虫技术爬你的网站怎么办?有没有安全措施)

单位时间内请求次数超过某个阈值就让输入验证码,可以极大降低抓取的速度,如果多次超
过某个阀值可以加入黑名单。还有就是页面内容使用 json 返回,数据经常变一变格式,或
者 js 动态生成页面内容

100.订单表的数据量太大, 我把订单分到许多表中, 那么我我想用一条 sql 查处所有的订单, 怎么
解决?

分库情况下:可以使用 mycat 数据库中间件实现多个表的统一管理。虽然物理上是把一个表
中的数据保存到多个数据库中,但是逻辑上还是一个表,使用一条 sql 语句就可以把数据全
部查询出来。
单库情况下:需要动态生成 sql 语句。先查询订单相关的表,然后将查询多个表的 sql 语句
使用 union 连接即可

101.TCP和UDP的区别

1.tcp面向连接(如打电话要先拨号连接);udp是无连接的,即发送数据之前不需要连接
2.tcp提供可靠的服务。也就是说通过tcp传送的数据,无差错,无丢失,不重复,且按序到达;udp尽最大努力交付,不保证交付是否成功
3.tcp面下字节流,实际上tcp把数据看成是一连串无结构的字节流;udp是面向报文的,udp没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,比如视频会议)
4.每一条tcp连接只能是点到点的;udp支持一对一,一对多,多对一,多对多的交互通信
5.tcp首部开销20字节;udp首部开销小,只有8字节
6.tcp通信信道是全双工的可靠信道;udp则是不可靠

102.tcp三次握手和四次挥手

1.三次握手

2.四次挥手

103.为什么挥手会比握手多一次

因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,”你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

104.spring对bean的管理

1.BeanFactory: BeanFactory采用了工厂设计模式,负责读取bean配置文档,管理bean的加载,实例化,维护bean之间的依赖关系,负责bean的生命周期。
2.ApplicationContext:除了提供上述BeanFactory所能提供的功能之外,还提供了更完整的框架功能:国际化支持、aop、事务等。
3.BeanFactory在解析配置文件时并不会初始化对象,只有在使用对象getBean()才会对该对象进行初始化,而ApplicationContext在解析配置文件时对配置文件中的所有对象都初始化了,getBean()方法只是获取对象的过程。

105.mybatis返回最近插入的数据的id

SELECT LAST_INSERT_ID() AS ID insert into t_employee (ID, EmployeeName, Position, Salary, Tel, DepartmentID ) values (#{id,jdbcType=INTEGER}, #{employeename,jdbcType=VARCHAR}, #{position,jdbcType=VARCHAR}, #{salary,jdbcType=DOUBLE}, #{tel,jdbcType=VARCHAR}, #{departmentid,jdbcType=INTEGER} ) 1 2 3 4 5 6 7 8 9 10 11 Employee employee = new Employee(); employee.setDepartmentid(1); employee.setEmployeename("xiaoA"); employee.setPosition("manager"); employee.setSalary(13000d); int result = employeeMapper.insert(employee); int id = employee.getId();//获取新插入的id LOGGER.info("last insert id : " + id); } }

设计模式——单例模式和多例的区别

单例模式的关键有两点:
1、构造方法为私有,这样外界就不能随意调用。
2、get的方法为静态,由类直接调用

多例模式(Multiton)
1 、多例类可以有多个实例
2 、多例类必须能够自我创建并管理自己的实例,并向外界提供自己的实例。

一、单例模式和多例模式说明:

  1. 单例模式和多例模式属于对象模式。
  2. 单例模式的对象在整个系统中只有一份,多例模式可以有多个实例。
  3. 它们都不对外提供构造方法,即构造方法都为私有。

单例和多例的详细描述:

  1. 什么是单例多例:
    所谓单例就是所有的请求都用一个对象来处理,比如我们常用的service和dao层的对象通常都是单例的,而多例则指每个请求用一个新的对象来处理,比如action;
  2. 如何产生单例多例:
    在通用的SSH中,单例在spring中是默认的,如果要产生多例,则在配置文件的bean中添加scope=”prototype”;
  3. 为什么用单例多例:
    之所以用单例,是因为没必要每个请求都新建一个对象,这样子既浪费CPU又浪费内存;
    之所以用多例,是为了防止并发问题;即一个请求改变了对象的状态,此时对象又处理另一个请求,而之前请求对对象状态的改变导致了对象对另一个请求做了错误的处理;
    用单例和多例的标准只有一个:
    当对象含有可改变的状态时(更精确的说就是在实际应用中该状态会改变),则多例,否则单例;
  4. 何时用单例?何时用多例?
    对于struts2来说,action必须用多例,因为action本身含有请求参数的值,即可改变的状态;
    而对于STRUTS1来说,action则可用单例,因为请求参数的值是放在actionForm中,而非action中的;
    另外要说一下,并不是说service或dao一定是单例,标准同第3点所讲的,就曾见过有的service中也包含了可改变的状态,同时执行方法也依赖该状态,但一样用的单例,这样就会出现隐藏的BUG,而并发的BUG通常很难重现和查找;

多线程中sleep()、wait()方法等得区别?

个人分类: java多线程

1、这两个方法来自不同的类分别是Thread和Object

2、最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。

3、wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在

任何地方使用(使用范围)

synchronized(x){

x.notify()

//或者wait()

}

4、sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常

扩充阅读:

java 线程中的sleep和wait有一个共同作用,停止当前线程任务运行,但他们存在一定的不同,首先我们先看sleep中的构造函数

sleep(long millis) Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers.

sleep(long millis, int nanos) Causes the currently executing thread to sleep (cease execution) for the specified number of milliseconds plus the specified number of nanoseconds, subject to the precision and accuracy of system timers and schedulers.

sleep方法属于Thread类中方法,表示让一个线程进入睡眠状态,等待一定的时间之后,自动醒来进入到可运行状态,不会马上进入运行状态,因为线程调度机制恢复线程的运行也需要时间,一个线程对象调用了sleep方法之后,并不会释放他所持有的所有对象锁,所以也就不会影响其他进程对象的运行。但在sleep的过程中过程中有可能被其他对象调用它的interrupt(),产生InterruptedException异常,如果你的程序不捕获这个异常,线程就会异常终止,进入TERMINATED状态,如果你的程序捕获了这个异常,那么程序就会继续执行catch语句块(可能还有finally语句块)以及以后的代码。

注意sleep()方法是一个静态方法,也就是说他只对当前对象有效,通过t.sleep()让t对象进入sleep,这样的做法是错误的,它只会是使当前线程被sleep 而不是t线程

wait方法

void wait(long timeout)

Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed.

void wait(long timeout, int nanos)

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object, or some other thread interrupts the current thread, or a certain amount of real time has elapsed.

wait属于Object的成员方法,一旦一个对象调用了wait方法,必须要采用notify()和notifyAll()方法唤醒该进程;如果线程拥有某个或某些对象的同步锁,那么在调用了wait()后,这个线程就会释放它持有的所有同步资源,而不限于这个被调用了wait()方法的对象。wait()方法也同样会在wait的过程中有可能被其他对象调用interrupt()方法而产生

InterruptedException,效果以及处理方式同sleep()方法

追加内容:

Collection是个java.util下的接口,它是各种集合结构的父接口。

Collections是个java.util下的类,它包含有各种有关集合操作的静态方法。

Collection 层次结构中的根接口。Collection 表示一组对象,这些对象也称为 collection的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。

collections 此类完全由在 collection 上进行操作或返回 collection 的静态方法组成。它包含在 collection 上操作的多态算法,即“包装器”,包装器返回由指定 collection 支持的新 collection,以及少数其他内容。 如果为此类的方法所提供的 collection 或类对象为 null,则这些方法都会抛出 NullPointerException。

java多线程:

线程或者说多线程,是我们处理多任务的强大工具。线程和进程是不同的,每个进程都是一个独立运行的程序,拥有自己的变量,且不同进程间的变量不能共享;而线程是运行在进程内部的,每个正在运行的进程至少有一个线程,而且不同的线程之间可以在进程范围内共享数据。也就是说进程有自己独立的存储空间,而线程是和它所属的进程内的其他线程共享一个存储空间。线程的使用可以使我们能够并行地处理一些事情。线程通过并行的处理给用户带来更好的使用体验,比如你使用的邮件系统(outlook、Thunderbird、foxmail等),你当然不希望它们在收取新邮件的时候,导致你连已经收下来的邮件都无法阅读,而只能等待收取邮件操作执行完毕。这正是线程的意义所在。

实现线程的方式

实现线程的方式有两种:

继承java.lang.Thread,并重写它的run()方法,将线程的执行主体放入其中。
实现java.lang.Runnable接口,实现它的run()方法,并将线程的执行主体放入其中。

这是继承Thread类实现线程的示例:
public class ThreadTest extends Thread { public void run() { // 在这里编写线程执行的主体 // do something } }

这是实现Runnable接口实现多线程的示例:
public class RunnableTest implements Runnable { public void run() { // 在这里编写线程执行的主体 // do something } }

这两种实现方式的区别并不大。继承Thread类的方式实现起来较为简单,但是继承它的类就不能再继承别的类了,因此也就不能继承别的类的有用的方法了。而使用是想Runnable接口的方式就不存在这个问题了,而且这种实现方式将线程主体和线程对象本身分离开来,逻辑上也较为清晰,所以推荐大家更多地采用这种方式。

如何启动线程

我们通过以上两种方式实现了一个线程之后,线程的实例并没有被创建,因此它们也并没有被运行。我们要启动一个线程,必须调用方法来启动它,这个方法就是Thread类的start()方法,而不是run()方法(既不是我们继承Thread类重写的run()方法,也不是实现Runnable接口的run()方法)。run()方法中包含的是线程的主体,也就是这个线程被启动后将要运行的代码,它跟线程的启动没有任何关系。上面两种实现线程的方式在启动时会有所不同。

继承Thread类的启动方式:
public class ThreadStartTest { public static void main(String[] args) { // 创建一个线程实例 ThreadTest tt = new ThreadTest(); // 启动线程 tt.start(); } }

实现Runnable接口的启动方式:
public class RunnableStartTest { public static void main(String[] args) { // 创建一个线程实例 Thread t = new Thread(new RunnableTest()); // 启动线程 t.start(); } }

实际上这两种启动线程的方式原理是一样的。首先都是调用本地方法启动一个线程,其次是在这个线程里执行目标对象的run()方法。那么这个目标对象是什么呢?为了弄明白这个问题,我们来看看Thread类的run()方法的实现:
public void run() { if (target != null) { target.run(); } }

当我们采用实现Runnable接口的方式来实现线程的情况下,在调用new Thread(Runnable target)构造器时,将实现Runnable接口的类的实例设置成了线程要执行的主体所属的目标对象target,当线程启动时,这个实例的run()方法就被执行了。当我们采用继承Thread的方式实现线程时,线程的这个run()方法被重写了,所以当线程启动时,执行的是这个对象自身的run()方法。总结起来就一句话,线程类有一个Runnable类型的target属性,它是线程启动后要执行的run()方法所属的主体,如果我们采用的是继承Thread类的方式,那么这个target就是线程对象自身,如果我们采用的是实现Runnable接口的方式,那么这个target就是实现了Runnable接口的类的实例。

线程的状态

在Java 1.4及以下的版本中,每个线程都具有新建、可运行、阻塞、死亡四种状态,但是在Java 5.0及以上版本中,线程的状态被扩充为新建、可运行、阻塞、等待、定时等待、死亡六种。线程的状态完全包含了一个线程从新建到运行,最后到结束的整个生命周期。线程状态的具体信息如下:
NEW(新建状态、初始化状态):线程对象已经被创建,但是还没有被启动时的状态。这段时间就是在我们调用new命令之后,调用start()方法之前。
RUNNABLE(可运行状态、就绪状态):在我们调用了线程的start()方法之后线程所处的状态。处于RUNNABLE状态的线程在JAVA虚拟机(JVM)上是运行着的,但是它可能还正在等待操作系统分配给它相应的运行资源以得以运行。
BLOCKED(阻塞状态、被中断运行):线程正在等待其它的线程释放同步锁,以进入一个同步块或者同步方法继续运行;或者它已经进入了某个同步块或同步方法,在运行的过程中它调用了某个对象继承自java.lang.Object的wait()方法,正在等待重新返回这个同步块或同步方法。
WAITING(等待状态):当前线程调用了java.lang.Object.wait()、java.lang.Thread.join()或者java.util.concurrent.locks.LockSupport.park()三个中的任意一个方法,正在等待另外一个线程执行某个操作。比如一个线程调用了某个对象的wait()方法,正在等待其它线程调用这个对象的notify()或者notifyAll()(这两个方法同样是继承自Object类)方法来唤醒它;或者一个线程调用了另一个线程的join()(这个方法属于Thread类)方法,正在等待这个方法运行结束。
TIMED_WAITING(定时等待状态):当前线程调用了java.lang.Object.wait(long timeout)、java.lang.Thread.join(long millis)、java.util.concurrent.locks.LockSupport.packNanos(long nanos)、java.util.concurrent.locks.LockSupport.packUntil(long deadline)四个方法中的任意一个,进入等待状态,但是与WAITING状态不同的是,它有一个最大等待时间,即使等待的条件仍然没有满足,只要到了这个时间它就会自动醒来。
TERMINATED(死亡状态、终止状态):线程完成执行后的状态。线程执行完run()方法中的全部代码,从该方法中退出,进入TERMINATED状态。还有一种情况是run()在运行过程中抛出了一个异常,而这个异常没有被程序捕获,导致这个线程异常终止进入TERMINATED状态。

在Java5.0及以上版本中,线程的全部六种状态都以枚举类型的形式定义在java.lang.Thread类中了,代码如下:
public enum State { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED; }

sleep()和wait()的区别

sleep()方法和wait()方法都成产生让当前运行的线程停止运行的效果,这是它们的共同点。下面我们来详细说说它们的不同之处。

sleep()方法是本地方法,属于Thread类,它有两种定义:
public static native void sleep(long millis) throws InterruptedException; public static void sleep(long millis, int nanos) throws InterruptedException { //other code }

其中的参数millis代表毫秒数(千分之一秒),nanos代表纳秒数(十亿分之一秒)。这两个方法都可以让调用它的线程沉睡(停止运行)指定的时间,到了这个时间,线程就会自动醒来,变为可运行状态(RUNNABLE),但这并不表示它马上就会被运行,因为线程调度机制恢复线程的运行也需要时间。调用sleep()方法并不会让线程释放它所持有的同步锁;而且在这期间它也不会阻碍其它线程的运行。上面的连个方法都声明抛出一个InterruptedException类型的异常,这是因为线程在sleep()期间,有可能被持有它的引用的其它线程调用它的interrupt()方法而中断。中断一个线程会导致一个InterruptedException异常的产生,如果你的程序不捕获这个异常,线程就会异常终止,进入TERMINATED状态,如果你的程序捕获了这个异常,那么程序就会继续执行catch语句块(可能还有finally语句块)以及以后的代码。

为了更好地理解interrupt()效果,我们来看一下下面这个例子:
public class InterruptTest { public static void main(String[] args) { Thread t = new Thread() { public void run() { try { System.out.println(“我被执行了-在sleep()方法前”); // 停止运行10分钟 Thread.sleep(1000 * 60 * 60 * 10); System.out.println(“我被执行了-在sleep()方法后”); } catch (InterruptedException e) { System.out.println(“我被执行了-在catch语句块中”); } System.out.println(“我被执行了-在try{}语句块后”); } }; // 启动线程 t.start(); // 在sleep()结束前中断它 t.interrupt(); } }

运行结果:
我被执行了-在sleep()方法前
我被执行了-在catch语句块中
我被执行了-在try{}语句块后

wait()方法也是本地方法,属于Object类,有三个定义:
public final void wait() throws InterruptedException { //do something } public final native void wait(long timeout) throws InterruptedException; public final void wait(long timeout, int nanos) throws InterruptedException { //do something }

wari()和wait(long timeout,int nanos)方法都是基于wait(long timeout)方法实现的。同样地,timeout代表毫秒数,nanos代表纳秒数。当调用了某个对象的wait()方法时,当前运行的线程就会转入等待状态(WAITING),等待别的线程再次调用这个对象的notify()或者notifyAll()方法(这两个方法也是本地方法)唤醒它,或者到了指定的最大等待时间,线程自动醒来。如果线程拥有某个或某些对象的同步锁,那么在调用了wait()后,这个线程就会释放它持有的所有同步资源,而不限于这个被调用了wait()方法的对象。wait()方法同样会被Thread类的interrupt()方法中断,并产生一个InterruptedException异常,效果同sleep()方法被中断一样。

实现同步的方式

同步是多线程中的重要概念。同步的使用可以保证在多线程运行的环境中,程序不会产生设计之外的错误结果。同步的实现方式有两种,同步方法和同步块,这两种方式都要用到synchronized关键字。

给一个方法增加synchronized修饰符之后就可以使它成为同步方法,这个方法可以是静态方法和非静态方法,但是不能是抽象类的抽象方法,也不能是接口中的接口方法。下面代码是一个同步方法的示例:
public synchronized void aMethod() { // do something } public static synchronized void anotherMethod() { // do something }

线程在执行同步方法时是具有排它性的。当任意一个线程进入到一个对象的任意一个同步方法时,这个对象的所有同步方法都被锁定了,在此期间,其他任何线程都不能访问这个对象的任意一个同步方法,直到这个线程执行完它所调用的同步方法并从中退出,从而导致它释放了该对象的同步锁之后。在一个对象被某个线程锁定之后,其他线程是可以访问这个对象的所有非同步方法的。

同步块的形式虽然与同步方法不同,但是原理和效果是一致的。同步块是通过锁定一个指定的对象,来对同步块中包含的代码进行同步;而同步方法是对这个方法块里的代码进行同步,而这种情况下锁定的对象就是同步方法所属的主体对象自身。如果这个方法是静态同步方法呢?那么线程锁定的就不是这个类的对象了,也不是这个类自身,而是这个类对应的java.lang.Class类型的对象。同步方法和同步块之间的相互制约只限于同一个对象之间,所以静态同步方法只受它所属类的其它静态同步方法的制约,而跟这个类的实例(对象)没有关系。

下面这段代码演示了同步块的实现方式:
public void test() { // 同步锁 String lock = “LOCK”; // 同步块 synchronized (lock) { // do something } int i = 0; // … }

对于作为同步锁的对象并没有什么特别要求,任意一个对象都可以。如果一个对象既有同步方法,又有同步块,那么当其中任意一个同步方法或者同步块被某个线程执行时,这个对象就被锁定了,其他线程无法在此时访问这个对象的同步方法,也不能执行同步块。

synchronized和Lock

Lock是一个接口,它位于Java 5.0新增的java.utils.concurrent包的子包locks中。concurrent包及其子包中的类都是用来处理多线程编程的。实现Lock接口的类具有与synchronized关键字同样的功能,但是它更加强大一些。java.utils.concurrent.locks.ReentrantLock是较常用的实现了Lock接口的类。下面是ReentrantLock类的一个应用实例:
private Lock lock = new ReentrantLock(); public void testLock() { // 锁定对象 lock.lock(); try { // do something } finally { // 释放对对象的锁定 lock.unlock(); } }

lock()方法用于锁定对象,unlock()方法用于释放对对象的锁定,他们都是在Lock接口中定义的方法。位于这两个方法之间的代码在被执行时,效果等同于被放在synchronized同步块中。一般用法是将需要在lock()和unlock()方法之间执行的代码放在try{}块中,并且在finally{}块中调用unlock()方法,这样就可以保证即使在执行代码抛出异常的情况下,对象的锁也总是会被释放,否则的话就会为死锁的产生增加可能。

使用synchronized关键字实现的同步,会把一个对象的所有同步方法和同步块看做一个整体,只要有一个被某个线程调用了,其他的就无法被别的线程执行,即使这些方法或同步块与被调用的代码之间没有任何逻辑关系,这显然降低了程序的运行效率。而使用Lock就能够很好地解决这个问题。我们可以把一个对象中按照逻辑关系把需要同步的方法或代码进行分组,为每个组创建一个Lock类型的对象,对实现同步。那么,当一个同步块被执行时,这个线程只会锁定与当前运行代码相关的其他代码最小集合,而并不影响其他线程对其余同步代码的调用执行。

关于死锁

死锁就是一个进程中的每个线程都在等待这个进程中的其他线程释放所占用的资源,从而导致所有线程都无法继续执行的情况。死锁是多线程编程中一个隐藏的陷阱,它经常发生在多个线程共用资源的时候。在实际开发中,死锁一般隐藏的较深,不容易被发现,一旦死锁现象发生,就必然会导致程序的瘫痪。因此必须避免它的发生。

程序中必须同时满足以下四个条件才会引发死锁:
互斥(Mutual exclusion):线程所使用的资源中至少有一个是不能共享的,它在同一时刻只能由一个线程使用。
持有与等待(Hold and wait):至少有一个线程已经持有了资源,并且正在等待获取其他的线程所持有的资源。
非抢占式(No pre-emption):如果一个线程已经持有了某个资源,那么在这个线程释放这个资源之前,别的线程不能把它抢夺过去使用。
循环等待(Circular wait):假设有N个线程在运行,第一个线程持有了一个资源,并且正在等待获取第二个线程持有的资源,而第二个线程正在等待获取第三个线程持有的资源,依此类推……第N个线程正在等待获取第一个线程持有的资源,由此形成一个循环等待。

线程池

线程池就像数据库连接池一样,是一个对象池。所有的对象池都有一个共同的目的,那就是为了提高对象的使用率,从而达到提高程序效率的目的。比如对于Servlet,它被设计为多线程的(如果它是单线程的,你就可以想象,当1000个人同时请求一个网页时,在第一个人获得请求结果之前,其它999个人都在郁闷地等待),如果为每个用户的每一次请求都创建一个新的线程对象来运行的话,系统就会在创建线程和销毁线程上耗费很大的开销,大大降低系统的效率。因此,Servlet多线程机制背后有一个线程池在支持,线程池在初始化初期就创建了一定数量的线程对象,通过提高对这些对象的利用率,避免高频率地创建对象,从而达到提高程序的效率的目的。

下面实现一个最简单的线程池,从中理解它的实现原理。为此我们定义了四个类,它们的用途及具体实现如下:
Task(任务):这是个代表任务的抽象类,其中定义了一个deal()方法,继承Task抽象类的子类需要实现这个方法,并把这个任务需要完成的具体工作在deal()方法编码实现。线程池中的线程之所以被创建,就是为了执行各种各样数量繁多的任务的,为了方便线程对任务的处理,我们需要用Task抽象类来保证任务的具体工作统一放在deal()方法里来完成,这样也使代码更加规范。
Task的定义如下:
public abstract class Task { public enum State { /* 新建 /NEW, / 执行中 /RUNNING, / 已完成 */FINISHED } // 任务状态 private State state = State.NEW; public void setState(State state) { this.state = state; } public State getState() { return state; } public abstract void deal(); }
TaskQueue(任务队列):在同一时刻,可能有很多任务需要执行,而程序在同一时刻只能执行一定数量的任务,当需要执行的任务数超过了程序所能承受的任务数时怎么办呢?这就有了先执行哪些任务,后执行哪些任务的规则。TaskQueue类就定义了这些规则中的一种,它采用的是FIFO(先进先出,英文名是First In First Out)的方式,也就是按照任务到达的先后顺序执行。
TaskQueue类的定义如下:
import java.util.Iterator; import java.util.LinkedList; import java.util.List; public class TaskQueue { private List queue = new LinkedList(); // 添加一项任务 public synchronized void addTask(Task task) { if (task != null) { queue.add(task); } } // 完成任务后将它从任务队列中删除 public synchronized void finishTask(Task task) { if (task != null) { task.setState(Task.State.FINISHED); queue.remove(task); } } // 取得一项待执行任务 public synchronized Task getTask() { Iterator it = queue.iterator(); Task task; while (it.hasNext()) { task = it.next(); // 寻找一个新建的任务 if (Task.State.NEW.equals(task.getState())) { // 把任务状态置为运行中 task.setState(Task.State.RUNNING); return task; } } return null; } }

addTask(Task task)方法用于当一个新的任务到达时,将它添加到任务队列中。这里使用了LinkedList类来保存任务到达的先后顺序。finishTask(Task task)方法用于任务被执行完毕时,将它从任务队列中清除出去。getTask()方法用于取得当前要执行的任务。
TaskThread(执行任务的线程):它继承自Thread类,专门用于执行任务队列中的待执行任务。
public class TaskThread extends Thread { // 该线程所属的线程池 private ThreadPoolService service; public TaskThread(ThreadPoolService tps) { service = tps; } public void run() { // 在线程池运行的状态下执行任务队列中的任务 while (service.isRunning()) { TaskQueue queue = service.getTaskQueue(); Task task = queue.getTask(); if (task != null) { task.deal(); } queue.finishTask(task); } } }
ThreadPoolService(线程池服务类):这是线程池最核心的一个类。它在被创建了时候就创建了几个线程对象,但是这些线程并没有启动运行,但调用了start()方法启动线程池服务时,它们才真正运行。stop()方法可以停止线程池服务,同时停止池中所有线程的运行。而runTask(Task task)方法是将一个新的待执行任务交与线程池来运行。
ThreadPoolService类的定义如下:
import java.util.ArrayList; import java.util.List; public class ThreadPoolService { // 线程数 public static final int THREAD_COUNT = 5; // 线程池状态 private Status status = Status.NEW; private TaskQueue queue = new TaskQueue(); public enum Status { /* 新建 /NEW, / 提供服务中 /RUNNING, / 停止服务 */TERMINATED, } private List threads = new ArrayList(); public ThreadPoolService() { for (int i = 0; i < THREAD_COUNT; i++) { Thread t = new TaskThread(this); threads.add(t); } } // 启动服务 public void start() { this.status = Status.RUNNING; for (int i = 0; i < THREAD_COUNT; i++) { threads.get(i).start(); } } // 停止服务 public void stop() { this.status = Status.TERMINATED; } // 是否正在运行 public boolean isRunning() { return status == Status.RUNNING; } // 执行任务 public void runTask(Task task) { queue.addTask(task); } protected TaskQueue getTaskQueue() { return queue; } }

完成了上面四个类,我们就实现了一个简单的线程池。现在我们就可以使用它了,下面的代码做了一个简单的示例:
public class SimpleTaskTest extends Task { @Override public void deal() { // do something } public static void main(String[] args) throws InterruptedException { ThreadPoolService service = new ThreadPoolService(); service.start(); // 执行十次任务 for (int i = 0; i < 10; i++) { service.runTask(new SimpleTaskTest()); } // 睡眠1秒钟,等待所有任务执行完毕 Thread.sleep(1000); service.stop(); } }

当然,我们实现的是最简单的,这里只是为了演示线程池的实现原理。在实际应用中,根据情况的不同,可以做很多优化。比如:
调整任务队列的规则,给任务设置优先级,级别高的任务优先执行。
动态维护线程池,当待执行任务数量较多时,增加线程的数量,加快任务的执行速度;当任务较少时,回收一部分长期闲置的线程,减少对系统资源的消耗。

事实上Java5.0及以上版本已经为我们提供了线程池功能,无需再重新实现。这些类位于java.util.concurrent包中。

Executors类提供了一组创建线程池对象的方法,常用的有一下几个:
public static ExecutorService newCachedThreadPool() { // other code } public static ExecutorService newFixedThreadPool(int nThreads) { // other code } public static ExecutorService newSingleThreadExecutor() { // other code }

newCachedThreadPool()方法创建一个动态的线程池,其中线程的数量会根据实际需要来创建和回收,适合于执行大量短期任务的情况;newFixedThreadPool(int nThreads)方法创建一个包含固定数量线程对象的线程池,nThreads代表要创建的线程数,如果某个线程在运行的过程中因为异常而终止了,那么一个新的线程会被创建和启动来代替它;而newSingleThreadExecutor()方法则只在线程池中创建一个线程,来执行所有的任务。

这三个方法都返回了一个ExecutorService类型的对象。实际上,ExecutorService是一个接口,它的submit()方法负责接收任务并交与线程池中的线程去运行。submit()方法能够接受Callable和Runnable两种类型的对象。它们的用法和区别如下:
Runnable接口:继承Runnable接口的类要实现它的run()方法,并将执行任务的代码放入其中,run()方法没有返回值。适合于只做某种操作,不关心运行结果的情况。
Callable接口:继承Callable接口的类要实现它的call()方法,并将执行任务的代码放入其中,call()将任务的执行结果作为返回值。适合于执行某种操作后,需要知道执行结果的情况。

无论是接收Runnable型参数,还是接收Callable型参数的submit()方法,都会返回一个Future(也是一个接口)类型的对象。该对象中包含了任务的执行情况以及结果。调用Future的boolean isDone()方法可以获知任务是否执行完毕;调用Object get()方法可以获得任务执行后的返回结果,如果此时任务还没有执行完,get()方法会保持等待,直到相应的任务执行完毕后,才会将结果返回。

我们用下面的一个例子来演示Java5.0中线程池的使用:
import java.util.concurrent.*; public class ExecutorTest { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService es = Executors.newSingleThreadExecutor(); Future fr = es.submit(new RunnableTest());// 提交任务 Future fc = es.submit(new CallableTest());// 提交任务 // 取得返回值并输出 System.out.println((String) fc.get()); // 检查任务是否执行完毕 if (fr.isDone()) { System.out.println(“执行完毕-RunnableTest.run()”); } else { System.out.println(“未执行完-RunnableTest.run()”); } // 检查任务是否执行完毕 if (fc.isDone()) { System.out.println(“执行完毕-CallableTest.run()”); } else { System.out.println(“未执行完-CallableTest.run()”); } // 停止线程池服务 es.shutdown(); } } class RunnableTest implements Runnable { public void run() { System.out.println(“已经执行-RunnableTest.run()”); } } class CallableTest implements Callable { public Object call() { System.out.println(“已经执行-CallableTest.call()”); return “返回值-CallableTest.call()”; } }

运行结果:
已经执行-RunnableTest.run()
已经执行-CallableTest.call()
返回值-CallableTest.call()
执行完毕-RunnableTest.run()
执行完毕-CallableTest.run()

springmvc和mybatis面试题(含答案)

Spring MVC Framework有这样一些特点:

1。它是基于组件技术的.全部的应用对象,无论控制器和视图,还是业务对象之类的都是java组件.并且和Spring提供的其他基础结构紧密集成.
2。不依赖于Servlet API(目标虽是如此,但是在实现的时候确实是依赖于Servlet的)
3。可以任意使用各种视图技术,而不仅仅局限于JSP
4。支持各种请求资源的映射策略
5。它应是易于扩展的
1
2
3
4
5
2) SpringMVC的工作流程?

  1. 用户发送请求至前端控制器DispatcherServlet
  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器。
  3. 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
  4. DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
  5. 执行处理器(Controller,也叫后端控制器)。
  6. Controller执行完成返回ModelAndView
  7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
  8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器
  9. ViewReslover解析后返回具体View
  10. DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
  11. DispatcherServlet响应用户
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
  1. 如果你也用过struts2.简单介绍下springMVC和struts2的区别有哪些?
  1. springmvc的入口是一个servlet即前端控制器,而struts2入口是一个filter过虑器。
  2. springmvc是基于方法开发(一个url对应一个方法),请求参数传递到方法的形参,可以设计为单例或多例(建议单例),struts2是基于类开发,传递参数是通过类的属性,只能设计为多例。
  3. Struts采用值栈存储请求和响应的数据,通过OGNL存取数据, springmvc通过参数解析器是将request请求内容解析,并给方法形参赋值,将数据和视图封装成ModelAndView对象,最后又将ModelAndView中的模型数据通过reques域传输到页面。Jsp视图解析器默认使用jstl。
    1
    2
    3
  1. SpringMvc原理图
    这里写图片描述

  2. SSM优缺点、使用场景?

  1. Mybatis和hibernate不同,它不完全是一个ORM框架,因为MyBatis需要程序员自己编写Sql语句,不过mybatis可以通过XML或注解方式灵活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的sql,最后将sql执行的结果再映射生成java对象。

  2. Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁,一但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql映射文件,工作量大。

  3. Hibernate对象/关系映射能力强,数据库无关性好,对于关系模型要求高的软件(例如需求固定的定制化软件)如果用hibernate开发可以节省很多代码,提高效率。但是Hibernate的学习门槛高,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样用好Hibernate需要具有很强的经验和能力才行。

  4. 总之,按照用户的需求在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架构,所以框架只有适合才是最好。
    1
    2
    3
    4
    5
    6
    Mybatis

  1. 简单介绍下你对mybatis的理解?
  1. mybatis配置
  2. SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
  3. mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
  4. 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
  5. 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
  6. mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
  7. Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
  8. Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
  9. Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

一、事务的基本要素(ACID)

1、原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。

2、一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。

3、隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。

4、持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。

二、事务的并发问题

1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

三、MySQL事务隔离级别

事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted) 是 是 是
不可重复读(read-committed) 否 是 是
可重复读(repeatable-read) 否 否 是
串行化(serializable) 否 否 否

mysql默认的事务隔离级别为repeatable-read

你可能感兴趣的:(总结)