代码编织梦想

给大家总结了几种不适合咱们进的公司,有以下几种情况:一,项目着急上线,进去后就要加班,压力大节奏紧,不容易生存;二、技术栈比较偏门冷门,不适合做,不利于后期跳槽,三,后端人数太少,活重;四、内网开发;五、让Java干前端,胜任度有点难,六、项目正常后端人数正常,不过进去后就直接让开干,不给项目熟悉和缓冲期,这种适合心理强大技术比较好的伙伴,否则也有点够呛;七、严防小外包,派的项目可能是短期的或者不太靠谱的,遇到特殊情况小外包人员是先被遣散的,这几种情况,可以拿到offer后委婉问下,掉坑机率小一些

所以,我们拿到offer后,可以问下企业,第一,目前项目主要的进度怎么样,是新开的项目,还是即将要上线的项目,还是开发中期或者后期持续更新迭代的项目,第二,后端人数有多少,第三,进去后项目主要用什么技术栈较多,需不需要我们负责前端开发,第四,如果有幸进入贵公司,是直接开始上手分需求做项目,还是给1周时间先让看文档熟悉项目

1.深拷贝和浅拷贝的区别是什么?truncate和delete

​ 浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然 指向原来的对象.换言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象.

​ 深拷贝:被复制对象的所有变量都含有与原来的对象相同的值.而那些引用其他对象的变量将指 向被复制过的新对象.而不再是原有的那些被引用的对象.换言之.深拷贝把要复制的对象所引用 的对象都复制了一遍.

2.String 是基本数据类型吗?

​ 不是的,基本数据类型只包括 byte、int、char、long、float、double、boolean 和 short。 java.lang.String 类是 final 类型的,因此不可以继承这个类、不能修改这个类。为了提高效 率节省空间,我们应该用 StringBuffer 类

3.什么是反射?

​ 反射就是动态加载对象,并对对象进行剖析。在运行状态中,对于任意一个类,都能够知 道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法,这种动态获取 信息以及动态调用对象方法的功能成为 Java 反射机制。

4.JDK 和 JRE 的区别是什么?

​ Java 运行时环境(JRE)是将要执行 Java 程序的 Java 虚拟机。它同时也包含了执行 applet 需要 的浏览器插件。Java 开发工具包(JDK)是完整的 Java 软件开发包,包含了 JRE,编译器和其他的 工具(比如:JavaDoc,Java 调试器),可以让开发者开发、编译、执行 Java 应用程序。

5.什么是迭代器(Iterator)?

​ Iterator 接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返回迭代器 实例的迭代方法。迭代器可以在迭代的过程中删除底层集合的元素。 克隆(cloning)或者是序列化(serialization)的语义和含义是跟具体的实现相关的。因此,应该 由集合类的具体实现来决定如何被克隆或者是序列化。 Iterator 可用来遍历 Set 和 List 集合,但是 ListIterator 只能用来遍历 List。

6.谈谈对 NIO 的认知?

​ 对于 NIO,它是非阻塞式,核心类: 1.Buffer 为所有的原始类型提供 (Buffer)缓存支持。 2.Charset 字符集编码解码解决方案 3.Channel 一个新的原始 I/O 抽象,用于读写 Buffer 类型,通道可以认为是一种连接,可以是 到特定设备,程序或者是网络的连接。

7.NIO 和传统的 IO 有什么区别?

​ 传统 io 的管道是单向的,nio 的管道是双向的。传统 IO 一般是一个线程等待连接。两者都是同步的,也就是 java 程序亲力亲为的去读写数据,不管传统 io 还是 nio 都需要 read 和 write 方法。

8.什么是 Java 序列化,如何实现 Java 序列化?

​ 序列化就是一种用来处理对象流的机制,将对象的内容进行流化。可以对流化后的对象进行读写 操作,可以将流化后的对象传输于网络之间。序列化是为了解决在对象流读写操作时所引发的问 题。序列化的实现:将需要被序列化的类实现 Serialize 接口,没有需要实现的方法,此接口只 是为了标注对象可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个 ObjectOutputStream(对象流)对象,再使用 ObjectOutputStream 对象的 write(Object obj)方 法就可以将参数 obj 的对象写出。

9.什么是节点流,什么是处理流,有什么好处?

节点流 直接与数据源相连,用于输入或者输出 处理流:在节点流的基础上对之进行加工,进行一些功能的扩展 处理流的构造器必须要 传入节点流的子类

10.Java 中有几种类型的流?

​ 按照流的方向:输入流(inputStream)和输出流(outputStream) 按照实现功能分:节点流(可以从或向一个特定的地方(节点)读写数据。如 FileReader)和 处理流(是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如 BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流 的多次包装,称为流的链接) 按照处理数据的单位:字节流和字符流。字节流继承于 InputStream 和 OutputStream 字符流继 承于 InputStreamReader 和 OutputStreamWriter。

11.如何实现对象克隆?

有两种方式:

1). 实现 Cloneable 接口并重写 Object 类中的 clone()方法;

2). 实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克 隆

12.session 和 cookie 的区别?

​ session 是存储在服务器端,cookie 是存储在客户端的,所以安全来讲 session 的安全性要比 cookie 高,然后我们获取 session 里的信息是通过存放在会话 cookie 里的 sessionid 获取的。 又由于session是存放在服务器的内存中,所以session里的东西不断增加会造成服务器的负担, 所以会把很重要的信息存储在 session 中,而把一些次要东西存储在客户端的 cookie 里。

​ 然后 cookie 确切的说分为两大类分为会话 cookie 和持久化 cookie,会话 cookie 确切的说是, 存放在客户端浏览器的内存中,所以说他的生命周期和浏览器是一致的,浏览器关了会话 cookie 也就消失了,然而持久化 cookie 是存放在客户端硬盘中,而持久化 cookie 的生命周期就是我们 在设置 cookie 时候设置的那个保存时间。

13.servlet 的生命周期?

​ Servlet 生命周期可以分成四个阶段:加载和实例化、初始化、服务、销毁。 当客户第一次请求时,首先判断是否存在 Servlet 对象,若不存在,则由 Web 容器创建对象, 而后调用 init()方法对其初始化,此初始化方法在整个 Servlet 生命周期中只调用一次。 完成 Servlet 对象的创建和实例化之后,Web 容器会调用 Servlet 对象的 service()方法来 处理请求。 当 Web 容器关闭或者 Servlet 对象要从容器中被删除时,会自动调用 destory()方法。

14.jsp 和 servlet 的区别,共同点,各自应用的范围?

​ JSP 是 Servlet 技术的扩展,本质上就是 Servlet 的简易方式。JSP 编译后是“类 servlet”。 Servlet 和 JSP 最主要的不同点在于,Servlet 的应用逻辑是在 Java 文件中,并且完全从表示层中的 HTML 里分离开来。而 JSP 的情况是 Java 和 HTML 可以组合成一个扩展名为.jsp 的文件。 JSP 侧重于视图,Servlet 主要用于控制逻辑。在 struts 框架中,JSP 位于 MVC 设计模式的视图层, 而 Servlet 位于控制层.

15.JDBC 访问数据库的基本步骤是什么?

第一步:Class.forName()加载数据库连接驱动;

第二步:DriverManager.getConnection()获取数据连接对象;

第三步:根据 SQL 获取 sql 会话对象,有 2 种方式 Statement、PreparedStatement ;

第四步:执行 SQL,执行 SQL 前如果有参数值就设置参数值 setXXX();

第五步:处理结果集;

第六步:关闭结果集、关闭会话、关闭连接。

16.数据库连接池的原理,为什么要使用连接池

1、数据库连接是一件费时的操作,连接池可以使多个操作共享一个连接。

2、数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定 数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。 我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通 过连接池的管理机制监视数据库的连接的数量、使用情况,为系统开发,测试及性能调整提供依 据。

3、使用连接池是为了提高对数据库连接资源的管理

17.JDBC 的 ResultSet 是什么?

​ 在查询数据库后会返回一个 ResultSet,它就像是查询结果集的一张数据表。
ResultSet 对象维护了一个游标,指向当前的数据行。开始的时候这个游标指向的是第一行。如 果调用了 ResultSet 的 next()方法游标会下移一行,如果没有更多的数据了,next()方法会返 回 false。可以在 for 循环中用它来遍历数据集。
默认的 ResultSet 是不能更新的,游标也只能往下移。也就是说你只能从第一行到最后一行遍历 一遍。不过也可以创建可以回滚或者可更新的 ResultSet
当生成 ResultSet 的 Statement 对象要关闭或者重新执行或是获取下一个 ResultSet 的时候, ResultSet 对象也会自动关闭。
可以通过 ResultSet 的 getter 方法,传入列名或者从 1 开始的序号来获取列数据。

18.什么是 Servlet?

​ Servlet 是使用 Java Servlet 应用程序接口(API)及相关类和方法的 Java 程序,所有的 Servlet 都必须要实现的核心接口是 javax.servlet.servlet。每一个 servlet 都必须要直接或者间接实 现这个接口,或者继承 javax.servlet.GenericServlet 或 javax.servlet.HTTPServlet。 Servlet 主要用于处理客户端传来的 HTTP 请求,并返回一个响应。

19.JSP 常用的指令?

page:针对当前页面的指令。

include:包含另一个页面

taglib:定义和访问自定义标签

20.JSP 的四大范围?

JSP 中的四种作用域包括 page、request、session 和 application,具体来说: page 代表与一个页面相关的对象和属性。

request 代表与 Web 客户机发出的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉 及多个 Web 组件;需要在页面显示的临时数据可以置于此作用域。

session 代表与某个用户与服务器建立的一次会话相关的对象和属性。跟某个用户相关的数据应 该放在用户自己的 session 中。

application 代表与整个 Web 应用程序相关的对象和属性,它实质上是跨越整个 Web 应用程序, 包括多个页面、请求和会话的一个全局作用域。

21.说出 Servlet 的生命周期?

​ Web 容器加载 Servlet 并将其实例化后,Servlet 生命周期开始,容器运行其 init 方法进行 Servlet 的初始化,请求到达时运行其 service 方法,service 方法自动派遣运行与请求对应的 doXXX 方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用其 destroy 方法。

22.如何防止表单重复提交?

针对于重复提交的整体解决方案:

1.用 redirect(重定向)来解决重复提交的问题

2.点击一次之后,按钮失效
3.通过 loading(Loading 原理是在点击提交时,生成 Loading 样式,在提交完成之后隐藏该样式)
4.自定义重复提交过滤器

23.响应乱码?

1、原因: 由服务器编码,默认使用 ISO-8859-1 进行编码 由浏览器解码,默认使用 GBK 进行解码

2、解决方案

方法 1:设置响应头 response.setHeader(“Content-Type”,“text/html;charset=utf-8”);

方法 2:设置响应的内容类型 response.setContentType(“text/html;charset=utf-8”); 通过这种方式可以在响应头中告诉浏览器响应体的编码方式是 UTF-8;同时服务器也会采 用该字符集进行编码 但需要注意的是,两种方法一定要在 response.getWriter()之前进行。

24.Cookie 对象的缺陷?

1、Cookie 是明文的,不安全

2、不同的浏览器对 Cookie 对象的数量和大小有限制

3、Cookie 对象携带过多费流量

4、Cookie 对象中的 value 值只能是字符串,不能放对象、网络中传递数据只能是字符串

25.Session 的运行机制?

1、在服务器端创建 Session 对象,该对象有一个全球唯一的 ID

2、 在创建Session对象的同时创建一个特殊的Cookie对象,该Cookie对象的名字是JSESSIONID, 该 Cookie 对象的 value 值是 Session 对象的那个全球唯一的 ID,并且会将这个特殊的 Cookie 对象携带发送给浏览器

3、以后浏览器再发送请求就会携带这个特殊的 Cookie 对象

4、服务器根据这个特殊的 Cookie 对象的 value 值在服务器中寻找对应的 Session 对象,以此来 区分不同的用户

26.BIO 和 NIO 和 AIO 的区别以及应用场景?

同步:java 自己去处理 io。

异步:java 将 io 交给操作系统去处理,告诉缓存区大小,处理完成回调。

阻塞:使用阻塞 IO 时,Java 调用会一直阻塞到读写完成才返回。

非阻塞:使用非阻塞 IO 时,如果不能立马读写,Java 调用会马上返回,当 IO 事件分发器通知 可读写时在进行读写,不断循环直到读写完成。

BIO:同步并阻塞,服务器的实现模式是一个连接一个线程,这样的模式很明显的一个缺陷是: 由于客户端连接数与服务器线程数成正比关系,可能造成不必要的线程开销,严重的还将导致服 务器内存溢出。当然,这种情况可以通过线程池机制改善,但并不能从本质上消除这个弊端。

NIO:在 JDK1.4 以前,Java 的 IO 模型一直是 BIO,但从 JDK1.4 开始,JDK 引入的新的 IO 模型 NIO,它是同步非阻塞的。而服务器的实现模式是多个请求一个线程,即请求会注册到多路复用 器 Selector 上,多路复用器轮询到连接有 IO 请求时才启动一个线程处理。

AIO:JDK1.7 发布了 NIO2.0,这就是真正意义上的异步非阻塞,服务器的实现模式为多个有效请 求一个线程,客户端的 IO 请求都是由 OS 先完成再通知服务器应用去启动线程处理(回调)。

应用场景:并发连接数不多时采用 BIO,因为它编程和调试都非常简单,但如果涉及到高并发的 情况,应选择 NIO 或 AIO,更好的建议是采用成熟的网络通信框架 Netty。

27.Filter 的工作原理?

Filter 接口中有一个 doFilter 方法,当我们编写好 Filter,并配置对哪个 web 资源进行拦截后, WEB 服务器每次在调用 web 资源的 service 方法之前, 都会先调用一下 filter 的 doFilter 方法,因此,在该方法内编写代码可达到如下

目的:

调用目标资源之前,让一段代码执行。

是否调用目标资源(即是否让用户访问 web 资源)。

调用目标资源之后,让一段代码执行。 web 服务器在调用 doFilter 方法时,会传递一个 filterChain 对象进来,filterChain 对象 是 filter 接口中最重要的一个对象,它也提供了一个 doFilter 方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则 web 服务器就会 调用 web 资源的 service 方法,即 web 资源就会被访问, 否则 web 资源不会被访问

28.监听器类型?

按监听的对象划分:servlet2.4 规范定义的事件有三种:

1.用于监听应用程序环境对象(ServletContext)的事件监听器

2.用于监听用户会话对象(HttpSession)的事件监听器

3.用于监听请求消息对象(ServletRequest)的事件监听器

按监听的事件类项划分

1.用于监听域对象自身的创建和销毁的事件监听器

2.用于监听域对象中的属性的增加和删除的事件监听器

3.用于监听绑定到 HttpSession 域中的某个对象的状态的事件监听器 在一个 web 应用程序的整个运行周期内,web 容器会创建和销毁三个重要的对象, ServletContext,HttpSession,ServletRequest。

29.Servlet,Filter,Listener 启动顺序?

启动的顺序为 listener->Filter->servlet.

简单记为:理(Listener)发(Filter)师(servlet).

执行的顺序不会因为三个标签在配置文件中的先后顺序而改变。

30.常用的日志框架?

1.Slf4j

​ slf4j 的全称是 Simple Loging Facade For Java,即它仅仅是一个为 Java 程序提供日志输出 的统一接口,并不是一个具体的日志实现方案,就比如 JDBC 一样,只是一种规则而已。所以单 独 的 slf4j 是 不能 工作 的, 必须 搭配 其 他具 体的 日志 实现 方案 ,比 如 apache 的 org.apache.log4j.Logger,jdk 自带的 java.util.logging.Logger 等。

2.Log4j

​ Log4j 是 Apache 的一个开源项目,通过使用 Log4j,我们可以控制日志信息输送的目的地是控 制台、文件、GUI 组件,甚至是套接口服务器、NT 的事件记录器、UNIX Syslog 守护进程等; 我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地 控制日志的生成过程。 Log4j 由三个重要的组成构成:日志记录器(Loggers),输出端(Appenders) 和日志格式化器(Layout)。

​ 1.Logger:控制要启用或禁用哪些日志记录语句,并对日志信息进行级别限制

​ 2.Appenders : 指定了日志将打印到控制台还是文件中

​ 3.Layout : 控制日志信息的显示格式 Log4j 中将要输出的 Log 信息定义了 5 种级别,依次为 DEBUG、INFO、WARN、ERROR 和 FATAL, 当输出时,只有级别高过配置中规定的 级别的信息才能真正的输出,这样就很方便的来配置不 同情况下要输出的内容,而不需要更改代码。

3.LogBack

​ 简单地说,Logback 是一个 Java 领域的日志框架。它被认为是 Log4J 的继承人。

31.加密算法算法有哪些?

AES

​ 高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密 传输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥,具体的加密流程

RSA

​ RSA 加密算法是一种典型的非对称加密算法,它基于大数的因式分解数学难题,它也是应用最广 泛的非对称加密算法。非对称加密是通过两个密钥(公钥-私钥)来实现对数据的加密和解密的。公钥用于加密,私钥 用于解密

CRC

​ 循环冗余校验(Cyclic Redundancy Check, CRC)是一种根据网络数据包或电脑文件等数据产生简 短固定位数校验码的一种散列函数,主要用来检测或校验数据传输或者保存后可能出现的错误。 它是利用除法及余数的原理来作错误侦测的。

MD5 摘要算法,严格来说不叫加解密算法 MD5 常常作为文件的签名出现,我们在下载文件的时候,常常会看到文件页面上附带一个扩展名 为.MD5 的文本或者一行字符,这行字符就是就是把整个文件当作原数据通过 MD5 计算后的值, 我们下载文件后,可以用检查文件 MD5 信息的软件对下载到的文件在进行一次计算。两次结果 对比就可以确保下载到文件的准确性。 另一种常见用途就是网站敏感信息加密,比如用户名 密码, 支付签名等等。随着 https 技术的普及,现在的网站广泛采用前台明文传输到后台,MD5 加密(使用偏移量)的方式保护敏感数据保护站点和数据安全。

32.JVM Java 的内存划分?

第一、程序计数器(PC,Program Counter Register)。在 JVM 规范中,每个线程都有它自己的程序 计数器,并且任何时间一个线程都只有一个方法在执行,也就是所谓的当前方法。程序计数器会 存储当前线程正在执行的 Java 方法的 JVM 指令地址;或者,如果是在执行本地方法,则是未 指定值(undefined)。(唯一不会抛出 OutOfMemoryError)

第二,Java 虚拟机栈(Java Virtual Machine Stack),早期也叫 Java 栈。每个线程在创建 时都会创建一个虚拟机栈,其内部保存一个个的栈帧(Stack Frame),对应着一次次的 Java 方 法调用。

第三,堆(Heap),它是 Java 内存管理的核心区域,用来放置 Java 对象实例,几乎所有创建 的 Java 对象实例都是被直接分配在堆上。堆被所有的线程共享,在虚拟机启动时,我们指定的 “Xmx”之类参数就是用来指定最大堆空间等指标。

第四,方法区(Method Area)。这也是所有线程共享的一块内存区域,用于存储所谓的元(Meta) 数据,例如类结构信息,以及对应的运行时常量池、字段、方法代码等。

第五,运行时常量池(Run-Time Constant Pool),这是方法区的一部分。如果仔细分析过反编 译的类文件结构,你能看到版本号、字段、方法、超类、接口等各种信息,还有一项信息就是常 量池。Java 的常量池可以存放各种常量信息,不管是编译期生成的各种字面量,还是需要在运 行时决定的符号引用,所以它比一般语言的符号表存储的信息更加宽泛。

第六,本地方法栈(Native Method Stack)。它和 Java 虚拟机栈是非常相似的,支持对本地 方法的调用,也是每个线程都会创建一个。在 Oracle Hotspot JVM 中,本地方法栈和 Java 虚 拟机栈是在同一块儿区域,这完全取决于技术实现的决定,并未在规范中强制。

33.什么是 Java 虚拟机,为什么 Java 被称作是无关平台的编程语言?

​ Java 虚拟机是一个可以执行 Java 字节码的虚拟机进程。Java 源文件被编译成能被 Java 虚拟机 执行的字节码文件。 Java 被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每 一个平台单独重写或者是重新编译。Java 虚拟机让这个变为可能,因为它知道底层硬件平台的 指令长度和其他特性

34.如何判断一个对象应该被回收?

1)在 Java 中采取了 可达性分析法,通过一系列的“GC Roots”对象作为起点进行搜索,如果在“GC Roots”和一个对象之间没有可 达路径,则称该对象是不可达的,不过要注意的是被判定为不可达的对象不一定就会成为可回收 对象。被判定为不可达的对象要成为可回收对象必须至少经历两次标记过程,如果在这两次标记 过程中仍然没有逃脱成为可回收对象的可能性,则基本上就真的成为可回收对象了。

2)虚拟机栈中引用的对象、方法区类静态属性引用的对象、方法区常量池引用的对象、本地方法 栈 JNI 引用的对象

35.GC 触发的条件?

1)程序调用 System.gc 时可以触发;

(2)系统自身来决定 GC 触发的时机

36.JVM 中一次完整的 GC 流程是怎样的,对象如何晋升到老年代?

Java 堆 = 老年代 + 新生代

新生代 = Eden + S0 + S1

当 Eden 区的空间满了, Java 虚拟机会触发一次 Minor GC,以收集新生代的垃圾,存活下来 的对象,则会转移到 Survivor 区。

大对象(需要大量连续内存空间的 Java 对象,如那种很长的字符串)直接进入老年态;

如果对象在 Eden 出生,并经过第一次 Minor GC 后仍然存活,并且被 Survivor 容纳的话,年龄 设为 1,每熬过一次 Minor GC,年龄+1,若年龄超过一定限制(15),则被晋升到老年态。即长 期存活的对象进入老年态。

老年代满了而无法容纳更多的对象,Minor GC 之后通常就会进行 Full GC,Full GC 清理整个 内存堆 – 包括年轻代和年老代。

Major GC 发生在老年代的 GC,清理老年区,经常会伴随至少一次 Minor GC,比 Minor GC 慢 10 倍以上。

37.双亲委派模型?

双亲委派模型工作过程是:

如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派 给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的 类时(即 ClassNotFoundException),子加载器才会尝试自己去加载。

38.为什么需要双亲委派模型?

防止内存中出现多份同样的字节码

39.怎么打破双亲委派模型?

打破双亲委派机制则不仅要继承 ClassLoader 类,还要重写 loadClass 和 findClass 方法。

40.导致 Full GC 一般有哪些情况?

1).新生代设置过小

​ 一是新生代 GC 次数非常频繁,增大系统消耗;二是导致大对象直接进入旧生代,占据了旧生 代剩余空间,诱发 Full GC

2). 新生代设置过大

​ 一是新生代设置过大会导致旧生代过小(堆总量一定),从而诱发 Full GC;

​ 二是新生代 GC 耗 时大幅度增加

3). Survivor 设置过小 导致对象从 eden 直接到达旧生代

4). Survivor 设置过大 导致 eden 过小,增加了 GC 频率 一般说来新生代占整个堆 1/3 比较合适

GC 策略的设置方式 1). 吞吐量优先 可由-XX:GCTimeRatio=n 来设置 2). 暂停时间优先 可由-XX:MaxGCPauseRatio=n 来设置

41.JVM 性能调优?

1、设定堆内存大小 -Xmx:堆内存最大限制。

2、设定新生代大小。 新生代不宜太小,否则会有大量对象涌入老年代 -XX:NewSize:新生代大小 -XX:NewRatio 新生代和老生代占比 -XX:SurvivorRatio:伊甸园空间和幸存者空间的占比

3、设定垃圾回收器 年轻代用 -XX:+UseParNewGC 年老代用-XX:+UseConcMarkSweepGC

42.垃圾回收算法有哪些,简述其原理?

GC 最基础的算法有三种: 标记 -清除算法、复制算法、标记-压缩算法,我们常用的垃圾回收 器一般都采用分代收集算法。

标记 -清除算法,“标记-清除”(Mark-Sweep)算法,如它的名字一样,算法分为“标记”和 “清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对 象。

复制算法,“复制”(Copying)的收集算法,它将可用内存按容量划分为大小相等的两块,每 次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后 再把已使用过的内存空间一次清理掉。

标记-压缩算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进 行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存

43.Java 中类的生命周期是什么?

1、加载,查找并加载类的二进制数据,在 Java 堆中也创建一个 java.lang.Class 类的对象

2、连接,连接又包含三块内容:验证、准备、初始化。 1)验证,文件格式、元数据、字节码、 符号引用验证; 2)准备,为类的静态变量分配内存,并将其初始化为默认值; 3)解析,把类 中的符号引用转换为直接引用

3、初始化,为类的静态变量赋予正确的初始值

4、使用,new 出对象程序中使用 5、卸载,执行垃圾回收

44.JVM 调优命令?

Sun JDK 监控和故障处理命令有 jps jstat jmap jhat jstack jinfo

45.描述一下 JVM 加载 class 的原理?

JVM 中类的装载是由类加载器(ClassLoader)和它的子类来实现的,Java 中的类加载器是一个 重要的 Java 运行时系统组件,它负责在运行时查找和装入类文件中的类。类的加载是指把类 的.class 文件中的数据读入到内存中,通常是创建一个字节数组读入.class 文件

46.GC 是什么,为什么要有 GC?

GC 是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,

忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java 提供的 GC 功能可以自动监测对象是否超过作用域从而 达到自动回收内存的目的, Java 语言没有提供释放已分配内存的显示操作方法。

47.垃圾回收器的基本原理是什么?

对于 GC 来说,当程序员创建对象时,GC 就开始监控这个对象的地址、大小以及使用情况。通常, GC 采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的 “,哪些对象是"不可达的”。当 GC 确定一些对象为"不可达"时,GC 就有责任回收这些内存空间。 可以。程序员可以手动执行 System.gc(),通知 GC 运行,但是 Java 语言规范并不保证 GC 一定 会执行。

48.Jenkins

Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件项目可以进行持续集成

49.线程调用 start()和 run()的区别?

启动一个线程是调用 start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可 以由 JVM 调度并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来 停止一个线程。

50.synchronized 和 Volatile,CAS 比较?

synchronized 是悲观锁,属于抢占式,会引起其他线程阻塞。

volatile 提供多线程共享变量可见性和禁止指令重排序优化。

CAS 是基于冲突检测的乐观锁(非阻塞)

51.线程同步的方法?

wait():使一个线程处于等待状态,并且释放所持有的对象的 lock。 sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉 InterruptedException 异常。

notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某 一个等待状态的线程,而是由 JVM 确定唤醒哪个线程,而且不是按优先级。

notityAll():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让 它们竞争。

52.Java 中如何停止一个线程?

如果要手动结束一个线程,你可以用 volatile 布尔变量来 退出 run()方法的循环或者是取消任务来中断线程。

53.线程池的优点?

1)重用存在的线程,减少对象创建销毁的开销。

2)可有效的控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。

3)提供定时执行、定期执行、单线程、并发数控制等功能。

54.产生死锁的条件?

1、互斥条件:一个资源每次只能被一个进程使用。

2、请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

3、不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 4、循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

55.请写出实现线程安全的几种方式?

方式一:使用同步代码块

方式二:使用同步方法

方式三:使用 ReentrantLock

56.什么是线程?

线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。 程序

员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速

57.volatile 的理解?

volatile 关键字的两层语义

一旦一个共享变量(类的成员变量、类的静态成员变量)被 volatile 修饰之后,那么就具备了 两层语义:

1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值 对其他线程来说是立即可见的。

2)禁止进行指令重排序。 用 volatile 修饰之后,变量的操作:

第一:使用 volatile 关键字会强制将修改的值立即写入主存;

第二:使用 volatile 关键字的话,当线程 2 进行修改时,会导致线程 1 的工作内存中缓存变量 stop 的缓存行无效反映到硬件层的话,就是 CPU 的 L1 或者 L2 缓存中对应的缓存行无效;

第三:由于线程 1 的工作内存中缓存变量 stop 的缓存行无效,所以线程 1 再次读取变量 stop 的值时会去主存读取。

58.线程的生命周期?

当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。 在 线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞 (Blocked) 和死亡(Dead)5 种状态。尤其是当线程启动以后,它不可能一直"霸占"着 CPU 独自 运行,所以 CPU 需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换

59.公平锁与非公平锁?

公平锁 是指多个线程按照申请锁的顺序来获取锁,类似于排队买饭,先来后到,先来先服务,就是公平 的,也就是队列

非公平锁 是指多个线程获取锁的顺序,并不是按照申请锁的顺序,有可能申请的线程比先申请的线程优先 获取锁

60.可重入锁与不可重入锁?

可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生 死锁(前提是同一个对象或者类)

不可重入锁,与可重入锁相反,不可递归调用,递归调用就会发生死锁。

61.项目中使用了哪种线程池,使用场景是什么?

在项目中 我们对于数据查询加载使用线程池 比较多,比如商品的详情加载,商品的 sku 信息和 spu 信息 是 根据代码的顺序加载的,而且其中难免会有订单服务,远程调用商品服务查询 sku 信息这种耗时的程序,打个比方,查询商品的订单编号 = 50ms,查询商品的 sku 信息远程调用 =100ms,多个查询 多个远程调用 加 多个数据的封装返回 前端 接收 展示,一套下来 难免有 个 2-3s 的 时间 这还不包括别的,总体下来 要有个 5-6s ,但是在现在,去打开一个网页 如 果 4s 之内不给我出现响应,我直接就给关了 ,所以这就很考研我们代码的加载性能,我们在项 目中对这些 场景 使用线程池,进行异步加载的形式,调用多个线程进行异步加载,大大减少了 代码的运行时间。

后台系统实现数据的批量导入,采用线程池实现数据分片处理

62.共享锁和独占锁是什么?

java 并发包提供的加锁模式分为独占锁和共享锁。

独占锁

独占锁模式下,每次只能有一个线程能持有锁,ReentrantLock 就是以独占方式实现的互斥锁。 独占锁是一种悲观保守的加锁策略,它避免了读/读冲突,如果某个只读线程获取锁,则其他读 线程都只能等待,这种情况下就限制了不必要的并发性,因为读操作并不会影响数据的一致性。

共享锁

共享锁则允许多个线程同时获取锁,并发访问 共享资源,如:ReadWriteLock。共享锁则是一种 乐观锁,它放宽了加锁策略,允许多个执行读操作的线程同时访问共享资源。

1.AQS 的内部类 Node 定义了两个常量 SHARED 和 EXCLUSIVE,他们分别标识 AQS 队列中等待线 程的锁获取模式。

2.java 的并发包中提供了 ReadWriteLock,读-写锁。它允许一个资源可以被多个读操作访问, 或者被一个 写操作访问,但两者不能同时进行。

63.你对偏向锁是理解是什么?

偏向锁的目的是在某个线程获得锁之后,消除这个线程锁重入(CAS)的开销,看 起来让这个线程得到了偏护。

64.什么 CAS?

CAS(Compare And Swap/Set)比较并交换,CAS 算法的过程是这样:它包含 3 个参数 CAS(V,E,N)。V 表示要更新的变量(内存值),E 表示预期值(旧的),N 表示新值。当且仅当 V 值 等于 E 值时,才会将 V 的值设为 N,如果 V 值和 E 值不同,则说明已经有其他线程做了更新, 则当前线程什么都不做。最后,CAS 返回当前 V 的真实值。

CAS 操作是抱着乐观的态度进行的(乐观锁),它总是认为自己可以成功完成操作。当多个线程同 时使用 CAS 操作一个变量时,只有一个会胜出,并成功更新,其余均会失败。失败的线程不会 被挂起,仅是被告知失败,并且允许再次尝试,当然也允许失败的线程放弃操作。基于这样的原 理, CAS 操作即使没有锁,也可以发现其他线程对当前线程的干扰,并进行恰当的处理。

65.说一下你熟悉的设计模式?

单例模式:保证被创建一次,节省系统开销。

工厂模式(简单工厂、抽象工厂):解耦代码。

观察者模式:定义了对象之间的一对多的依赖,这样一来,当一个对象改变时,它的所有的依赖 者都会收到通知并自动更新。

外观模式:提供一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层的接口, 让子系统更容易使用。

66.设计模式的优点?

设计模式可在多个项目中重用。

设计模式提供了一个帮助定义系统架构的解决方案。

设计模式吸收了软件工程的经验。

设计模式为应用程序的设计提供了透明性。

设计模式是被实践证明切实有效的,由于它们是建立在专家软件开发人员的知识和经验之上 的。

67.ReentrantLock 的理解 互斥锁

ReentantLock 继承接口 Lock 并实现了接口中定义的方法,他是一种可重入锁,除了能完成 synchronized 所能完成的所有工作外,还提供了诸如可响应中断锁、可轮询锁请求、定时锁等 避免多线程死锁的方法。

非公平锁

68.MyBatis 的优点?

1、基于 SQL 语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL 写在 XML 里,解除 sql 与程序代码的耦合,便于统一管理;提供 XML 标签,支持编写动态 SQL 语句,并可重用。

2、与 JDBC 相比,减少了 50%以上的代码量,消除了 JDBC 大量冗余的代码,不需要手动开关连 接;

3、很好的与各种数据库兼容(因为 MyBatis 使用 JDBC 来连接数据库,所以只要 JDBC 支持的数 据库 MyBatis 都支持)。

4、能够与 Spring 很好的集成;

5、提供映射标签,支持对象与数据库的 ORM 字段关系映射;提供对象关系映射标签,支持对象 关系组件维护。

69.MyBatis 框架的缺点?

(1)SQL 语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写 SQL 语句的功 底有一定要求。

(2)SQL 语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

70.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 响应用户

71.SpringIOC 是什么?

Spring IOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理 这些对象的整个生命周期。

72.拦截器与过滤器的区别?

1、拦截器是基于 java 的反射机制的,而过滤器是基于函数回调

2、拦截器不依赖与 servlet 容器,过滤器依赖与 servlet 容器。

3、拦截器只能对 action 请求起作用,而过滤器则可以对几乎所有的请求起作用。

4、拦截器可以访问 action 上下文、值栈里的对象,而过滤器不能访问。 5、在 action 的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次

73.什么是 Spring bean?

它们是构成用户应用程序主干的对象。

Bean 由 Spring IoC 容器管理。

它们由 Spring IoC 容器实例化,配置,装配和管理。

Bean 是基于用户提供给容器的配置元数据创建。

单例模式 多例模式 HTTP请求(request) 会话 (Session)

74.@Component,@Controller,@Repository,@Service 有何区别?

1、@Component:这将 java 类标记为 bean。它是任何 Spring 管理组件的通用构造型。spring 的组件扫描机制现在可以将其拾取并将其拉入应用程序环境中。

2、 @Controller:这将一个类标记为 Spring Web MVC 控制器。标有它的 Bean 会自动导入到 IoC 容器中。

3、@Service:此注解是组件注解的特化。它不会对 @Component 注解提供任何其他行为。您可以在服务层类中使用 @Service 而不是 @Component,因为它以更好的方式指定了意图。

4、@Repository:这个注解是具有类似用途和功能的 @Component 注解的特化。它为 DAO 提供 了额外的好处。它将 DAO 导入 IoC 容器,并使未经检查的异常有资格转换为 Spring DataAccessException。

75.Mybatis 中#{}和${}的区别是什么?

#{}是预编译处理,${}是字符串替换。

Mybatis 在处理#{}时,会将 sql 中的#{}替换为?号,调用 PreparedStatement 的 set 方法来赋 值;

Mybatis 在处理 时,就是把 {}时,就是把 时,就是把{}替换成变量的值。所以可以拼接 SQL 关键字 使用#{}可以有效的防止 SQL 注入,提高系统安全性。

76.Spring bean 的生命周期?

1.Spring 容器根据配置中的 bean 定义中实例化 bean。

2.Spring 使用依赖注入填充所有属性,如 bean 中所定义的配置。

3.如果 bean 实现 BeanNameAware 接口,则工厂通过传递 bean 的 ID 来调用 setBeanName()。 如果 bean 实现 BeanFactoryAware 接口,工厂通过传递自身的实例来调用 setBeanFactory()。

4.如果存在与 bean 关联的任何 BeanPostProcessors 则调 preProcessBeforeInitialization() 方法。

5.如果为 bean 指定了 init 方法(的 init-method 属性)那么将调用它。

6.最后,如果存在与 bean 关联的任何 BeanPostProcessors,则将调用 postProcessAfterInitialization()方法。

7.如果 bean 实现 DisposableBean 接口,当 spring 容器关闭时,会调用 destory()。

8.如果为 bean 指定了 destroy 方法( 的 destroy-method 属性),那么将调用它。

77.Spring AOP(面向切面)编程的原理?

1、AOP 面向切面编程,它是一种思想。它就是针对业务处理过程中的切面进行提取,以达到优 化代码的目的,减少重复代码的目的。 就比如,在编写业务逻辑代码的时候,我们习惯性的都 要写:日志记录,事物控制,以及权限控制等,每一个子模块都要写这些代码,代码明显存在重 复。这时候,我们运用面向切面的编程思想,采用横切技术,将代码中重复的部分,不影响主业 务逻辑的部分抽取出来,放在某个地方进行集中式的管理,调用。 形成日志切面,事物控制切 面,权限控制切面。 这样,我们就只需要关系业务的逻辑处理,即提高了工作的效率,又使得 代码变的简洁优雅。这就是面向切面的编程思想,它是面向对象编程思想的一种扩展。

2、AOP 的使用场景: 缓存、权限管理、内容传递、错误处理、懒加载、记录跟踪、优化、校准、 调试、持久化、资源池、同步管理、事物控制等。 AOP 的相关概念: 切面(Aspect) 连接点 (JoinPoint) 通知(Advice) 切入点(Pointcut) 代理(Proxy): 织入(WeaVing)

3、Spring AOP 的编程原理? 代理机制 JDK 的动态代理:只能用于实现了接口的类产生代理。 Cglib 代理:针对没有实现接口的类产生代理,应用的是底层的字节码增强技术,生成当前类的 子类对象。

78.什么是 IOC,什么是 DI?

IOC:就是对象之间的依赖关系由容器来创建,对象之间的关系本来是由我们开发者自己创建和 维护的,在我们使用 Spring 框架后,对象之间的关系由容器来创建和维护,将开发者做的事让 容器做,这就是控制反转。BeanFactory 接口是 Spring Ioc 容器的核心接口。

DI:我们在使用 Spring 容器的时候,容器通过调用 set 方法或者是构造器来建立对象之间的依 赖关系。

控制反转是目标,依赖注入是我们实现控制反转的一种手段。

79.Spring 运行原理?

1、内部最核心的就是 IOC 了,之前是 new 对象,现在可以直接从容器中获取, 动态注入,这 其实就是利用 java 里的反射。反射其实就是在运行时动态的去创建、调用对象,Spring 就是在 运行时,根据 xml Spring 的配置文件来动态的创建对象,和调用对象里的方法的。

2、Spring 另一个核心就是 AOP 面向切面编程,可以为某一类对象 进行监督和控制(也就是在 调用这类对象的具体方法的前后去调用你指定的 模块)从而达到对一个模块扩充的功能。这些 都是通过配置类达到的。(日志、事务等)

3、Spring 目的:就是让对象与对象(模块与模块)之间的关系没有通过代码来关联,都是通过 配置类说明 管理的(Spring 根据这些配置 内部通过反射去动态的组装对象)要记住:Spring 是一个容器,凡是在容器里的对象才会有 Spring 所提供的这些服务和功能。

4、Spring 里用的最经典设计模式:模板方法模式。(有兴趣同学可以了解一下) 、核心容器 组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC)模式将应用程序 的配置和依赖性规范与实际的应用程序代码分开

80.Mybatis 的缓存策略:一级缓存与二级缓存?

一级缓存: SqlSession(连接对象)级别的缓存,同一个 SqlSession 的发起多次同构查询,会将数据保存在 一级缓存中。

在 sqlsession 中有一个数据结构是 map 结构,这个区域就是一级缓存区域,一级缓存区域中的 key 是由 sql 语句方法参数 statement 等组成的一个唯一值对应的 value 就是缓存内容,一级缓 存 map 的生命周期和当前 sqlSession 一致 注意:无需任何配置,默认开启一级缓存

二级缓存: SqlSessionFactory(连接 对象的 工厂)级别 的缓存 ,同一 个 SqlSessionFactory 构建的 SqlSession 发起的多次同构查询,会将数据保存在二级缓存中。

二级缓存指的是同一个 namespace 下的 mapper 二级缓存的数据结构,也是一个 map 二级缓存 需 要 手动开启

81.什么是 Redis 持久化,rdb 和 aof 的比较?

持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。

比较: 1、aof 文件比 rdb 更新频率高,优先使用 aof 还原数据。

2、aof 比 rdb 更安全也更大

3、rdb 性能比 aof 好

4、如果两个都配了优先加载 AOF

82.Redis 哈希槽的概念?

Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念,Redis 集群有 16384 个哈希槽, 每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽。

83.Redis 和数据库的数据一致性如何保证?

先解释一下 redis 和 数据库 怎么互动的 就是先 查 redis 没数据 去查数据库 存到 reids 然后如何保证?

首先 对于数据, 如果你选择强一致性,那就不能放缓存,所以,我们也就是仅仅能够保证最终 的一致性,如果要保证强一致性,那还是别用缓存了,我们尽量的去保证 redis 和数据库 数据 一致,只是说降低概率发生,而不能完全的避免,但是我们还是要说。

84.Redis 有哪些数据结构?
  1. String字符串类型
  2. List:列表类型
  3. Hash:哈希表类型
  4. Set:无序集合类型
  5. sorted set:有序集合类型
85.Redis 缓存穿透、缓存雪崩、缓存击穿?

缓存穿透:无效 ID,在 redis 缓存中查不到,去查询 DB,造成 DB 压力增大。

解决方法:

1、解决方法 1:布隆过滤器,提供一个很大的 Bit-Map,提供多个 hash 函数,分别对查询 参数值【比如 UUID】,进行求 hash,然后分别对多个 hash 结果,在对应位置对比是否全为 1 或 者某个位置为 0,一旦有一个位置标识为 0,表示本次查询 UUID,不存在于缓存,再去查询 DB.起 到一个再过滤的效果。

2、解决方法 2:把无效的 ID,也在 redis 缓存起来,并设置一个很短的超时时间。

缓存雪崩:缓存同一时间批量失效,导致大量的访问直接访问 DB

解决方法: 在做缓存时候,就做固定失效时间+随机时间段,保证所有的缓存不会同一时间失效

缓存击穿:在缓存失效的时候,会有高并发访问失效的缓存【热点数据】 解决方法: 最简单的解决方法,就是将热点数据设置永不超时!

第二个解决方法:对访问的 Key 加上互斥锁,请求的 Key 如果不存在,则加锁,去数据库取, 新请求过来,如果相同 KEy,则暂停 10s 再去缓存取值;如果 Key 不同,则直接去缓存取!

86.Redis 如何实现高并发?

redis 通过一主多从,主节点负责写,从节点负责读,读写分离,从而实现高并发。

87.Redis 如何实现高可用?

主备切换,哨兵集群,主节点宕机的情况下,自动选举出一个从节点变成主节点,从而保证了 redis 集群的高可用。

88.Redis 的哨兵机制的作用?

1、监控:Sentinel 会不断的检查主服务器和从服务器是否正常运行。

2、通知:当被监控的某个 redis 服务器出现问题,Sentinel 通过 API 脚本向管理员或者其他的 应用程序发送通知。

3、自动故障转移:当主节点不能正常工作时,Sentinel 会开始一次自动的故障转移操作,它会 将与失效主节点是主从关系 的其中一个从节点升级为新的主节点,并且将其他的从节点指向新 的主节点。

89.分布式缓存?

硬盘上的数据,缓存在别的计算机上(非程序运行的计算机)的内存上,而且可以缓存的计算机 的个数不止一个,可以使用 n 个用户通过访问 http 服务器,然后访问应用服务器资源,应用服 务器调用后端的数据库,在第一次访问的时候,直接访问数据库,然后将要缓存的内容放入到 memcached 集群,集群规模根据缓存文件的大小而定。在第二次访问的时候就直接进入缓存读取, 不需要进行数据库的操作。这个适合数据变化不频繁的场景,比如:互联网站显示的榜单,阅读 排行等。

90.Redis 的过期策略?

key 的生存时间到了,Redis 会立即删除吗?不会立即删除。

有以下几种策略:

定期删除:Redis 每隔一段时间就去会去查看 Redis 设置了过期时间的 key,会再 100ms 的间隔 中默认查看 3 个 key。

惰性删除:如果当你去查询一个已经过了生存时间的 key 时,Redis 会先查看当前 key 的生存时 间,是否已经到了,直接删除当前 key,并且给用户返回一个空值。

91.基于 Redis 分布式锁?

1.获取锁的时候,使用 setnx(SETNX key val:当且仅当 key 不存在时,set 一个 key 为 val 的字符串,返回 1;若 key 存在,则什么都不做,返回 0)加锁,锁的 value 值为一 个随机生成的 UUID,在释放锁的时候进行判断。并使用 expire 命令为锁添加一个超时时 间,超过该时间则自动释放锁。

2.获取锁的时候调用 setnx,如果返回 0,则该锁正在被别人使用,返回 1 则成功获取锁。 还设置一个获取的超时时间,若超过这个时间则放弃获取锁。

3.释放锁的时候,通过 UUID 判断是不是该锁,若是该锁,则执行 delete 进行锁释放。

92.Mysql 与 Redis 的数据一致性?

例如如果一个事务执行失败回滚了,但是如果采取了先写 Redis 的方式, 就会造成 Redis 和 MySQL 数据库的不一致,再比如说,一个事务写入了 MySQL,但是此时还未写入 Redis,如果这时候有 用户访问 Redis,则此时就会出现数据不一致。解决方案如下。

1、分别处理

针对某些对数据一致性要求不是特别高的情况下,可以将这些数据放入 Redis,请求来了 直接查询 Redis,例如近期回复、历史排名这种实时性不强的业务。而针对那些强实时性的业务, 例如虚拟货币、物品购买件数等等,则直接穿透 Redis 至 MySQL 上,等到 MySQL 上写入成功,再同步更新到 Redis 上去。这样既可以起到 Redis 的分流大量查询请求的作用,又保证了关键数据 的一致性。

2、高并发情况下

此时如果写入请求较多,则直接写入 Redis 中去,然后间隔一段时间,批量将所有的写 入请求,刷新到 MySQL 中去;如果此时写入请求不多,则可以在每次写入 Redis,都立刻将该命 令同步至 MySQL 中去。这两种方法有利有弊,需要根据不同的场景来权衡。

3、基于订阅 binlog 的同步机制

阿里巴巴的一款开源框架 canal,提供了一种发布/ 订阅模式的同步机制,通过该框架 我们可以对 MySQL 的 binlog 进行订阅,这样一旦 MySQL 中产生了新的写入、更新、删除等操作, 就可以把 binlog 相关的消息推送至 Redis,Redis 再根据 binlog 中的记录,对 Redis 进行更新。 值得注意的是,binlog 需要手动打开,并且不会记录关于 MySQL 查询的命令和操作。

其实这种机制,很类似 MySQL 的主从备份机制,因为 MySQL 的主备也是通过 binlog 来实 现的数据一致性。而 canal 正是模仿了 slave 数据库的备份请求,使得 Redis 的数据更新达到了 相同的效果。如下图就可以看到 Slave 数据库中启动了 2 个线程,一个是 MySQL SQL 线程,这个 线程跟 Matser 数据库中起的线程是一样的,负责 MySQL 的业务率执行,而另外一个线程就是 MySQL 的 I/O 线程,这个线程的主要作用就是同步 Master 数据库中的 binlog,达到数据备份的 效果。而 binlog 就可以理解为一堆 SQL 语言组成的日志。

93.什么是 Nginx?

Nginx 是一个高性能的 HTTP 和反向代理服务器,及电子邮件代理服务器,同时也是一个非常高 效的反向代理、负载平衡。

轻量级,同样起 web 服务,比 apache 占用更少的内存及资源

抗并发,nginx 处理请求是异步非阻塞的,而 apache 则是阻塞型的,在高并发下 nginx 能保持 低资源低消耗高性能

94.Nginx 是如何实现高并发的?

nginx 之所以可以实现高并发,与它采用的 epoll 模型有很大的关系。epoll 模型采用异步非阻 塞的事件处理机制。这种机制可让 nginx 进程同时监控多个事件。

简单来说,就是异步非阻塞,使用了 epoll 模型和大量的底层代码优化。如果深入一点的话,就 是 nginx 的特殊进程模型和事件模型的设计,才使其可以实现高并发。

95.Nginx 负载均衡的 4 种分配方式?

1、轮询(默认)

每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器 down 掉,能自动剔除。

2、weight

指定轮询几率,weight 和访问比率成正比,用于后端服务器性能不均的情况。

2、ip_hash

每个请求按访问 ip 的 hash 结果分配,这样每个访客固定访问一个后端服务器,可以解决的问题。

3、fair(第三方)

按后端服务器的响应时间来分配请求,响应时间短的优先分配。

4、url_hash(第三方)

按访问 url 的 hash 结果来分配请求,使同样的 url 定向到同一个后端服务器,后端服务器为缓 存时比较有效

96.什么是负载均衡?

负载均衡即是代理服务器将接收的请求均衡的分发到各服务器中,负载均衡主要解决网络拥塞问 题,提高服务器响应速度,服务就近提供,达到更好的访问质量,减少后台服务器大并发压力

97.Nginx 如何实现反向代理负载均衡?

普通的负载均衡软件,(如 LVS)其实现的功能只是对请求数据包的转发、传递,从负载均衡下 的节点服务器来看,接收到的请求还是来自访问负载均衡器的客户端的真实用户;而反向代理就 不一样了,反向代理服务器在接收访问用户请求后,会代理用户 重新发起请求代理下的节点服 务器, 最后把数据返回给客户端用户。在节点服务器看来,访问的节点服务器的客户端用户就 是反向代理服务器,而非真实的网站访问用户。

98.什么是正向代理?

一个位于客户端和原始服务器之间的服务器,为了从原始服务器取得内容,客户端向代理发送一 个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户 端。客户端才能使用正向代理

正向代理总结就一句话:代理端代理的是客户端

99.什么是反向代理?

反向代理是指以代理服务器来接受 internet 上的连接请求,然后将请求,发给内部网络上的服 务器,并将从服务器上得到的结果返回给 internet 上请求连接的客户端,此时代理服务器对外就 表现为一个反向代理服务器

反向代理总结就一句话:代理端代理的是服务端

100.可以从哪些方面来优化 nginx 服务?

1、配置 nginx 的 proxy 缓存;

2、对静态页面开启压缩功能,如 br 压缩或者 gzip 压缩;

3、调整 nginx 运行工作进程个数,最多开启 8 个,8 个以上话性能就不会再提升了,而且稳定 性变得更低,所以 8 个足够用了;

4、调整 nginx 运行 CPU 的亲和力;

5、修改 nginx 最多可打开的文件数,若超过系统限制的最多打开文件数(ulimit -n 命令查看 系统的最多打开文件数),还需要修改系统默认的文件数;

6、修改单个 worker 的最大连接数;

7、开启高效传输;

8、设置连接超时时间,以便保护服务器资源,因为建立连接也是需要消耗资源的;

9、优化 fastCGI 的一个超时时间,也可以根据实际情况对其配置缓存动态页面;

10、expires 缓存调优,主要针对图片、css、js 等元素更改较少的情况下使用。

11、配置防盗链;

12、优化内核参数,如进程可以同时打开的最大句柄数;开启 tcp 重用机制,以便允许 TIME_WAIT

101.为什么要用 MQ?

1、解耦:如果多个模块或者系统中,互相调用很复杂,维护起来比较麻烦,但是这个调用又不 是同步调用,就可以运用 MQ 到这个业务中。

2、异步:这个很好理解,比如用户的操作日志的维护,可以不用同步处理,节约响应时间。

3、削峰:在高峰期的时候,系统每秒的请求量达到 5000,那么调用 MySQL 的请求也是 5000, 一般情况下 MySQL 的请求大概在 2000 左右,那么在高峰期的时候,数据库就被打垮了,那系 统就不可用了。此时引入 MQ,在系统 A 前面加个 MQ,用户请求先到 MQ,系统 A 从 MQ 中每 秒消费 2000 条数据,这样就把本来 5000 的请求变为 MySQL 可以接受的请求数量了,可以保 证系统不挂掉,可以继续提供服务。MQ 里的数据可以慢慢的把它消费掉。

102.使用 MQ 会有什么问题?

(1)降低了系统可用性 (2)增加了系统的复杂性

103.怎么保证 MQ 的高可用?

RabbitMQ 是比较有代表性的,因为是基于主从做高可用性的。以他为例,自行查阅以下模式。 rabbitmq 有三种模式:单机模式、普通集群模式、镜像集群模式。

104.MQ 的优缺点?

在特殊场景下有其对应的好处,解耦、异步、削峰。

缺点有以下几个:

系统可用性降低

系统引入的外部依赖越多,越容易挂掉。万一 MQ 挂了,MQ 一挂,整套系统崩溃,你不就完了? 系统复杂度提高

硬生生加个 MQ 进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息 传递的顺序性?问题一大堆。

一致性问题 A 系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是 BCD 三个 系统那里,BD 两个系统写库成功了,结果 C 系统写库失败了,咋整?你这数据就不一致了。

105.如何设置消息的过期时间?

设置队列属性,队列中所有消息都有相同的过期时间

对消息本身进行单独设置,每条消息的 TTL 可以不同

如果两种方法一起使用,则消息的 TTL 以两者之间较小的那个数值为准

106.消息的持久化是如何实现的?

RabbitMQ 的持久化分为:交换器的持久化、队列的持久化和消息的持久化

交换器和队列的持久化都是通过在声明时将 durable 参数置为 true 实现的 消息的持久化是在发送消息指定 deliveryMode 为 2 实现的

107.什么是 RabbitMQ 的死信队列?

死信,顾名思义就是无法被消费的消息,字面意思可以这样理 解,一般来说,producer 将消息投递到 broker 或者直接到 queue 里了,consumer 从 queue 取出 消息进行消费,但某些时候由于特定的原因导致 queue 中的某些消息无法被消费,这样的消息如 果没有后续的处理,就变成了死信,有死信,自然就有了死信队列;

产生死信的原因

对 rabbitmq 来说,产生死信的来源大致有如下几种: 消息被拒绝(basic.reject 或 basic.nack)并且 requeue=false.

消息 TTL 过期

队列达到最大长度(队列满了,无法再添加数据到 mq 中)

108.什么是延迟队列,延迟队列的实现方式

延时队列,首先,它是一种队列,队列意味着内部的元素是有序的,元素出队和入队是有方向性 的,元素从一端进入,从另一端取出。

其次,延时队列,最重要的特性就体现在它的延时属性上,跟普通的队列不一样的是,普通队列 中的元素总是等着希望被早点取出处理,而延时队列中的元素则是希望被在指定时间得到取出和 处理,所以延时队列中的元素是都是带时间属性的,通常来说是需要被处理的消息或者任务。 简单来说,延时队列就是用来存放需要在指定时间被处理的元素的队列。

1,利用 TTL(过期时间)+死信队列

2,利用 RabbitMQ 插件实现

109.如何保证消息不丢失?

第一种:生产者没能成功将消息发送到 MQ;

a、 丢失的原因:**因为网络传输的不稳定性,当生产者在向 MQ 发送消息的过程中,MQ 没有成 功接收到消息,但是生产者却以为 MQ 成功接收到了消息,不会再次重复发送该消息,从而 导致消息的丢失。

b、 解决办法: 有两个解决办法:事务机制和 confirm 机制,最常用的是 confirm 机制。

第二种:MQ 在接收到消息后弄丢了消息

a、 丢失的原因:RabbitMQ 接收到生产者发送过来的消息,是存在内存中的,如果没有被消费 完,此时 RabbitMQ 宕机了,那么再次启动的时候,原来内存中的那些消息都丢失了。

b、 解决办法:开启 RabbitMQ 的持久化。当生产者把消息成功写入 RabbitMQ 之后,RabbitMQ 就把消息持久化到磁盘。结合上面的说到的 confirm 机制,只有当消息成功持久化磁盘之后, 才会回调生产者的接口返回 ack 消息,否则都算失败,生产者会重新发送。存入磁盘的消息 不会丢失,就算 RabbitMQ 挂掉了,重启之后,他会读取磁盘中的消息,不会导致消息的丢 失。

第三种:消费者弄丢了消息

a、丢失的原因:如果 RabbitMQ 成功的把消息发送给了消费者,那么 RabbitMQ 的 ack 机制会自 动的返回成功,表明发送消息成功,下次就不会发送这个消息。但如果就在此时,消费者还没处 理完该消息,然后宕机了,那么这个消息就丢失了。

b、解决的办法:简单来说,就是必须关闭 RabbitMQ 的自动 ack,可以通过一个 api 来调用 就行,然后每次在自己代码里确保处理完的时候,再在程序里 ack 一把。这样的话,如果你 还没处理完,不就没有 ack了?那 RabbitMQ 就认为你还没处理完,这个时候 RabbitMQ 会把 这个消费分配给别的 consumer 去处理,消息是不会丢的。

110.Zookeeper 是什么?

ZooKeeper 是一个开放源码的分布式协调服务,它是集群的管理者,监视着集群中各个节点的状 态根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的 系统提供给用户

111.Zookeeper 的应用场景?

数据发布/订阅

负载均衡

命名服务

分布式协调/通知

集群管理

Master

选举

分布式锁

分布式队列

112.什么是 Dubbo?

Dubbo 是阿里巴巴开源的基于 Java 的高性能 RPC 分布式服务框架,现已成为 Apache 基金会 孵化项目。

113.为什么要用 Dubbo?

因为是阿里开源项目,国内很多互联网公司都在用,已经经过很多线上考验。内部使用了 Netty、 Zookeeper,保证了高性能高可用性。

使用 Dubbo 可以将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,可用于提 高业务复用灵活扩展,使前端应用能更快速的响应多变的市场需求。

114.Dubbo 和 Spring Cloud 有什么区别?

两个没关联,如果硬要说区别,有以下几点。
1)通信方式不同

Dubbo 使用的是 RPC 通信,而 Spring Cloud 使用的是 HTTP RESTFul 方式。

2)组成部分不同

组件 | Dubbo | Spring Cloud —|—|— 服务注册中心 | Zookeeper | Spring Cloud Netflix Eureka 服务监控 | Dubbo-monitor | Spring Boot Admin 断路器 | 不完善 | Spring Cloud Netflix Hystrix 服务网关 | 无 | Spring Cloud Netflix Gateway 分布式配置 | 无 | Spring Cloud Config 服务跟踪 | 无 | Spring Cloud Sleuth 消息总线 | 无 | Spring Cloud Bus 数 据流 | 无 | Spring Cloud Stream 批量任务 | 无 | Spring Cloud Task … | … | …

115.Dubbo 需要 Web 容器吗?

不需要,如果硬要用 Web 容器,只会增加复杂性,也浪费资源。

116.Dubbo 内置了哪几种容器?

Spring Container

Jetty Container

Log4j Container

Dubbo 的服务容器只是一个简单的 Main 方法,并加载一个简单的 Spring 容器,用于暴露服务。

117.Dubbo 有哪几种配置方式?

1)Spring 配置方式 2)Java API 配置方式

118.Dubbo 默认使用的是什么通信框架,还有别的选择吗?

Dubbo 默认使用 Netty 框架,也是推荐的选择,另外内容还集成有 Mina、Grizzly。

119.什么是 Spring Boot?

Spring Boot 是解决这个问题的方法。 Spring Boot 已经建立在现有 spring 框架之上。使用 spring 启动,我们避免了之前我们必须做的所有样板代码和配置。因此,Spring Boot 可以帮助我们以 最少的工作量,更加健壮地使用现有的 Spring 功能。

120.Spring Boot 有哪些优点?

减少开发,测试时间和努力。

使用 JavaConfig 有助于避免使用 XML。

避免大量的 Maven 导入和各种版本冲突。

提供意见发展方法。 通过提供默认值快速开始开发。

没有单独的 Web 服务器需要。

121.如何重新加载 Spring Boot 上的更改,而无需重新启动服务器?

这可以使用 DEV 工具来实现。通过这种依赖关系,您可以节省任何更改,嵌入式 tomcat 将重新 启动。

122.Spring Boot 中的监视器是什么?

Spring boot actuator 是 spring 启动框架中的重要功能之一。Spring boot 监视器可帮助您访 问生产环境中正在运行的应用程序的当前状态。有几个指标必须在生产环境中进行检查和监控。 即使一些外部应用程序可能正在使用这些服务来向相关人员触发警报消息。监视器模块公开了一 组可直接作为 HTTP URL 访问的 REST 端点来检查状态。

123.什么是 Spring Cloud?

Spring cloud 流应用程序启动器是基于 Spring Boot 的 Spring 集成应用程序,提供与外部系统 的集成。Spring cloud Task,一个生命周期短暂的微服务框架,用于快速构建执行有限数据处 理的应用程序。

124.使用 Spring Cloud 有什么优势?

使用 Spring Boot 开发分布式微服务时,我们面临以下问题
1、与分布式系统相关的复杂性-这种开销包括网络问题,延迟开销,带宽问题,安全问题。
2、服务发现-服务发现工具管理群集中的流程和服务如何查找和互相交谈。它涉及一个服务目录, 在该目录中注册服务,然后能够查找并连接到该目录中的服务。
3、冗余-分布式系统中的冗余问题。
4、负载平衡 --负载平衡改善跨多个计算资源的工作负荷,诸如计算机,计算机集群,网络链路, 中央处理单元,或磁盘驱动器的分布。
5、性能-问题 由于各种运营开销导致的性能问题。
6、部署复杂性-Devops 技能的要求。

125.@ComponentScan 注解的作用

自动扫描并加载符合条件的组件(比如@Component 和@Repository 等)或者 bean 定义,最终将这些 bean 定义加载到 IoC 容器中。

126.Docker 是什么?

Docker 镜像(Images):Docker 镜像是用于创建 Docker 容器的模板。 Docker 容器(Container) :容器是独立运行的一个或一组应用。

Docker 客户端(Client):Docker 客户端通过命令行或者其他工具使用 Docker API 与 Docker 的守护进程通信。

Docker 主机(Host) :一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。

Docker 仓库(Registry):Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。 Docker Hub:提供了庞大的镜像集合供使用。 DockerMachine:Docker Machine 是一个简化 Docker 安装的命令行工具,通过一个简单的命令 行即可在相应的平台上安装 Docker

127.RedLock 的实现原理?

1.互斥;任何时刻只能有一个 client 获取锁

2.释放死锁;即使锁定资源的服务崩溃或者分区,仍然能释放锁

3.容错性;只要多数 redis 节点(一半以上)在使用,client 就可以获取和释放锁 多节点 redis 实现的分布式锁算法(RedLock):有效防止单点故障

128.http 协议的状态码有哪些,含义是什么?

200 OK 客户端请求成功

301Moved Permanently(永久移除),请求的URL已移走。 Response中应该包含一个 Location URL, 说明资源现在所处的位置

302found 重定向

400Bad Request 客户端请求有语法错误,不能被服务器所理解 401Unauthorized 请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用

403 Forbidden 服务器收到请求,但是拒绝提供服务

404 Not Found 请求资源不存在,eg:输入了错误的 URL

500 Internal Server Error 服务器发生不可预期的错误

129.一次完整的 Http 请求是怎样的?

域名解析 --> 发起 TCP 的 3 次握手 --> 建立 TCP 连接后发起 http 请求 --> 服务器响应 http 请求,浏览器得到 html 代码 --> 浏览器解析 html 代码,并请求 html 代码中的资源(如 js、css、图片等) --> 浏览器对页面进行渲染呈现给用户

130.TCP 的三次握手与四次挥手?

第一次握手:建立连接时,客户端发送 syn 包(syn=x)到服务器,并进入 SYN_SENT 状态, 等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。

第二次握手:服务器收到 syn 包,必须确认客户的 SYN(ack=x+1),同时自己也发送一个 SYN 包(syn=y),即 SYN+ACK 包,此时服务器进入 SYN_RECV 状态;

第三次握手:客户端收到服务器的 SYN+ACK 包,向服务器发送确认包 ACK(ack=y+1),此包 发送完毕,客户端和服务器进入 ESTABLISHED(TCP 连接成功)状态,完成三次握手。

四次挥手

第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于 CLOSE_WAIT 状态。

第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于 LAST_ACK 的状态。

第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为自己 ACK
报文的序列号值,此时客户端处于 TIME_WAIT 状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入 CLOSED
状态,服务端收到 ACK 报文之后,就处于关闭连接了,处于 CLOSED 状态。

第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态。

131.建立了连接,但是客户端突然出现故障了怎么办?

服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为 2 小时, 若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔 75 秒钟发 送一次。若一连发送 10 个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连 接。

132.http 中重定向和请求转发的区别?

本质区别:转发是服务器行为,重定向是客户端行为。

重定向特点:两次请求,浏览器地址发生变化,可以访问自己 web 之外的资源,传输的数 据会丢失。

请求转发特点:一次强求,浏览器地址不变,访问的是自己本身的 web 资源,传输的数据 不会丢失。

133.Http 与 Https 的区别?

1、HTTP 的 URL 以 http:// 开头,而 HTTPS 的 URL 以 https:// 开头

2、HTTP 是不安全的,而 HTTPS 是安全的

3、HTTP 标准端口是 80 ,而 HTTPS 的标准端口是 443

4、在 OSI 网络模型中,HTTP 工作于应用层,而 HTTPS 的安全传输机制工作在传输层

5、HTTP 无法加密,而 HTTPS 对传输的数据进行加密

6、HTTP 无需证书,而 HTTPS 需要 CA 机构 wosign 的颁发的 SSL 证书

134.存储过程的优缺点?

优点:

1)存储过程是预编译过的,执行效率高。

2)存储过程的代码直接存放于数据库中,通过存储过程名直接调用,减少网络通讯。

3)安全性高,执行存储过程需要有一定权限的用户。

4)存储过程可以重复使用,可减少数据库开发人员的工作量。

缺点:移植性差

135.SQL 优化的具体操作?
  1. 定位:发现需要优化的 SQL 语句

    可以采用一定的技术实现 SQL 语句定位:

    A. Mysql 的慢查询,开启慢查询实现执行慢的 SQL 语句

    B. 采用 Druid 实现,SQL 监控,获取执行慢的 SQL 语句

    C. Java 代码基于 Spring AOP 实现执行慢的 SQL 语句记录

    D. 采用第三方软件实现

    2.分析

    根据 SQL 分析,慢的原因,目前慢的原因主要有下面几种:

    1. 数据量大

    2. 并发量大

    3. Sql 语句业务逻辑

    4. 索引失效

    5. 多表关系路径问题

    6. 互斥锁的问题

    3.解决 根据分析的结果,进行方案选择,进行解决 比如数据量大,可以搭建 Mysql 集群,实现数据分片 比如并发量大,可以实现数据库的读写分离 比如 sql 语句有业务逻辑,需要把业务逻辑放到 Java 程序中 比如索引失效,那么尽量保证索引的高效

136.事务的四个特性?

原子性(Atomicity): 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,因此事务的操作如果 成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。

隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。同一时间,只允许一个 事务请求同一数据,不同的事务之间彼此没有任何干扰。比如 A 正在从一张银行卡中取钱,在 A 取钱的过程结束前,B 不能向这张卡转账。

持久性(Durability): 持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是 在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

137.事务的并发问题?
  1. 脏读:是两个并发的事务 1 和事务 2 在执行时,事务 1 读取了事务 2 尚未提交的数据, 而事务 2 由于出现异常回滚了,事务 1 拿着读到的事务 2 的数据进行后续操作时就出现数据 错误了

  2. 事务 1 中读取了某个数据,同时事务 2 也在修改这个数据,在事务 2 修改完这个数据并 提交事务后,事务 1 又一次读取了这个数据,两次读取的同一数据就会不一致,这种现象叫 做不可重复读。

  3. 事务 1 中首先读取了某一业务(比如交易记录数)记录数,此时并发的事务 2 新增了一 条交易记录,并提交事务,此时事务 1 再次读取交易记录数时,记录数前后就会出现不一致, 这种现象称为幻读。

138.数据库的五大范式和 BCNF?

第一范式:(确保每列保持原子性)所有字段值都是不可分解的原子值。

第二范式:(确保表中的每列都和主键相关)在一个数据库表中,一个表中只能保存一种数 据,不可以把多种数据保存在同一张数据库表中。

第三范式:(确保每列都和主键列直接相关,而不是间接相关) 数据表中的每一列数据都和 主键直接相关,而不能间接相关。

第四范式:要求把同一表内的多对多关系删除。

第五范式:从最终结构重新建立原始结构。

139.什么是内连接,外连接,交叉连结,笛卡尔积等?

内连接: 只连接匹配的行

左外连接: 包含左边表的全部行(不管右边的表中是否存在与它们匹配的行),以及右边 表中全部匹配的行

右外连接: 包含右边表的全部行(不管左边的表中是否存在与它们匹配的行),以及左边 表中全部匹配的行

全外连接: 包含左、右两个表的全部行,不管另外一边的表中是否存在与它们匹配的行。

交叉连接: 生成笛卡尔积-它不使用任何匹配或者选取条件,而是直接将一个数据源中的 每个行与另一个数据源的每个行都一一匹配

140.什么是索引?

数据库索引,是数据库管理系统中一个排序的数据结构,索引的实现通常使用 B 树及其变 种 B+树。

在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方 式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构,就是索 引。

141.索引的作用?

协助快速查询、更新数据库表中数据。

为表设置索引要付出代价的:

一是增加了数据库的存储空间

二是在插入和修改数据时要花费较多的时间(因为索引也要随之变动)。

142.索引的优缺点?

创建索引可以大大提高系统的性能(优点):

1.通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。

2.可以大大加快数据的检索速度,这也是创建索引的最主要的原因。

3.可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。

4.在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。

5.通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。

增加索引也有许多不利的方面(缺点):

1.创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。

2.索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间, 如果要建立聚簇索引,那么需要的空间就会更大。

3.当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数 据的维护速度

143.什么样的字段适合建索引?

唯一、不为空、经常被查询的字段、作为查询条件的字段都可以

144.事务的隔离级别?

第一种隔离级别:Read uncommitted(读未提交)

第二种隔离级别:Read committed(读提交)

第三种隔离级别:Repeatable read(可重复读取)

第四种隔离级别:Serializable(可序化)

145.索引的分类?

普通索引:仅加速查询

唯一索引:加速查询 + 列值唯一(可以有 null)

主键索引:加速查询 + 列值唯一(不可以有 null)+ 表中只有一个

组合索引:多列值组成一个索引,专门用于组合搜索,其效率大于索引合并 全文索引:对文本的内容进行分词,进行搜索

索引合并,使用多个单列索引组合搜索

146.如果有一个特别大的访问量,到数据库上怎么做优化?
  1. SQL 语句的优化处理 通过慢查询确认执行效率低下的 SQL 语句,进行拆解和索引的控制
    2. 为数据库搭建集群,实现主从复制
    3. 实现数据库的读写分离
    4. 实现数据的分片处理
    5. 采用数据库中间件 Mycat
147.大面积并发,在不增加服务器,如何解决服务器响应不及时问题?

衡量服务器的并发能力

1.吞吐率

吞吐率,单位时间里服务器处理的最大请求数,单位 req/s

2.压力测试

使用 Jmeter,压力测试中关心的时间又细分以下 2 种:

用户平均请求等待时间(这里暂不把数据在网络的传输时间,还有用户 PC 本地的计算时间计算 入内)

服务器平均请求处理时间

提高服务器的并发能力

1.提高 CPU 并发计算能力

2.考虑减少内存分配和释放

3.考虑使用持久连接

4.改进 I/O 模型

5.Sendfile Linux 提供 sendfile()系统调用,可以讲磁盘文件的特定部分直接传送到代表客户 端的 socket 描述符,加快了静态文件的请求速度,同时减少 CPU 和内存的开销。

6.内存映射

148.秒杀系统的设计与实现?

1,验证时间;

2,输入验证码,这一步主要是时间换取空间,换取后台代码的执行时间; 3,用户点击按钮后,按钮变灰,主要是防止用户重复点击,也只能对‘小白’起作用,其中还 有限制 IP,限制账号,分析用户行为等等;

4,验证库存,秒杀成功后库存-1,其中使用的是乐观锁,主要不认为会产生数据的冲突,因为 并发量没那么高(如果出现商品超卖,就使用 redis 自旋锁配合数据库的乐观锁);

5,用户秒杀成功后,但是五分钟内不付款,视为放弃放弃本次优惠,库存+1;

149.JVM
1.1.1 程序计数器

内存空间小,线程私有。解释器工作是就是通过改变这个计数器的值来选取下一条需要执行指令的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器完成

1.1.2 Java 虚拟机栈

线程私有,生命周期和线程一致。描述的是 Java 方法执行的内存模型:每个方法在执行时都会床创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行结束,就对应着一个栈帧从虚拟机栈中入栈到出栈的过程。

1.1.3 本地方法栈

区别于 Java 虚拟机栈的是,Java 虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。也会有 StackOverflowError 和 OutOfMemoryError 异常。

1.1.4 Java 堆

对于绝大多数应用来说,这块区域是 JVM 所管理的内存中最大的一块。线程共享,主要是存放对象实例和数组。内部会划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer, TLAB)。可以位于物理上不连续的空间,但是逻辑上要连续。

1.1.5 方法区

属于共享内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

150.HashMap底层原理
1.HashMap的几个重要知识点
  1. HashMap是无序且不安全的数据结构。

  2. HashMap 是以key–value对的形式存储的,key值是唯一的(可以为null),一个key只能对应着一个value,但是value是可以重复的。

  3. HashMap 如果再次添加相同的key值,它会覆盖key值所对应的内容,这也是与HashSet不同的一点,Set通过add添加相同的对象,不会再添加到Set中去。

  4. HashMap 提供了get方法,通过key值取对应的value值,但是HashSet只能通过迭代器Iterator来遍历数据,找对象。

    2、JDK7与JDK8的HashMap区别
    既然讲HashMap,那就不得不说一下JDK7与JDK8(及jdk8以后)的HashMap有什么区别:
    1. jdk8中添加了红黑树,当链表长度大于等于8的时候链表会变成红黑树

    2. 链表新节点插入链表的顺序不同(jdk7是插入头结点,jdk8因为要把链表变为红 黑树所以采用插入尾节点)

    3. hash算法简化 ( jdk8 )

    4. resize的逻辑修改(jdk7会出现死循环,jdk8不会)

      3.面试的时候,面试官经常会问道一个问题:为什么HashMap的默认负载因子是0.75,而不是0.5或者是整数1呢?

      答案有两种:

      1. 阈值(threshold) = 负载因子(loadFactor) x 容量(capacity) 根据HashMap的扩容机制,他会保证容量(capacity)的值永远都是2的幂 为了保证负载因子x容量的结果是一个整数,这个值是0.75(4/3)比较合理,因为这个数和任何2的次幂乘积结果都是整数。
      2. 理论上来讲,负载因子越大,导致哈希冲突的概率也就越大,负载因子越小,费的空间也就越大,这是一个无法避免的利弊关系,所以通过一个简单的数学推理,可以测算出这个数值在0.75左右是比较合理的
151.HashMap的结构

JDK7与JDK8及以后的HashMap结构与存储原理有所不同:***
Jdk1.7:数组 + 链表 ( 当数组下标相同,则会在该下标下使用链表)
Jdk1.8:数组 + 链表 + 红黑树 (预值为8 如果链表长度<=8则会把链表变成红黑树 )
Jdk1.7中链表新元素添加到链表的头结点,先加到链表的头节点,再移到数组下标位置
Jdk1.8中链表新元素添加到链表的尾结点
(数组通过下标索引查询,所以查询效率非常高,链表只能挨个遍历,效率非常低。jdk1.8及以
上版本引入了红黑树,当链表的长度大于或等于8的时候则会把链表变成红黑树,以提高查询效率)

152.HashMap存储原理与存储流程

1.HashMap存储原理

  1. 获取到传过来的key,调用hash算法获取到hash值
  2. 获取到hash值之后调用indexFor方法,通过获取到的hash值以及数组的长度算
    出数组的下标 (把哈希值和数组容量转换为二进,再在数组容量范围内与哈希值
    进行一次与运算,同为1则1,不然则为0,得出数组的下标值,这样可以保证计算出的数组下标不会大于当前数组容量)
  3. 把传过来的key和value存到该数组下标当中。
  4. 如该数组下标下以及有值了,则使用链表,jdk7是把新增元素添加到头部节点 jdk8则添加到尾部节点。

2.HashMap存储流程

前面寻址算法都是一样的,根据key的hashcode经过高低位异或之后的值,再按位与 &(table.lingth - 1),得到一个数组下标,然后根据这个数组下标内的状况,状况不同,然后情况也不同,大概分为了4种状态:

( 1.)第一种就是数组下标下内容为空:
这种情况没什么好说的,为空据直接占有这个slot槽位就好了,然后把当前.put方法传进来的key和value包装成一个node对象,放到这个slot中就好了。

( 2.)第二种情况就是数组下标下内容不为空,但它引用的node还没有链化:
这种情况下先要对比一下这个node对象的key与当前put对象的key是否完全.相等,如果完全相等的情况下,就行进行replace操作,把之前的槽位中node.下的value替换成新的value就可以了,否则的话这个put操作就是一个正儿.八经的hash冲突,这种情况在slot槽位后面追加一个node就可以了,用尾插法 ( 前面讲过,jdk7是把新增元素添加到头部节点,而jdk8则添加到尾部节点)。

( 3.)第三种就是该数组下标下内容已经被链化了:
这种情况和第二种情况处理很相似,首先也是迭代查找node,看看链表上中元素的key,与当前传过来的key是否完全一致,如果完全一致的话还是repleace操作,用put过来的新value替换掉之前node中的value,否则的话就是一致迭代到链表尾节点也没有匹配到完全一致的node,就和之前的一样,把put进来数据包装成node追加到链表的尾部,再检查一下当前链表的长度,有没有达到树化阈值,如果达到了阈值就调用一个树化方法,树化操作都是在这个方法里完成的。

( 4.)第四种情况就是冲突很严重的情况下,这个链表已经转化成红黑树了:
红黑树就比较复杂 要将清楚这个红黑树还得从TreeNode说起 TreeNode继承了Node结构,在Node基础上加了几个字段,分别是指向父节点parent字段,指向左子节点left字段,指向右子节点right字段,还有一个表示颜色的red字段,这就是TreeNode的基本结构,然后红黑树的插入操作,首先找到一个合适的插入点,就是找到插入节点的父节点,然后红黑树它又满足二叉树的所有特性,所以找这个父节点的操作和二叉树排序是完全一致的,然后说一下这个二叉树排序,其实就是二分查找算法映射出来的结构,就是一个倒立的二叉树,然后每个节点都可以有自己的子节点,本且左节点小于但前节点,右节点大于当前节点,然后每次向下查找一层就能那个排除掉一半的数据,查找效率非常的高效,当查找的过程中也是分情况的。

  1. 首先第一种情况就是一直向下探测,直到查询到左子树或者右子树位null,说明整个树中,并没有发现node链表中的key与当前put key一致的TreeNode,那此时探测节点就是插入父节点的所在了,然后就是判断插入节点的hash值和父节点的hash值大小决定插入到父节点的左子树还是右子树。当然插入会打破平衡,还需要一个红黑树的平衡算法保持平衡。
  2. 其次第二种情况就是根节点在向下探测过程中发现TreeNode中key与当前put的key完全一致,然后就也是一次repleace操作,替换value。

六、jdk8中HashMap为什么要引入红黑树?

其实主要就是为了解决jdk1.8以前hash冲突所导致的链化严重的问题,因为链表结构的查询效率是非常低的,他不像数组,能通过索引快速找到想要的值,链表只能挨个遍历,当hash冲突非常严重的时候,链表过长的情况下,就会严重影响查询性能,本身散列列表最理想的查询效率为O(1),当时链化后链化特别严重,他就会导致查询退化为O(n)为了解决这个问题所以jdk8中的HashMap添加了红黑树来解决这个问题,当链表长度>=8的时候链表就会变成红黑树,红黑树其实就是一颗特殊的二叉排序树嘛,这个时间复杂…反正就是要比列表强很多

七、扩容后的新table数组,那老数组中的这个数据怎么迁移呢

迁移其实就是挨个桶位推进迁移,就是一个桶位一个桶位的处理,主要还是看当前处理桶位的数据状态把,这里也是分了大概四种状态:
这四种的迁移规则都不太一样

(1.)第一种就是数组下标下内容为空:
这种情况下就没什么可说的,不用做什么处理。

( 2.)第二种情况就是数组下标下内容不为空,但它引用的node还没有链化:
当slot它不为空,但它引用的node还没有链化的时候,说明这个槽位它没有发生过hash冲突,直接迁移就好了,根据新表的tableSize计算出他在新表的位置,然后存放进去就好了。

( 3.)第三种就是slot内储存了一个链化的node:
当node中next字段它不为空,说明槽位发生过hash冲突,这个时候需要把当前槽位中保存的这个链表拆分成两个链表,分别是高位链和低位链

(4.)第四种就是该槽位储存了一个红黑树的根节点TreeNode对象:

153.线程与进程

线程:是操作系统能够调度的最小单位,包含在进程中,是进程的实际运作的单位.

进程:简单点就是一个正在进行的程序

区别:线程是进程的子集,一个进程可以有很多个任务,不同的线程执行不同的任务

一个java应用程序至少有两个线程,一个是主线程(main),一个是执行垃圾回收的线程

二.如何在java中实现线程
调用java.lang.Thread类或者实现java.lang.Runnable接口重写run()方法

面试回答上面的就行了,这里写下如何实现的,更能深入记住他

第一种.继承Therad类
第二种 实现Runnable接口

什么是线程死锁
就是多个线程互相等待,造成多不执行的情况.举个例子,两个中国人进门,两个都很有礼貌,都想等待对方先进才能进,结果最后两个都没进都在等待.还有个就是哲学家问题,4个哲学家围在一起吃饭,中间放一只筷子,然后规定他们只有先取左边的筷子再取右边的筷子才能吃饭.我们来分析筷子作为临界值,当大家都拿起左边的筷子的时候,大家发现右边没筷子了,所以都在希望等对方把筷子放下,然后拿右边的筷子,结果一直僵持着.

所以我们知道造成线程死锁的条件:

(1)互斥条件:一个资源每次只能被一个进程使用。比如:4个哲学界,却只有两双筷子

(2)请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 比如:他们都不想放下自己手中的筷子

(3)不可剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。 比如:他们都不能取抢夺别人手中的筷子

(4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。比如:所以他们之间就形成了循环等待条件

七.sleep()和wait()有什么区别
sleep()是使线程停止一段时间的方法.但在sleep()后不一定立即恢复执行,因为此刻可能别的线程还在争夺赢了cpu使用权,但如果你通过setPriority()方法设置更高的优先权

wait()当线程交互时候,如果线程对同步对象发出wait()调用,这个对象只有在被唤醒才能执行

八.在win32环境中线程有哪三种模式
1.单线程

指从任务的开始到结束都需要自己来完成

2.单元线程

指可以多个单线程组成一个单元,他们完成各自的分工

3.自由线程

这些线程可以互相帮忙执行任务

154.Bean的作用范围

在Spring中使用Scope来表示一个bean定义对应产生实例的类型,也可以说是对应实例的作用范围。Spring内置支持的scope严格来说默认是有五种,分别是:

singleton:这是默认Scope,表示在整个bean容器中或者说是整个应用中只会有一个实例。
prototype:多例类型,表示每次从bean容器中都会获取到一个对应bean定义全新的实例。
request:仅适用于Web环境下的ApplicationContext,表示每一个HttpRequest生命周期内会有一个单独的实例,即每一个Http请求都会拥有一个单独的实例。
session:仅适用于Web环境下的ApplicationContext,表示每一个HttpSession生命周期内会有一个单独的实例,即每一个HttpSession下都会拥有一个单独的实例,即每一个用户都将拥有一个单独的实例。
globalSession:仅适用于Web环境下的ApplicationContext,一般来说是Portlet环境下。表示每一个全局的Http Session下都会拥有一个单独的实例。
application:仅适用于Web环境下的ApplicationContext,表示在ServletContext生命周期内会拥有一个单独的实例,即在整个ServletContext环境下只会拥有一个实例。

155.IOC AOP原理

Spring的IOC和AOP原理
本文讲的是面试之Spring框架IOC和AOP的实现原理, IoC(Inversion of Control) (1). IoC(Inversion of Control)是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控。控制权由应用代码中转到了外部容器,控制权的转移是所。

IoC(Inversion of Control)
(1). IoC(Inversion of Control)是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控。控制权由应用代码中转到了外部容器,控制权的转移是所谓反转。 对于Spring而言,就是由Spring来控制对象的生命周期和对象之间的关系;IoC还有另外一个名字——“依赖注入(Dependency Injection)”。从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,即由容器动态地将某种依赖关系注入到组件之中。

(2). 在Spring的工作方式中,所有的类都会在spring容器中登记,告诉spring这是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。

(3). 在系统运行中,动态的向某个对象提供它所需要的其他对象。

(4). 依赖注入的思想是通过反射机制实现的,在实例化一个类时,它通过反射调用类中set方法将事先保存在HashMap中的类属性注入到类中。 总而言之,在传统的对象创建方式中,通常由调用者来创建被调用者的实例,而在Spring中创建被调用者的工作由Spring来完成,然后注入调用者,即所谓的依赖注入or控制反转。 注入方式有两种:依赖注入和设置注入;

IoC的优点:降低了组件之间的耦合,降低了业务对象之间替换的复杂性,使之能够灵活的管理对象。

AOP(Aspect Oriented Programming)
1、AOP面向方面编程基于IoC,是对OOP的有益补充;
2、 AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了 多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的 逻辑或责任封装起来,比如日志记录,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
3、 AOP代表的是一个横向的关 系,将“对象”比作一个空心的圆柱体,其中封装的是对象的属性和行为;则面向方面编程的方法,就是将这个圆柱体以切面形式剖开,选择性的提供业务逻辑。而 剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹,但完成了效果。
4、 实现AOP的技术,主要分为两大类:
一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;
二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。
5、 Spring实现AOP:JDK动态代理和CGLIB代理

JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理;其核心的两个类是InvocationHandler和Proxy。

CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强;需要引入包asm.jar和cglib.jar。
使用AspectJ注入式切面和@AspectJ注解驱动的切面实际上底层也是通过动态代理实现的。
(6). AOP使用场景:
Authentication 权限检查
Caching 缓存
Context passing 内容传递
Error handling 错误处理
Lazy loading 延迟加载
Debugging  调试
logging, tracing, profiling and monitoring 日志记录,跟踪,优化,校准
Performance optimization 性能优化,效率检查
Persistence  持久化
Resource pooling 资源池
Synchronization 同步
Transactions 事务管理
另外Filter的实现和struts2的拦截器的实现都是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以动态灵活的方式来管理对象 , 注入的两种方式,设置注入和构造注入。

设置注入的优点:直观,自然

通过setter访问器实现
灵活性好,但setter方法数量较多
时效性差
通过无参构造函数实例化
构造注入的优点:可以在构造器中决定依赖关系的顺序。

通过构造方法实现
灵活性差,仅靠重载限制太多
时效性好
通过匹配的构造方法实例化,但建议保留无参构造

156.同步锁以及如何避免死锁?

同步:在高并发的情况下,为了防止数据出错,一个线程对于共享资源执行操作的时候,另外的线程要执行操作此共享资源需要等待前一个线程释放此共享资源,才能操作。

同步监视器:共享资源。

同步函数:synchronized修饰的方法,同步监视器为当前this对象。

同步代码块:synchronized修饰的代码块,同步监视器可以自定义。

同步锁Lock:另一种更加强大的线程安全机制:通过显示的定义同步锁对象来实现同步,同步锁对象由Lock对象充当。

两者同步机制的区别:Lock是显示的使用Lock对象作为同步监视器,同步方法隐式的使用当前对象作为同步监视器。

Lock开启后必须关闭:lock()//加锁 unlock()//释放锁

死锁:简单来说就是两个没有释放的同步进程都想取得对方共享资源(同步监视器)的操作权。

举个例子:有同步函数A,B 有资源a1,b1 问题:A,B都想取得a1,b1的操作权。

假设:A先取的a1的操作权,同时B取得了b1的操作权,此时,A再想取得b1得操作权必须等同步函数B先释放资源,但是B由于没有拿到a1得操作权所以一直没有释放资源。此时就会造成线程得等待死锁(阻塞死锁)

死锁分类:

1.等待死锁(如上)。

2.递归死锁:(一般很少人在递归函数里面加锁,很容易死翘翘)

举例:A同步函数,B非同步函数。A同步函数里调用了B非同步函数,但是B非同步进程里又调用了A同步进程。

假设:运行A同步函数时,由于A中同步函数调用了B函数,所以进入B函数,B函数再次调用了A同步函数,因为之前得A同步函数资源还没有释放,再从B函数中调用A同步函数会造成,再次调用得A同步函数进入递归死锁状态。

避免死锁得技术:

1.加锁顺序

所有线程按照一定顺序获取锁,避免按照不同顺序加锁时出现死锁。

举例:

有线程A&B&C,有锁:lock1&lock2&lock3

A{lock1,lock2,lock3}

B{lock2,lock3}

C{lock1}

A想获得lock3,必须先获得lock1,但是lock1被C加锁。所以A需要等待C释放即可,

A获得lock1,继续获得lock2,想获得lock2必须等待B释放资源。等待B释放资源,A终于获得lock3。

反例:

有线程A&B&C,有锁:lock1&lock2&lock3

A{lock1,lock2,lock3}

B{lock3,lock1}

C{lock2}

A想获得lock3, B想获得lock1,A获得了lock1,开始获得lock2,等待C释放资源,

此时B获得lock3,需要获得lock1。C释放资源后,A获得lock2,但是此时lock3被B加锁,但是lock1又被A加锁。此时A,B就发生了死锁。

缺点:需要知道所有加锁情况,全局分析(难以避免未知情况)

2.加锁时限

在获取锁的过程中加上超时时间,超时则释放资源并回退,稍后再尝试加锁。

举例:

如1中的反例:假设A线程设置了300毫秒的限时,B线程设置了100毫秒的限时,

如果B等待时间超过限时,释放资源并回退,此时A就可以成功获得所有锁并结束程序。然后B再尝试获取锁,就可以解决死锁问题。

缺点:当线程增至10条或20条以上,各线程的限时时长就越发接近,那么越容易造成死锁。例如:如果上例子中A,B线程限时时常一样,那么死锁依然会发生。

3.死锁检测

死锁检测机制,主要针对顺序加锁和加锁限时都无法实现的情况下使用。

原理:每当一个线程获得或者请求锁后,获得或请求的锁信息会在锁和线程的数据结构中记录下来。当一个线程请求锁失败时,会遍历锁的关系图,查看是否发生死锁。

举例:

简单例子:

有线程A,B, 有锁lock1,lock2

A{lock1,lock2}

B{lock2,lock1}

此时当A请求lock2失败时,会检测自身是否加锁了B请求的锁。如果有就发生了死锁。

复杂例子:

多线程的递归检测死锁:

有线程A,B,C,D 有锁lock1,lock2,lock3,lock4

A{lock1,lock2}

B{lock2,lock3}

C{lock3,lock4}

D{lock4,lock1}

A加锁lock1,加锁lock2时请求失败,检测锁的关系图,发现lock2被B加锁,

B请求的lock3,又被C加锁,C请求的lock4又被D加锁,D请求的lock1又被

A加锁。造成递归加锁。

当检测到死锁后:线程回退,等待一段时间再重新尝试加锁。

一、简介

主从备份模式,主库(maser)和备份库(slave)数据完全一致。实现数据的多重备份,保障数据的安全性。一般用于读写分离,主库master(InnoDB)用于写、从库slave(MyISAM)用于读取。

从库(MyISAM)一般使用DQL语法操作。

主从模式中,对主库master的所有操作,都会同步到备库slave中。注意,主库和备库的初始环境必须完全一致,库、表的初始完全相同。如果master有db1,db2,而slave中只有db1,那么在master执行drop database db2时,从库slave会报错,一旦报错,那么之后对master的所有操作,slave都不会再同步执行。此时,只能重新去建立主从备份模式。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Jim_ZTR/article/details/127010609

java面试题mysql部分_联想高级Java研发面经+面试题:Spring+多线程+MySQL+设计模式...-爱代码爱编程

上个礼拜,之前的一个同事突然联系我说他去面了联想的JAVA开发工程师,想分享一下面试经历和面试题。我当时就拍板说,好啊! 然后就整理了一下,写了这篇文章;和大家分享一下这次面试经验和面试题。 薪资还可以啊,年薪40W+啊!多少人的梦想啊! 言归正传,和大家分享一下这次联想的面经和面试题: 联想面经: 第一轮:电话初面 第二轮:技术面

java语言基础教程课后答案,积累总结-爱代码爱编程

Spring面试高频问题 SpringMVC面试高频问题 MyBatis面试高频问题 SpringBoot面试高频题 SpringCloud面试高频问题 Redis高级面试题 Dubbo高频常问面试问题 Java虚拟机(JVM) MySQL数据库高频面试问题 Java高频面试专题合集解析: 当然在