抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

Java面试

进程和线程有什么区别

1.线程是进程的子集,一个进程里包括多个线程,每个线程执行不同的任务
2.每个进程占用不同的内存空间,而所有线程共享一个相同的内存空间
3.每个线程拥有单独的栈内存用来存储本地的数据

mysql索引的优点与缺点

索引是一种单独存储在磁盘上的一种数据结构,它是基于存储引擎实现的,MySQL中索引的存储类型有两种,即BTREE和HASH
优点:
1.通过创建唯一索引,可以保证数据库表中每一行数据的唯一性
2.使用索引查询数据,加快查询速度
3.在数据库参照完整性方面,可以加速表与表的连接
缺点:
1.索引需要占用磁盘空间
2.创建索引和维护索引耗费时间,并且随着数量的增加所耗费的时间也会增加
3.当对表中的数据进行增加,修改删除时,索引也需要动态的维护,这就降低了数据的维护速度

死锁的定义以及发生的条件

死锁:两个或者两个以上的线程相互竞争资源而造成持续等待的情况。若无外力的作用则会一直等待下去
死锁产生的条件:
1.互斥:一个资源同一时刻只能由一个线程执行
2.请求与保持:一个线程在请求获得资源的同时,对已获得的资源保持不放
3.循环等待:发生死锁时所有线程都会成为一个死循环
4.不可剥夺条件:线程在对所获得的资源在未使用完时,不能被其他线程剥夺,只能自己释放

Redis的数据类型

redis中常用的五中数据结构:string,list,set,zset,hash
String结构底层是一个简单动态字符串,支持扩容,存储字符串
list存储线性有序且可重复的元素,底层数据结构可以是双向链表/压缩列表
set存储不可重复的元素,一般用于求交集、差集等,底层数据结构可以是hash和整数数组
zset存储的是有序不可重复的元素,zset为每个元素添加了一个score属性作为排序依据,底层数据结构可以是ziplist和跳表
hash类型存储的是键值对,底层数据结构是ziplist和hash

乐观锁和悲观锁

乐观锁:乐观锁总是假设最好的情况,每次拿数据时默认别人不会修改,所以不会上锁,只有在更新时会判断一下
在此期间有没有人更新数据
悲观锁:悲观锁总是假设最坏的情况,每次去拿数据是都认为别人会修改,所以每次在拿数据时都会上锁,这样别人想拿这个数据时会阻塞直到拿到锁。
mysql数据库的共享锁和排他锁都是悲观锁的实现

AOP的理解

AOP面向切面编程。是spring两大核心之一,它是一种编程思想,是对OOP的一种补充。它可以对业务逻辑的各个部分进行隔离,降低耦合,提高代码的可重用性。
它的底层是通过动态代理实现的。它的应用场景有事务、日志管理等。

对反射的理解

反射就是在程序运行期间动态获取对象的属性和方法的功能。
获取Class对象的三种方式:getClass();xx.class;Class.forName(“xx”);
优点:运行期间能够动态的获取类,提高代码的灵活性
缺点:性能比直接的Java代码要慢很多

请你说说聚簇索引和非聚簇索引

两者主要区别是数据和索引是否分离。聚簇索引是将数据与索引存储到一起,找到索引也就找到了数据;
而非聚簇索引是将数据和索引存储分离开,索引树的叶子节点存储了数据行的地址
在InnoDB中,一个表只有一个聚簇索引,并且该索引建立在主键上,即使没有指定主键
也会特殊处理生成一个聚簇索引,其他索引都是辅助索引,使用辅助索引访问索引外的其他字段时都需要进行二次查找。

数据库为什么不用红黑树而用B+树

索引的数据结构会被存储在磁盘里,每次查询都需要去磁盘中访问,对于红黑树,树的高度可能会非常高
,会进行很多次的磁盘IO,效率会非常低,而B+树的高度一般为2-4,也就是说最坏的情况下,最多会进行
2到4次的磁盘IO,在实际中性能比较高。

线程安全的集合有哪些

java.uti包中的集合类大部分都是非线程安全的,例如:ArrayList/LinkedList/HashMap等等,
但也有少部分是线程安全的,像是Vector和Hashtable,它们属于很古老的API了,是基于Synchronized
实现的,性能很差,在实际的开发中不常用。一般可以使用collections工具类中的syncheronizedXxx()方法将非线程安全的集合包装成线程安全的类。
在java5之后可以使用concurrent包提供的大量的支持并发访问的集合类,例如ConcurrentHashMap/CopyOnWriteArrayList等

缓存穿透、击穿、雪崩的区别

缓存穿透:

客户端访问不存在的数据,使得请求直达到数据库,导致负载量过大,直到宕机。原因可能是业务层误删
了缓存和库中的数据,或者有人恶意访问不存在的数据。

缓存穿透解决方法:

1.数据库没有找到数据后,返回空值存入缓存层,客户端在访问时,缓存直接返回空值
2.将数据存入布隆过滤器,访问存储之前经过滤器拦截,若请求的数据不存在则直接返回空值。
3.设置参数校验

缓存击穿:

一份热点数据,它的访问量非常的大,在它缓存失效的瞬间,大量请求直达数据库,导致服务崩溃

缓存击穿解决方法:

1.设置热点数据永久不过期
2.在缓存去访问数据库时加互斥锁,这样一个线程访问数据库时,另一个线程只能等待,这个线程
访问完后缓存中的数据将被重新建立,届时其他线程可以去缓存中访问了

缓存雪崩

大量数据同时过期,或者是redis节点故障导致服务不可用,缓存无法提供服务,所有请求直达数据库
造成数据库宕机。

缓存雪崩解决方法:

1.避免数据同时过期,设置随机过期的时间
2.启动降级和熔断措施
3.设置数据永不过时
4.采用redis集群,一个宕机,其他还可以用

Redis如何与数据库保持双写一致性

策略1:先更新缓存,再更新数据库
策略2:先更新数据库,再更新缓存
策略3:先删除缓存,再更新数据库
策略4:先更新数据库,再删除缓存
解决方法:延时双删,先删除缓存,再修改数据库,延迟一段时间再删除缓存

线程的同步方式

1.java通过加锁实现线程的同步,所有两类:synchronized和Lock。
2.synchronized加在三个不同的位置,对应三种不同的使用方式,这三种方式的区别是锁对象不同:
(1.)加在普通方法上,则锁是当前的实例(this)。
(2.)加在静态方法上,锁是当前类的Class对象。
(3.)加在代码块上,则需要在关键字后面的小括号里,显式指定一个对象作为锁对象。
Lock支持的功能包括:支持响应中断、支持超时机制、支持以非阻塞的方式获取锁、支持多个条件变量(阻塞队列)

synchronized与lock的区别

1.synchronized是Java关键字,再JVM层面实现加锁和解锁;Lock是一个接口,在代码层面实现加锁和解锁
2.synchronized可以用在代码块和方法上;Lock只能写在代码里
3.synchronized在代码执行完或者出现异常时自动释放锁;Lock不会自动释放锁,则需要在finally里显示释放锁
4.synchronized会导致线程拿不到锁一直等待;Lock可以设置获取锁失败的超时时间
5.synchronized无法得知是否获得锁成功;Lock则可以通过tryLock得知加锁是否成功
6.synchronized锁可重入、不可中断、非公平;Lock锁可重入、可中断、可公平/不公平,并可以细分读写锁以提高效率。

String、StringBuffer、StringBuilder有什么区别

StringBuilder和StringBuffer非常类似,均代表可变的字符序列,而且方法也一样
String:不可变字符序列,效率低,但是复用率高。
StringBuffer:可变字符序列、效率较高(增删)、线程安全
StringBuilder:可变字符序列、效率最高、线程不安全

HashMap的底层原理

在1.8之前,HashMap的底层是通过数组加链表实现的,在1.8之后是通过数组+链表+红黑树实现的;
它的put流程是:基于哈希算法来确定元素位置,当我们向集合存入数据时,他会计算传入key的哈希值,并
利用哈希值取绝对值再根据集合长度取余来确定元素值的位置,如果这个位置已经有其他的元素了,就会发生
哈希碰撞,则hashmap就会通过链表将这些元素组织起来,如果链表的长度达到8,就会转化为红黑树,从而
提高查询速度。
扩容机制:HashMap中数组的默认初始容量为16,当达到默认负载因子0.75时,会以2的指数倍进行扩容。
Hashmap时非线程安全的,在多线程环境下回产生循环死链,因此在多线程环境下建议使用ConcurrentHashMap。

JVM内存模型

JVM由三部分组成:类加载子系统、执行引擎、运行时数据区。
1.类加载子系统可以根据指定的全限定名来载入类或者接口
2.执行引擎,负责执行哪些包含在被载入类的方法中的指令
3.运行时数据区:在程序运行时,存储程序的内容,例如:字节码、对象、参数、返回值等。运行时数据区又分为方法区、堆、栈、程序计数器

接口和抽象类的区别

加分回答 在二者的设计目的上,接口作为系统与外界交互的窗口,体现了一种规范。对于接口的实现者来说,接口规定了实现者必须向外提供哪些服务;
对于接口的调用者而言,接口规定了调用者可以调用哪些服务,以及如何调用这些服务;抽象类则不一样,抽象类作为系统中多个子类的共同父类,它体现的是一种模板式设计。
抽象类作为多个子类的父类,它可以被当作系统实现过程中的中间产品
接口和抽象类相同点:
1.接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其他类实现和继承
2.接口和抽象类都可以有抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法
接口和抽象类的差异:
1.接口里只能包含静态方法、默认方法、私有方法、抽象方法且不能为普通方法提供实现,抽象类则可以定义方法的实现
2.接口里只能定义静态常量,不能定义普通的成员变量,抽象类里既可以定义普通成员变量,也可以定义静态常量
3.接口里不包含构造器;抽象类可以包含构造器,但抽象类的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作
4.接口里不能包含初始化块,抽象类则可以包含初始化块
5.一个类最多只能有一个父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承的不足

synchronize的用法及原理

synchronized可以修饰静态方法、普通方法、代码块。 能够保证同一个时刻只有一个线程执行该段代码,保证线程安全。 在执行完或者出现异常时自动释放锁。
synchronized作用在代码块时,它的底层是通过monitorenter、monitorexit指令来实现的。

说说static修饰符的用法

ava类中包含了成员变量、方法、构造器、初始化块和内部类(包括接口、枚举)5种成员,static关键字可以修饰除了构造器外的其他4种成员。static关键字修饰的成员被称为类成员。
类成员属于整个类,不属于单个对象。 static关键字有一条非常重要的规则,即类成员不能访问实例成员

说说你对ThreadLocal的理解

ThreadLocal,即本地线程变量,他将需要并发访问的资源复制多份,让每个线程拥有一份资源。由于每个线程都拥有自己的资源副本,从而就没有必要
对该变量就行线程同步了。ThreadLocal提供了线程安全的共享机制,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal

Spring Boot常用的注解

@SpringBootApplication注解:它是SpringBoot的核心注解,用于开启自动配置,准确的是通过该注解内的@EnableAutoConfiguration的注解实现的
自动配置。
@EnableAutoConfiguration:自动配置注解,在启动Spring应用程序上下文时进行自动配置,自动配置通常是基于项目classpath中引入的类和已经定义
的bean来实现的。
@Import:@EnableAutoConfiguration的关键功能是通过@Import注解导入ImportSelector来完成的。
@Congiguration:配置类注解,根据一些特定条件来控制bean的实例化的行为。 @ComponentScan:位置在SpringBoot的启动类上,Spring包扫描。

说说你了解的线程通信方式

在Java中提供了两种多线程通信方式分别是利用monitor实现通信方式和使用condition实现线程通信方式。
使用不同的线程同步方式也就相应的使用不同的线程通信方式。当我们使用synchronize同步时就会使用monitor来实现线程通信,
这里的monitor其实就是锁对象,其利用object的wait,notify,notifyAll等方法来实现线程通信。
而使用Lock进行同步时就是使用Condition来实现线程通信,Condition对象通过Lock创建出来依赖于Lock对象,使用其await,sign或signAll方法实现线程通信。

HashMap和Hashtable的区别

  1. Hashtable在实现Map接口时保证了线程安全性,而HashMap则是非线程安全的。所以,Hashtable的性能不如HashMap,因为为了保证线程安全它牺牲了一些性能。
  2. Hashtable不允许存入null,无论是以null作为key或value,都会引发异常。而HashMap是允许存入null的,无论是以null作为key或value,都是可以的。
  3. 虽然Hashtable是线程安全的,但仍然不建议在多线程环境下使用Hashtable。因为它是一个古老的API,从Java 1.0开始就出现了,它的同步方案还不成熟,性能不好。
    如果要在多线程环下使用HashMap,建议使用ConcurrentHashMap。它不但保证了线程安全,也通过降低锁的粒度提高了并发访问时的性能。

MyBatis的缓存机制

一级缓存也称为本地缓存,它默认启用且不能关闭。一级缓存存在于SqlSession的生命周期中,即它是SqlSession级别的缓存,
在同一个SqlSession中查询时,MyBatis会把执行的方法和参数通过算法生成缓存的键值,将键值和查询结果存入一个Map对象中,
如果同一个SqlSession中执行的方法和参数完全一致,则会将缓存的对象返回;
二级缓存则为SqlSessionFactory,mybaits的全局配置setting有一个参数cacheEnabled,这个参数是二级缓存的全局开关,
默认值是true,初始状态为启用状态,映射语句文件中的所有SELECT 语句将会被缓存。
映射语句文件中的所有时INSERT 、UPDATE 、DELETE 语句会刷新缓存。缓存会使用Least Recently U sed ( LRU ,最近最少使用的)算法来收回

@Autowired和@Resource注解的区别

@Autowied是Spring提供的注解,@Resource是JDK提供的注解。@Autowied是只能按类型注入,@Resource默认按名称注入,也支持按类型注入。
@Autowired按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false,如果我们想使用按名称装配,
可以结合@Qualifier注解一起使用

sleep()和wait()的区别

sleep()是Thread类中的静态方法,而wait()是Object类中的成员方法;
sleep()可以在任何地方使用,而wait()只能在同步方法或同步代码块中使用;
sleep()不会释放锁,而wait()会释放锁,并需要通过notify()/notifyAll()重新获取锁。

Spring MVC的执行流程

1.整个过程开始于客户端发送一个http请求,web服务器接收到这个请求。如果匹配DispatcherServlet的请求映射路径,则web服务器将该请求
交给DispatcherServlet处理
2.DispatcherServlet接收到请求后,将根据请求的信息包括URL、HTTP方法、请求报文头、请求参数、Cookie等)及HandlerMapping的配置找到处理请求的处理器(Handler)。
可将HandlerMapping看做路由控制器,将Handler看做目标主机。值得注意的是,在Spring MVC中并没有定义一个Handler接口,实际上任何一个Object都可以成为请求处理器。
3.当DispatcherServlet根据HandlerMapping得到对应当前请求的Handler后,通过HandlerAdapter对Handler进行封装,再以统一的适配器接口调用Handler。
HandlerAdapter是Spring MVC框架级接口,顾名思义,HandlerAdapter是一个适配器,它用统一的接口对各种Handler方法进行调用
4.处理器完成业务逻 辑的处理后,将返回一个ModelAndView给DispatcherServlet,ModelAndView包含了视图逻辑名和模型数据信息。
5.ModelAndView中包含的是“逻辑视图名”而非真正的视图对象,DispatcherServlet借由ViewResolver完成逻辑视图名到真实视图对象的解析工作。
6.当得到真实的视图对象View后,DispatcherServlet就使用这个View对象对ModelAndView中的模型数据进行视图渲染。
7.最终客户端得到的响应消息可能是一个普通的HTML页面,也可能是一个XML或JSON串,甚至是一张图片或一个PDF文档等不同的媒体形式。

在MyBatis中$和#有什么区别

使用$设置参数时,MyBatis会创建普通的SQL语句,然后在执行SQL语句时将参数拼入SQL,而使用#设置参数时,MyBatis会创建预编译的SQL语句,然后在执行SQL
时MyBatis会为预编译SQL中的占位符赋值预编译的SQL语句执行效率高,并且可以防止注入攻击,效率和安全性都大大优于前者,但在解决一些特殊问题,如在一些根据不同的条件产生
不同的动态列中,我们要传递SQL的列名,根据某些列进行排序,或者传递列名给SQL就只能使用$了。