java技术面试-BEIJING

第一部分、Java 基础

1.在浏览器地址栏里输入一个网址,接下来会发生什么?

(1)浏览器查找该网址的IP地址。
(2)浏览器根据解析得到的IP地址向Web服务器发送一个HTTP请求。
(3)服务器收到请求并进行处理。
(4)服务器返回一个响应。
(5)浏览器对该响应进行解码,并渲染显示页面。
(6)页面显示完成后,浏览器发送异步请求。

2.http的请求方式有哪些?

GET、POST、DELETE、PUT、HEAD、TRACE、CONNECT、OPTIONS

3.简述一下TCP的三次握手?

第一次握手:建立连接时,客户端发送syn包(seq=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。 [3]
第二次握手:服务器收到syn包,必须确认客户端的SYN(ack=j+1),同时自己也发送一个SYN包(seq=k),即SYN+ACK包,此时服务器进入SYN_RECV状态。 [3]
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。 [3]
完成三次握手,客户端与服务器开始传送数据。

4.Java虚拟机工作原理

从最初的我们编写的Java源文件(.java文件)是如何一步步执行的,如下图所示,首先Java源文件经过前端编译器(javac或ECJ)将.java文件编译为Java字节码文件,然后JRE加载Java字节码文件,载入系统分配给JVM的内存区,然后执行引擎解释或编译类文件,再由即时编译器将字节码转化为机器码。

5.Mybatis 的一级、二级缓存

  1. 一级缓存
    一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构用于存储缓存数据。不同的sqlSession之间的缓存数据区域是互相不影响的。也就是他只能作用在同一个sqlSession中,不同的sqlSession中的缓存是互相不能读取的。
  2. 二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
    UserMapper有一个二级缓存区域(按namespace分),其它mapper也有自己的二级缓存区域(按namespace分)。每一个namespace的mapper都有一个二级缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同的二级缓存区域中。

6.说说你对Spring中的IOC是怎么理解的?

“IOC就是控制反转,spring框架的核心就是IOC思想的实现,spring中所有的模块都是基于IOC,更重要的是基于IOC整合各种资源,例如Hibenate,AOP,Redis,Shiro等”

7.用过AOP吗?说说你对AOP的理解

AOP是面向切面编程( Aspect)
简单的说就是把我们重复的代码抽取出来,在需要执行的时候,使用动态代理技术,在不修改源码的基础上,对我们已有的方法进行增强
AOP的作用和优势
作用:在程序运行期间,不修改源码对已有方法进行增强。
优势:减少重复代码,提高开发效率,维护方便
AOP的实现方式:可用于权限认证、日志、事务处理

8.Spring 框架中的单例 Bean 是线程安全的么?

“不,Spring框架中的单例bean不是线程安全的。”

9.说一下Spring Bean的生命周期

在这里插入图片描述

10.Spring 是怎么解决循环依赖的?

第一种:构造器参数循环依赖
第二种:setter方式单例,默认方式
第三种:setter方式原型,prototype

11.Spring Boot 自动装配原理是什么?

三大核心注解
@Configuration(@SpringBootConfiguration实质就是一个@Configuration)
@EnableAutoConfiguration
@ComponentScan

12.熟悉哪些设计模式

常用的设计模式可以分为以下三大类:
创建型模式: 包括工厂模式(又可进一步分为简单工厂模式、工厂方法模式、抽象工厂模式)、建造者模式、单例模式。
结构型模式: 包括适配器模式、桥接模式、装饰模式、外观模式、享元模式、代理模式。
行为型模式: 包括命令模式、中介者模式、观察者模式、状态模式、策略模式。

13.你们项目中单例模式使用的是哪种?

单例模式(Singleton)
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory。但没有从构造器级别去控制单例,这是因为spring管理的是是任意的java对象。
核心提示点:Spring下默认的bean均为singleton,可以通过singleton=“true|false” 或者 scope=“?”来指定

14.Java中的原始数据类型都有哪些,它们的大小及对应的封装类是什么?

byte——1 byte——Byte
short——2 bytes——Short
int——4 bytes——Integer
long——8 bytes——Long
char——2 bytes——Character
float——4 bytes——Float
double——8 bytes——Double

15.说下你对== 和 equals 的认识,它们有什么差别?

对于==
基本类型,比如int等,==比较的是值是否相同;
引用类型,比如自定义对象:比较地址是否相同;
尤其地,对常量,由于常量被放在常量池里管理,所以对String等常量,==也是比较值
对于equals 方法
对于String,ArrayList等,equals方法是比较值;
但在Object里,equals还是比较地址;
如果自己创建了一个类,但没有重写equals方法,还是会比较地址

16.Java中的四种引用及其应用场景是什么?

  1. 强引用: 通常我们使用new操作符创建一个对象时所返回的引用即为强引用
  2. 软引用: 若一个对象只能通过软引用到达,那么这个对象在内存不足时会被回收,可用于图片缓存中,内存不足时系统会自动回收不再使用的Bitmap
  3. 弱引用: 若一个对象只能通过弱引用到达,那么它就会被回收(即使内存充足),同样可用于图片缓存中,这时候只要Bitmap不再使用就会被回收
  4. 虚引用: 虚引用是Java中最“弱”的引用,通过它甚至无法获取被引用的对象,它存在的唯一作用就是当它指向的对象回收时,它本身会被加入到引用队列中,这样我们可以知道它指向的对象何时被销毁。

17.object中定义了哪些方法?

clone(), equals(), hashCode(), toString(), notify(), notifyAll(), wait(), finalize(), getClass()

18.访问控制符public,protected,private,以及默认的区别

在这里插入图片描述

19.是否可以继承String类

String类是final类故不可以继承,一切由final修饰过的都不能继承。

20.说明Java里内存泄漏和溢出的区别。

内存溢出(out of memory)是指程序在申请内存时,没有足够的内存空间可供使用。
内存泄漏(memory leak)是指程序在申请内存后,无法释放已申请的内存空间。一次内存泄漏的危害可以忽略,但内存泄漏堆积的后果很严重,无论计算机有多少内存,迟早会被用完。
内存泄漏最终会导致内存溢出。

21.说明抽象类和接口的区别?

抽象类的子类要用 extends 来继承;而实现接口要用 implements 。
抽象类可以定义构造函数,而接口不能。
抽象类里可以定义 main 方法,但接口不能有 main 方法。
实现数量:类可以实现很多个接口;但是只能继承一个抽象类。
访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符。

22.JDK 和 JRE 有什么区别?

JDK是java的开发工具包,有JDK8,9甚至到14的差别,安装以后,不仅包含了java 的开发环境,比如java.exe,还包含了运行环境(jre)相关包。
JRE是java 运行环境,一般装好JDK后,系统里会有对应的JRE环境。

23.Java虚拟机加载类的顺序

  1. 通过ClassLoader对象的loadClass()方法
  2. 类名.class
  3. Class.forName()
  4. object.getClass()

24.如果两个对象的 hashCode值一样,则它们用equals()比较也是为 true,是不是?

不是
hashCode是定义在HashMap里,用以快速索引;
Object里,hashCode和equals是两个不同的方法,默认hashCode是返回对象地址,equals方法也是对比地址;
两者不是一回事,可以通过重写对象的hashCode方法,让不同值的对象有相同的hashCode,但它们的equals方法未必相同

25.综合说下final的作用

修饰在类上,该类不能被继承。
修饰在方法上,该方法不能被重写。
修饰在变量上,叫常量,该常量必须初始化,初始化之后值就不能被修改,而常量一般全都是用大写来命名。

26.Math.round(-2.5) 等于多少?

结果是-2,因为该函数在数轴上,表现是向右取整,由此 Math.round(1.3) = 2。

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

String 不是基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、double,而 String 是对象。
但说到这里,你要多说句。
String s = “abc”;,这是常量,放常量池管理。
不建议频繁对String修改,因为会产生内存碎片。

28.String str="abc"与 String str=new String(“abc”)的定义方法一样吗?

不一样,String str="abc"的方式,java 虚拟机会将其分配到常量池中;所以建议这种写法。
而 String str=new String(“abc”) 则会被分到堆内存中,如果再频繁修改,会导致内存碎片。

29.如何将字符串反转?

使用 StringBuilder 或 stringBuffer 的 reverse() 方法。

30.String 类的常用方法都有那些?

indexOf():返回指定字符的索引。
length():返回字符串长度。
equals():字符串比较。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。

31. 抽象类必须要有抽象方法吗?

不需要的,抽象类不一定非要有抽象方法。但从面向对象思想角度来分析,不建议这样做。

32.一般的类和抽象类有哪些区别?

一般的类不能包含没有方法体的抽象方法,而抽象类可以包含抽象方法。
抽象类不能直接用new来实例化,普通类可以直接实例化。

33.抽象类能使用 final 修饰吗?

首先说明,语法上不能,然后再进一步从面向对象思想角度来说明。
定义抽象类的本意是,让其它类继承的,从而进一步完善对象。如果定义为 final 该类就不能被继承,这样就会有矛盾,所以 final 不能修饰抽象类。

34.Iterator 和 ListIterator 有什么区别?

  1. ListIterator有add()方法,可以向List中添加对象,而Iterator不能
  2. ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
  3. ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
  4. 都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。

35.java 中 IO 流分为几种?

按功能来分可以分输入流(input)和输出流(output)。从类型来分可以是字节流和字符流。

36.BIO、NIO、AIO 有什么区别?

BIO的英语全称是Block IO, 同步阻塞式 IO,就是平常经常使用的传统 IO,特点是简单方便,但并发处理能力低。
NIO,叫New IO, 同步非阻塞 IO,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
AIO,Asynchronous IO, 是 NIO 的升级,实现了异步非堵塞 IO ,它是基于事件和回调机制。

37.Files的常用方法都有哪些?

Files.exists():检测路径是否存在。
Files.createFile():创建文件。
Files.createDirectory():创建文件夹。
Files.delete():删除文件或文件夹。
Files.copy():复制文件。
Files.move():移动文件,即复制后删除。
Files.size():查看文件的个数。
Files.read():读取文件。
Files.write():写入文件。

38.说出 JDK 1.7 中的三个新特性?

  1. try-with-resource 语句,这样你在使用流或者资源的时候,就不需要手动关闭,Java 会自动关闭。Fork-Join 池某种程度上实现 Java 版的 Map-reduce。
  2. 允许 Switch 中有 String 变量和文本。菱形操作符(<>)用于类型推断,不再需要在变量声明的右边申明泛型,因此可以写出可读写更强、更简洁的代码。
  3. 另一个值得一提的特性是改善异常处理,如允许在同一个 catch 块中捕获多个异常。

39.说出 5 个 JDK 1.8 引入的新特性?

Java 8 在 Java 历史上是一个开创新的版本,下面 JDK 8 中 5 个主要的特性:
Lambda 表达式,允许像对象一样传递匿名函数
Stream API,充分利用现代多核 CPU,可以写出很简洁的代码
Date 与 Time API,最终,有一个稳定、简单的日期和时间库可供你使用
扩展方法,现在,接口中可以有静态、默认方法。
重复注解,现在你可以将相同的注解在同一类型上使用多次。

41.Java中创建对象的5种方式

  1. 使用new关键字 } → 调用了构造函数
  2. 使用Class类的newInstance方法 } → 调用了构造函数
  3. 使用Constructor类的newInstance方法 } → 调用了构造函数
  4. 使用clone方法 } → 没有调用构造函数
  5. 使用反序列化 } → 没有调用构造函数

42.Java中异常有哪些

在这里插入图片描述

43.spring是如何实现事务的?

四种方式:
方式一:编程式事务管理:需要手动编写代码,在实际开发中很少使用
方式二:声明式事务
基于TransactionProxyFactoryBean的方式,需要为每个进行事务管理的类做相应配置
基于AspectJ的XML方式,tx标签不需要改动类,在XML文件中配置好即可
基于注解的方式,@Transactional,配置简单,需要在业务层类中添加注解(使用较多)

44.Java有几种类型的事务?

第一种:使用 TransactionTemplate 事务模板对象
第二种:使用 事务管理器 PlatformTransactionManager 对象
第三种:基于Aspectj AOP开启事务
第四种:基于注解的 @Transactional 的声明式事务管理

45.spring的4种事务特性,5种隔离级别,7种传播行为

事务特性(4种):
原子性 (atomicity):强调事务的不可分割.
一致性 (consistency):事务的执行的前后数据的完整性保持一致.
隔离性 (isolation):一个事务执行的过程中,不应该受到其他事务的干扰
持久性(durability) :事务一旦结束,数据就持久到数据库

如果不考虑隔离性引发安全性问题:
脏读 :一个事务读到了另一个事务的未提交的数据
不可重复读 :一个事务读到了另一个事务已经提交的 update 的数据导致多次查询结果不一致.
虚幻读 :一个事务读到了另一个事务已经提交的 insert 的数据导致多次查询结果不一致.

解决读问题: 设置事务隔离级别(5种)
DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
未提交读(read uncommited) :脏读,不可重复读,虚读都有可能发生
已提交读 (read commited):避免脏读。但是不可重复读和虚读有可能发生
可重复读 (repeatable read) :避免脏读和不可重复读.但是虚读有可能发生.
串行化的 (serializable) :避免以上所有读问题.
Mysql 默认:可重复读
Oracle 默认:读已提交

46.解决Jar包冲突的方法

  1. Maven默认处理:采用此种方法,要牢记Maven依赖调节机制的基本原则,路径最近者优先和第一声明优先;
  2. 排除法:上面Maven Helper的实例中已经讲到,可以将冲突的Jar包在pom.xml中通过exclude来进行排除;
  3. 版本锁定法:如果项目中依赖同一Jar包的很多版本,一个个排除非常麻烦,此时可用版本锁定法,即直接明确引入指定版本的依赖。根据前面介绍Maven处理Jar包基本原则,此种方式的优先级最高。这种方法一般采用上面我们讲到的如何统一Jar包依赖的方式。

47.http中get请求和POST请求的区别?

  1. GET在浏览器回退是无害的,而POST会再次提交请求
  2. GET产生的URL地址可以被网址收藏BOOKMARK,而POST不可以
  3. GET请求只能进行url编码,而post支持多种编码形式
  4. get请求参数会被完整保留在浏览器历史记录里,而post中的参数不会被保留
  5. get请求在url中传递的参数是有长度限制的不超过4k,而post没有
  6. 对参数的数据类型,get只接受ASCII类型,而post没有限制
  7. get比post更不安全,因为参数直接暴露在url上,所以不能用传递敏感信息
  8. get参数通过url传递,post放在request body报文体中
  9. get产生一个tcp数据包,post产生两个tcp数据包

48.http与https的区别?

在这里插入图片描述

49.springboot 启动方式是什么?

1.调用application启动类执行他的main方法作为入口
2.在主方法中,调用了springapplication的run方法
3.在run方法里面creatApplicationContext方法,get事件监听器,判断环境(通过swatich方法),根据环境insert组件,比如说autowired,configuration等
4.最后调用refreshContext()方法刷新环境,启动spring容器和serverlet容器

50.cookie和session的区别?

  1. Cookie是客户端技术,通常保存在客户端,即本地。
    因为Cookie在客户端所以可以编辑伪造,不是十分安全
    Session是服务器端技术,在服务端。
  2. cookie 只能存储 String 类型的对象
    session 能够存储任意的 java 对象
  3. Cookie存在客户端对服务器没影响
    Session过多时会消耗服务器资源,大型网站会有专门Session服务器
  4. Cookie通过设置指定作用域只能在指定作用域有效、Session在整个网页都有效
  5. Cookie可以通过 setMaxAge设置有效时间,即使浏览器关闭了仍然存在
  6. 关闭网页Session就结束了

51.各个默认端口?

  1. 数据库
    mysql:3306 sqlserver:1433 oracle:1521
  2. 组件
    redis:6379 nginx:80 tomcat:8080
  3. springcloud
    eureka:8761 nacos:8848 dubbo:20880
    rabbitmq:5672 zuul/gateway:9527/8888

第二部分,Java的集合,也叫容器

1.Collection 和 Collections 有什么区别?

Collection 是一个集合接口,是所有线性表对象的父类。
Collections是集合类的一个工具类,包含了对集合元素进行排序和线程安全等各种操作方法。

2.List、Set、Map 之间的区别是什么?

在这里插入图片描述

3.HashMap 和 Hashtable 有什么区别?

首先说,两者都是键值类的对象

HashTable线程安全的,而HashMap线程不安全的,大多数的场景是单线程环境,在单线程环境下,HashMap效率上比hashTable要高。
HashMap允许空键值,而hashTable不允许。

4.如何决定使用 HashMap 还是 TreeMap?

对于在Map中进行插入、删除和定位元素这类操作,可以选HashMap。但如果你要对一个有序的key集合进行遍历,需要选TreeMap。

5.说一下 HashMap 的实现原理?

HashMap是基于数据结构里的散列表,在大数据情况下,能保证get的高效性。
HashMap不保证映射的顺序,特别是它不保证该顺序恒久不变。
HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。
当向Hashmap对象里put元素时,会根据key的hashcode计算hash值,根据hash值得到这个元素在数组中的位置,如果该数组在该位置上已经存放了其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放入链尾.如果数组中该位置没有元素,就直接将该元素放到数组的该位置上。

注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn)

6.说一下 HashSet 的实现原理?

HashSet在底层上,是由HashMap实现的
HashSet的值放在HashMap的key上
HashMap的value统一为PRESENT

7.ArrayList 和 LinkedList 的区别是什么?

ArrrayList底层实现的数据结构是数组,支持随机访问,而 LinkedList 的底层数据结构是双向循环链表,不支持随机访问。
使用下标访问一个元素,ArrayList 的时间复杂度是 O(1),而 LinkedList 是 O(n)。

8.哪些集合类是线程安全的?

Vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。
Statck:堆栈类,先进后出,项目中用得并不多。
Hashtable:就比hashmap多了个线程安全,所以建议使用HashMap。
enumeration:枚举,所以现在建议用Iterator来迭代。
结论是,如果在单线程情况下,不建议使用这些线程安全对象。

9.String, StringBuilder, StringBuffer的区别是什么?

具体有String、StringBuffer和StringBuilder这三个类。
String是不可变类,每次操作都会生成新的String对象,并将结果指针指向新的对象,由此会产生内存碎片。
如果要频繁对字符串修改,建议采用StringBuffer 和 StringBuilder。
StringBuffer 和 StringBuilder的差别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,由于无需维护线程安全的操作,所以StringBuilder 的性能要高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。由于大多数环境下是单线程,所以大多是用 StringBuilder。

10.TreeMap, LinkedHashMap, HashMap的区别是什么?

HashMap的底层实现是散列表,因此它内部存储的元素是无序的;
TreeMap的底层实现是红黑树,所以它内部的元素的有序的。排序的依据是自然序或者是创建TreeMap时所提供的比较器(Comparator)对象。
LinkedHashMap可以看作能够记住插入元素的顺序的HashMap。

第三部分、多线程

1.并行和并发有什么区别?

并行是指两个或多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。
在一台处理器上“同时”处理多个任务,在多台处理器上同时处理多个任务。如hadoop分布式集群。
实际应用场景里,一般是考虑多并发问题,而不是多并行问题。

2.线程和进程的区别?

进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程,但一个进程一般有多个线程。

进程在运行过程中,需要拥有独立的内存单元,否则如果申请不到,就会挂起。而多个线程能共享内存资源,这样就能降低运行的门槛,从而效率更高。

线程是是cpu调度和分派的基本单位,在实际开发过程中,一般是考虑多线程并发。

3.创建线程有哪几种方式?

①. 继承Thread类创建线程类

通过extends Thread定义Thread类的子类,并重写该类的run方法。
创建Thread子类的实例,并调用线程对象的start()方法来启动该线程。
②. 通过Runnable接口创建线程类

implements Runnable接口的实现类,并重写该接口的run()方法。
创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象。
调用线程对象的start()方法来启动该线程。
③. 通过Callable和Future创建线程

创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
使用FutureTask对象作为Thread对象的target创建并启动新线程。
调用FutureTask对象的get()方法来获得子线程执行结束后的返回值。
另外,还有通过线程池来创建线程

4.说一下 runnable 和 callable 有什么区别?

Runnable接口中的run()方法的返回值是void,在其中可以定义线程的工作任务,但无法返回值。
Callable接口中的call()方法是有返回值的,是一个泛型,一般会和Future、FutureTask配合,能异步地得到线程的执行结果。

5.线程有哪些状态?

线程通常都有五种状态,创建、就绪、运行、阻塞和死亡。

创建状态。创建好线程对象,并没有调用该对象的start方法,此时线程处于创建状态。
就绪状态。当调用线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,也就是说还没进入运行状态。或者在线程运行之后,从等待或者睡眠状态中回来之后,也会处于就绪状态,等待被调度进入运行状态。
运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个实践的发生(比如说某项资源就绪)之后再继续运行。wait方法都可以导致线程阻塞。
死亡状态。如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪

6.sleep() 和 wait() 有什么区别?

wait(): Object类中定义的实例方法。在指定对象上调用wait方法会让当前线程进入等待状态(前提是当前线程持有该对象的monitor),此时当前线程会释放相应对象的monitor,这样一来其它线程便有机会获取这个对象的monitor了。当其它线程获取了这个对象的monitor并进行了所需操作时,便可以调用notify方法唤醒之前进入等待状态的线程。

sleep(): Thread类中的静态方法,作用是让当前线程进入休眠状态,以便让其他线程有机会执行。进入休眠状态的线程不会释放它所持有的锁。

7.简述Java IO与NIO的区别

Java IO是面向流的,这意味着我们需要每次从流中读取一个或多个字节,直到读取完所有字节;NIO是面向缓冲的,也就是说会把数据读取到一个缓冲区中,然后对缓冲区中的数据进行相应处理。

Java IO是阻塞IO,而NIO是非阻塞IO。

Java NIO中存在一个称为选择器(selector)的东西,它允许你把多个通道(channel)注册到一个选择器上,然后使用一个线程来监视这些通道:若这些通道里有某个准备好可以开始进行读或写操作了,则开始对相应的通道进行读写。而在等待某通道变为可读/写期间,请求对通道进行读写操作的线程可以去干别的事情。

8.创建线程池有哪几种方式?

①newFixedThreadPool(int nThreads)

创建一个固定长度的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程规模将不再变化,当线程发生未预期的错误而结束时,线程池会补充一个新的线程。

②newCachedThreadPool()

创建一个可缓存的线程池,如果线程池的规模超过了处理需求,将自动回收空闲线程,而当需求增加时,则可以自动添加新线程,线程池的规模不存在任何限制。

③newSingleThreadExecutor()

这是一个单线程的Executor,它创建单个工作线程来执行任务,如果这个线程异常结束,会创建一个新的来替代它;它的特点是能确保依照任务在队列中的顺序来串行执行。

④newScheduledThreadPool(int corePoolSize)

创建了一个固定长度的线程池,而且以延迟或定时的方式来执行任务,类似于Timer。

9.什么是死锁?

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源而导致相互等待,由此代码无法继续下。此时称系统处于死锁状态或系统产生了死锁。

10.怎么防止死锁?

死锁的四个必要条件:

  1. 互斥条件:进程对所分配到的资源不允许其他进程进行访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源
  2. 请求和保持条件:进程获得一定的资源之后,又对其他资源发出请求,但是该资源可能被其他进程占有,此事请求阻塞,但又对自己获得的资源保持不放
  3. 不可剥夺条件:是指进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用完后自己释放
  4. 环路等待条件:是指进程发生死锁后,若干进程之间形成一种头尾相接的循环等待资源关系

11.synchronized 和 volatile 的区别是什么?

volatile是在告诉jvm当前变量在自身线程的内存区里,值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。
volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。
volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。

12.synchronized 和 Lock 有什么区别?

synchronized是java关键字,Lock是个java类;
synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
synchronized会自动释放锁,Lock需在finally中手工释放锁(unlock()方法释放锁);
用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可);
Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

结论: synchronized很重,而且大多只能加在单个方法上,而Lock可以作用在调用多个业务的方法上,使用起来比较简便。

13.ThreadLocal的设计理念与作用

ThreadLocal的作用是提供线程内的局部变量,在多线程环境下访问时能保证各个线程内的ThreadLocal变量各自独立。也就是说,每个线程的ThreadLocal变量是自己专用的,其他线程是访问不到的。ThreadLocal最常用于以下这个场景:多线程环境下存在对非线程安全对象的并发访问,而且该对象不需要在线程间共享,但是我们不想加锁,这时候可以使用ThreadLocal来使得每个线程都持有一个该对象的副本。

14.synchronized 和 ReentrantLock 区别是什么?

synchronized是关键字,ReentrantLock是类,这是二者的本质区别。
ReentrantLock是类,所以synchronized更多更灵活的特性,可以被继承、可以有方法、可以有各种各样的类变量
ReentrantLock比synchronized的扩展性体现在几点上:
ReentrantLock可以对获取锁的等待时间进行设置,这样就避免了死锁
ReentrantLock可以获取各种锁的信息
ReentrantLock可以灵活地实现多路通知
另外,二者的锁机制其实也是不一样的:ReentrantLock底层调用的是Unsafe的park方法加锁,synchronized操作的应该是对象头中mark word。

15.线程间通信的几种实现方式

方式一:使用 volatile 关键字
方式二:使用Object类的wait() 和 notify() 方法
②while轮询的方式
方式三:使用JUC工具类 CountDownLatch

第四部分、SpringCloud

1.什么是微服务?

马丁福勒(Martin Fowler)
单个轻量级服务一般为一个单独微服务,微服务讲究的是 专注某个功能的实现。
微服务强调的是服务大小,关注的是某一个点,具体解决某一个问题/落地对应的一个服务应用。

2.微服务之间如何独立通讯的?

同步通信:dobbo通过 RPC 远程过程调用、springcloud通过 REST 接口json调用 等。
异步:消息队列,如:RabbitMq、ActiveM、Kafka 等。

3.SpringCloud 和 Dubbo 有哪些区别?

首先,他们都是分布式管理框架。
dubbo 是二进制传输,占用带宽会少一点。SpringCloud是http 传输,带宽会多一点,同时使用http协议一般会使用JSON报文,消耗会更大。
dubbo 开发难度较大,所依赖的 jar 包有很多问题大型工程无法解决。SpringCloud 对第三方的继承可以一键式生成,天然集成。
SpringCloud 接口协议约定比较松散,需要强有力的行政措施来限制接口无序升级。
最大的区别:
Spring Cloud抛弃了Dubbo 的RPC通信,采用的是基于HTTP的REST方式。

4.SpringBoot 和 SpringCloud 之间关系?

SpringBoot:专注于快速方便的开发单个个体微服务(关注微观);SpringCloud:关注全局的微服务协调治理框架,将SpringBoot开发的一个个单体微服务组合并管理起来(关注宏观);
SpringBoot可以离开SpringCloud独立使用,但是SpringCloud不可以离开SpringBoot,属于依赖关系。

5.什么是熔断?什么是服务降级?

服务熔断的作用类似于我们家用的保险丝,当某服务出现不可用或响应超时的情况时,为了防止整个系统出现雪崩,暂时停止对该服务的调用。
服务降级是从整个系统的负荷情况出发和考虑的,对某些负荷会比较高的情况,为了预防某些功能(业务场景)出现负荷过载或者响应慢的情况,在其内部暂时舍弃对一些非核心的接口和数据的请求,而直接返回一个提前准备好的fallback(退路)错误处理信息。这样,虽然提供的是一个有损的服务,但却保证了整个系统的稳定性和可用性。

6.微服务的优缺点是什么?

优点:
1.耦合度比较低。不会影响其他模块的开发。
2.减轻团队的成本,可以并行开发,不用关注其他人怎么开发,先关注自己的开发。
3.配置比较简单,基本用注解就能实现,不用使用过多的配置文件。
4.微服务跨平台的,可以用任何一种语言开发。
5.每个微服务可以有自己的独立的数据库也有用公共的数据库。
6.直接写后端的代码,不用关注前端怎么开发,直接写自己的后端代码即可,然后暴露接口,通过组件进行服务通信。
缺点:
1.部署比较麻烦,给运维工程师带来一定的麻烦。
2.针对数据的管理比麻烦,因为微服务可以每个微服务使用一个数据库。
3.系统集成测试比较麻烦
4.性能的监控比较麻烦。【最好开发一个大屏监控系统】

7.eureka和zookeeper都可以提供服务注册与发现的功能,请说说两个的区别?

  1. zookeeper 是CP原则,强一致性和分区容错性。
  2. eureka 是AP 原则 可用性和分区容错性。
  3. zookeeper当主节点故障时,zk会在剩余节点重新选择主节点,耗时过长,虽然最终能够恢复,但是选取主节点期间会导致服务不可用,这是不能容忍的。
  4. eureka各个节点是平等的,一个节点挂掉,其他节点仍会正常保证服务。

8.你所知道微服务的技术栈有哪些?列举一二。

在这里插入图片描述

9.什么是微服务架构?

微服务架构 就是 对微服务进行管理整合应用的。微服务架构 依赖于 微服务,是在微服务基础之上的。

10.RabbitMQ有什么优缺点?

优点:解耦、异步、削峰;可用性高、消息延迟微秒、信息可靠性高。
缺点:降低了系统的稳定性:本来系统运行好好的,现在你非要加入个消息队列进去,那消息队列挂了,你的系统不是呵呵了。因此,系统可用性会降低;增加了系统的复杂性:加入了消息队列,要多考虑很多方面的问题,比如:一致性问题、如何保证消息不被重复消费、如何保证消息可靠性传输等。因此,需要考虑的东西更多,复杂性增大。

11.Rabbitmq常见的消息模型有哪些?

  1. 基本消息队列:BaseQueue
  2. 工作消息队列:WorkQueue
  3. 发布订阅:Publish/Subscribe
    (1)Fanout Exchange 广播
    (2)Direct Exchange 路由(Routingkey指定的)
    (3)Topic Exchange 主题(#:0个或多个、*:代表一个)

12.Ribbon的IRULE的规则有哪些?

规则 解释
RoundRobinRule 轮询
RoundRule 随机
RetryRule 重试
WeightedResponseTimeRule 权重
ZoneAvoidanceRule 默认,对Zone分类的多个轮询
AvailabilityFilteringRule 会过滤掉那些不可用的服务
BestAvailableRule 忽略那些短路的服务

13.Eureka与Nacos的区别是什么?

接口方式:Nacos与Eureka都是对外暴露Rest风格的API接口、注册、发现
实例类型:Nacos分永久和临时实例;Eureka只支持临时实例
健康监测:Nacos对临时实例采用心跳,对永久实例采用主动;Eureka只支持心跳
服务发现:Nacos支持定时和订阅推送;Eureka只支持定时拉取

14.Nacos配置管理多种配置的优先级是什么?

服务名-profile.yml > 服务名.yml > 本地配置

15.Nacos注册表结构

在这里插入图片描述

16.Feign的自定义配置

类型 作用
feign.logger.level 修改日志级别
feign.codec.decoder 相应结果的解析器
feign.codec.encoder 请求参数编码
feign.contract 支持的注解格式
feign.retryer 失败重启机制

17.路由过滤器GatewayFilter有哪些?

名称 说明
AddRequestHeader 给当前请求添加一个请求头
RemoveRequestHeader 移除请求中的一个请求头
AddResponseHeader 给响应结果中添加一个响应头
RemoveResponseHeader 从相应结果中移除一个响应头
RequestRateLimiter 限制请求的流量

第五部分、Redis

1.什么是缓存穿透

缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。缓存穿透是指缓存和数据库中都没有的数据

缓存穿透的解决方案
布隆过滤器:
布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力;在访问缓存层和存储层之前,将存在的key用布隆过滤器提前保存起来,做第一层拦截,当收到一个对key请求时先用布隆过滤器验证是key否存在,如果存在在进入缓存层、存储层。可以使用bitmap做布隆过滤器。这种方法适用于数据命中不高、数据相对固定、实时性低的应用场景,代码维护较为复杂,但是缓存空间占用少。

缓存空对象:
缓存空对象:是指在持久层没有命中的情况下,对key进行set(key,"")
当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源;

2.什么是缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。在缓存失效的瞬间,有大量的请求并发访问,这类数据一般是热点数据,由于缓存过期,会同时访问数据库来查询最新数据,造成后端负载加大,甚至可能会让应用崩溃。
例如:一个秒杀的场景,同时几万个用户同时抢购,缓存中没有数据,几万个用户会同时去查询数据 ,可能会造成服务器宕机。

缓存击穿解决方案
1、设置热点数据永不过期
从缓存层面来看,没有设置过期时间,所以不会出现热点 key 过期后产生的问题。
2、分布式互斥锁
分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,该线程查询数据完成后,重建缓存set(key,value,timeout)。其他线程没有获得分布式锁的权限,因此只需要等待即可。等待缓存重构完成后重新从缓存获取数据即可。

第六部分:MYSQL

1.mybatis常用标签有哪些?

在这里插入图片描述

2.数据库三大范式是什么?

第一范式就是属性不可分割。属性是什么?就是表中的字段。
第二范式就是要有主键,要求其他字段都依赖于主键。
第三范式就是要消除传递依赖,方便理解,可以看做是“消除冗余”。

3.mybatis 有几种分页方式?

  1. 数组分页
  2. sql分页
  3. 拦截器分页
  4. RowBounds分页

4.MySQL 存储过程

存储过程(Stored Procedure)是一种在数据库中存储复杂程序,以便外部程序调用的一种数据库对象。
存储过程是为了完成特定功能的SQL语句集,经编译创建并保存在数据库中,用户可通过指定存储过程的名字并给定参数(需要时)来调用执行。
存储过程思想上很简单,就是数据库 SQL 语言层面的代码封装与重用。
创建存储个过程使用关键字:DELIMITER
优点

  1. 封装性
  2. 可增强 SQL 语句的功能和灵活性
  3. 可减少网络流量
  4. 高性能
  5. 提高数据库的安全性和数据的完整性
  6. 使数据独立

缺点

  1. 存储过程,往往定制化于特定的数据库上,因为支持的编程语言不同。当切换到其他厂商的数据库系统时,需要重写原有的存储过程。
  2. 存储过程的性能调校与撰写,受限于各种数据库系统。

5.索引类型及其作用

普通索引:最基本的索引,对数据没有任何限制,可以加快检索速率
唯一索引:要求数据不能重复,数据可以null,同一个表中可以建立多个唯一索引
主键索引:数据不能重复,数据不可以为null,同一个表中只能有一个主机索引
组合索引:多个列的值组成一个索引
全文索引:对文本的内容进行分词,进行搜索
创建索引:creat index index_name on table_name (‘column’)

6.什么情况下索引会失效?

  1. like查询是以%开头
  2. 条件中有or
  3. where的判断条件null
  4. where语句中使用 <>和 !=
  5. 如果mysql估计使用全表扫描要比使用索引快,则不使用索引
  6. 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引

7.left join、right join和inner join的区别

left join 左侧的表为主表
right join 右侧的表为主表
inner join查找的数据是左右两张表共有的

8.游标

  1. 声明一个游标: declare 游标名称 CURSOR for table;(这里的table可以是你查询出来的任意集合)
  2. 打开定义的游标:open 游标名称;
  3. 获得下一行数据:FETCH 游标名称 into testrangeid,versionid;
  4. 需要执行的语句(增删改查):这里视具体情况而定
  5. 释放游标:CLOSE 游标名称;
    注:mysql存储过程每一句后面必须用;结尾,使用的临时字段需要在定义游标之前进行声明。

9.浅谈MySQL中优化sql语句查询常用的方法

  1. 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
  2. 应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
  3. 应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描。
  4. 应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描。
  5. 下面的查询也将导致全表扫描:select id from t where name like '%abc%'若要提高效率,可以考虑全文检索。
  6. in 和 not in 也要慎用,否则会导致全表扫描。
  7. 如果在 where 子句中使用参数,也会导致全表扫描。
  8. 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。
  9. 应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
  10. 不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
  11. 在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。
  12. 不要写一些没有意义的查询,如需要生成一个空表结构。
  13. 很多时候用 exists 代替 in 是一个好的选择:
  14. 并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。
  15. 索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
  16. 应尽可能的避免更新 clustered 索引数据列,因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新 clustered 索引数据列,那么需要考虑是否应将该索引建为 clustered 索引。
  17. 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
  18. 尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
  19. 任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。
  20. 尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。
  21. 避免频繁创建和删除临时表,以减少系统表资源的消耗。
  22. 临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。
  23. 在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。
  24. 如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。
  25. 尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。
  26. 使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。
  27. 与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。
  28. 在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。
  29. 尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
  30. 尽量避免大事务操作,提高系统并发能力。

第七部分:前端

1.内元素和块级元素有哪些?

行内元素:

<a>标签可定义锚
<abbr>表示一个缩写形式
<acronym>定义只取首字母缩写
<b>字体加粗
<bdo>可覆盖默认的文本方向
<big>大号字体加粗
<br>换行
<cite>引用进行定义
<code>定义计算机代码文本
<dfn>定义一个定义项目
<em>定义为强调的内容
<i>斜体文本效果
<img>向网页中嵌入一幅图像
<input>输入框
<kbd>定义键盘文本
<label>标签为
<input> 元素定义标注(标记)
<q>定义短的引用
<samp>定义样本文本
<select>创建单选或多选菜单
<small>呈现小号字体效果
<span>组合文档中的行内元素
<strong>语气更强的强调的内容
<sub>定义下标文本
<sup>定义上标文本
<textarea>多行的文本输入控件
<tt>打字机或者等宽的文本效果
<var>定义变量

块级元素:

<address>定义地址
<caption>定义表格标题
<dd>定义列表中定义条目
<div>定义文档中的分区或节
<dl>定义列表
<dt>定义列表中的项目
<fieldset>定义一个框架集
<form>创建 HTML 表单
<h1>定义最大的标题
<h2>定义副标题
<h3>定义标题
<h4>定义标题
<h5>定义标题
<h6>定义最小的标题
<hr>创建一条水平线
<legend>元素为 
<fieldset>元素定义标题
<li>标签定义列表项目
<noframes>为那些不支持框架的浏览器显示文本,于 frameset 元素内部
<noscript>定义在脚本未被执行时的替代内容
<ol>定义有序列表
<ul>定义无序列表
<p>标签定义段落
<pre>定义预格式化的文本
<table>标签定义 HTML 表格
<tbody>标签表格主体(正文)
<td>表格中的标准单元格
<tfoot>定义表格的页脚(脚注或表注)
<th>定义表头单元格
<thead>标签定义表格的表头
<tr>定义表格中的行

2.行内元素和块级元素的转化:

把块级元素转换成行内元素:display:inline;
将行内元素转换成块级元素:display:block;
行内块元素:display:inline-block;

猜你喜欢

转载自blog.csdn.net/SmileSunshines/article/details/123085154