[Java 转载] JAVA新手面试整理

1、JDK、JRE、JVM区别和联系

jvm:java虚拟机。它只认识 xxx.class 这种类型的文件,它能够将 class 文件中的字节码指令进行识别并调用操作系统向上的 API 完成动作。所以说,jvm 是 Java 能够跨平台的核心

jre:运行环境。它主要包含两个部分,jvm 的标准实现和 Java 的一些基本类库。它相对于 jvm 来说,多出来的是一部分的 Java 类库。

jdk:开发工具包。包含jre和jvm。

2、==和equals的区别

==:用于比较引用和比较基本数据类型时具有不同的功能。

equal:用来检测两个对象是否相等,即两个对象的内容是否相等。

3、final

被final修饰的变量不能被改变,被final修饰的类不能被继承,被final修饰的方法不能被重写。

4、String、StringBuffer、StringBuild

String:是一个不可变字符串,底层使用final修饰

在修改字符串操作比较多的时候用StringBuilder或StringBuffer.

在要求线程安全的情况下用StringBuffer

在不要求线程安全的情况下用StringBuilder

5、重载和重写的区别

重载:方法名一致,参数列表不同,参数类型不同。与返回值无关

重写:方法名一致,参数列表一致,返回类型一致,存在子类中。

6、接口和抽象类

抽象类:只能单继承。可以存在普通成员函数。成员变量可以是多种类型的。

接口:多实现。只能只存在public abstract方法。只能是 publi static final类型的。

7、list和set的区别

list:有序可重复。按对象进入顺序保存对象,允许多个Null元素对象,可以用iteratiterator遍历取出所有元素。在逐一遍历,还可以使用get(int index)获取指定下标元素。

set:无序不可重复最多允许一个Null元素对象,取元素时只能通过iteratoriterator取得所有元素,在逐一遍历各个元素。

  1. 8、hashCode和equals

两者都是比较对象

equals比较,比较的比较全面、比较复杂,性能低,所以加上hashCode取得hash码更加快速,准确。

直接使用hashCode来比较的话,不同的对象可能会拥有相同的hash码,所以比较的结果不是那么的准确。

9、ArrayList和linkedList区别

ArrayList基于数组实现,连续存储在内存中。从中间插入元素比linkedList慢,因为他会将其之后的元素复制,再写入。从末尾添加就不会比linkedList慢~

linkedList基于链表实现,分散在内存中。

10、HashMap和HashTable的区别

HashMap:非线程安全的,允许key和value为null。

底层基于链表和数组实现。java8开始链表高度达到8,数组长度超过64,链表转化为红黑树,元素以内部类Node节点存在。

key为nul,存在下标0的位置。

HashTable:线程安全的,每一个方法synchronized修饰。不允许key和value为null

11、ConcurrentHashMap原理,jdk7和jdk8版本的区别

jdk1.7

数据结构:ReentrantLock+Segment+HashEntity,一个Segment中包含一个HashEntity数组,每个HashEntity又是一个链表结构

jdk1.8

synchronized+CAS(乐观锁)+Node+红黑树,Node的val和next都用volatile修饰,保证可见性,查找、替换、赋值操作都是使用CAS

12、如何实现一个IOC容器

配置文件配置包扫描路径

递归包扫描获取.class文件

反射、确定需要交给ioc管理的类

对需要注入的类进行依赖注入

13、java类加载器有哪些

根加载器,bootstraClassLoader

扩展加载器:ExtenuationClassLoader

应用程序加载器:AppClassLoader

自定义加载:比如阿里巴巴觉得JDK8不好用,自己编写一个alibbaJDK.(高端定制)

14、什么叫双亲委派机制?

类加载器去加载类的时候,从上往下加载,加载到了类,后边的就不加载了。

双亲委派机制的作用就是保证程序的安全。

15、什么是字节码?

.class文件中的二进制数据就是字节码。

代{过}{滤}理类要实现的接口是MethodInterceptor

而且需要一个增强剂的类(Enhancer)

16、JAVA中异常体系

java中的所有异常都来自顶级父类Throwable。Throwble下有两个子类Exception和Error

Exeception:不会导致程序终止。分为runTimeExeception和CheckedExeception检查异常。

Error:表示程序无法处理的错误,一旦发生错误,将停止程序运行。如内存溢出

17、Gc如何判断对象可以被回收

强引用:就算内存不足也不会被回收

弱引用:内存不足时,发现就会被回收

软引用:发现就会被回收

虚引用:形同虚设,随时都会被回收

18、线程的生命周期,线程有哪些状态

线程通常有五种状态:

创建(新建)

就绪

运行

阻塞

死亡

阻塞的情况又分为三种

等待阻塞:运行线程执行wait()方法会使线程处于等待状态,不能被自动唤醒,必须依靠其它线程调用notifyAll()方法

同步阻塞:运行线程在获取对象的同步锁时,若该同步被其他线程占用,则JVM会把线程放入“锁池”中

其他阻塞:运行的线程执行sleep或join方法,或者发出I/O请求时,JVM会把该线程置为阻塞状态。当sleep状态超时,join等待线程终止或者超时,或者I/O处理完毕,线程会重新进入就绪状态。

19、sleep()、wait()、join()、yield()的区别

sleep:sleep 方法是属于 Thread类中的,sleep 过程中线程不会释放锁,只会阻塞线程,让出cpu给其他线程,但是他的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态,可中断,sleep 给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会

wait:属于 Object 类中的,wait 过程中线程会释放对象锁,只有当其他线程调用 notify 才能唤醒此线程。wait 使用时必须先获取对象锁,即必须在 synchronized 修饰的代码块中使用,那么相应的 notify 方法同样必须在 synchronized 修饰的代码块中使用,如果没有在synchronized 修饰的代码块中使用时运行时会抛出IllegalMonitorStateException的异常

join:等待调用join方法的线程结束之后,程序再继续执行,一般用于等待异步线程执行完结果之后才能继续运行的场景。例如:主线程创建并启动了子线程,如果子线程中要进行大量耗时运算计算某个数据值,而主线程要取得这个数据值才能运行,这时就要用到 join 方法了

yield和 sleep 一样都是 Thread 类的方法,都是暂停当前正在执行的线程对象,不会释放资源锁,和 sleep 不同的是 yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,所以执行yield()的线程有可能在进入到可执行状态后马上又被执行。还有一点和 sleep 不同的是 yield 方法只能使同优先级或更高优先级的线程有执行的机会

20、线程安全的理解

多个线程的结果与单线程的结果一致,或者说是多线程运行后的结果是预期的结果

21、Thread、Runable的区别

Thread和Runable实际是继承关系,操作复杂线程推荐使用thread,如果只是执行一个简单线程建议使用runable

22、ThreadLocal的原理和使用场景

通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。而使用ThreadLocal创建的变量只能被当前线程访问,其它线程则无法访问及修改。 Thread.currentThread():获取当前线程的引用,既代码段正在被哪一个线程调用。

ThreadLocal的实现原理就是ThreadLocal里面有一个静态的ThreadLocalMap

ThreadLocalMap是ThreadLocal里面的一个静态类

ThreadLocal的值是放入了当前线程的一个ThreadLocalMap实例中,所以只能在本线程中访问,其他线程无法访问。

ThreadLocal类的应用场景:承载一些线程相关的数据

因为javaee三层架构里面,如果使用事务,要在service层里面进行开启事务(因为处理逻辑业务都是service层),然后又因为如果我们要使用事务,那么就必须保证执行sql语句的connection连接和开启事务的connection连接都要保持是同一个对象,所以我们要确保在service层和dao层的两个connection连接都是同一个,但是怎么保证connection连接对象都是同一个呢 据,service层处理业务),connection连接对象我们应该是在service层出现的,但是你却放到了dao层,这样数据的处理和逻辑业务的处理没有分离开来,javaee的三层开发就没有他的效果了,所以这一种方式的解决方法不好,所以我们就通过ThreadLocal的方式来存储这个connection对象,这样就能够保证在service层和dao层的数据保证一致了

23、并发、并行、串行的区别

串行:在时间上不可能发生重叠,前一个任务没弄完,下一个任务就只能等待

并行:在时间上是重叠的,两个任务在同一时刻互不干扰的同时执行

并发:允许两个任务彼此干扰。同一时间点,只有一个任务运行,交替执行

24、并发的三大特性

原子性

不可中断,要么全部执行,要么全部不执行

关键字:synchronized

可见性

对其他线程的可见性,a修改了线程的值,其它线程也能发现

关键字:synchronized、volatile、final

有序性

虚拟机在编译时,对于那些改变顺序之后不会对最终结果造成影响的代码,虚拟机不会按照我们期望的循序执行,有可能对他们重新排序,实际上,对于那些代码重新排序之后,虽然对变量的值没有造成影响,但是,可能会出现线程安全问题

关键字:synchronized、volatile

25、为什么用线程池?解释下线程池的参数?

频繁的创建和销毁线程,比较的消耗资源

提高线程的可管理性

corePoolSize:代表核心线程数,也就是正常情况下创建工作的线程,这些线程创建后并不会消除,而是一种常驻线程

maxinumPoolSize:代表最大线程数,表示最大允许创建的数量。

keepAliveTime:代表超出核心线程之外的空闲存活时间。

workQueue:用来存放执行的任务

ThreadFactory:线程工厂,用来生产线程执行任务

Handler:任务拒绝策略。有两种:(1)当我们调用shutdown等方法来关闭线程池后,但在线程池内还有没有完成的任务,我们还想继续提任务,但是由于线程池已经关闭,就会遭到拒绝。(2)当线程已经达到最大线程数,已经没有能力提交新的任务,也会遭到拒绝。

26、线程池中线程复用原理

首先线程池会有一个管理任务的队列,这个任务队列里就是存放着各种任务,线程池会一直不停的循环的去查看消息队列里有没有接到任务,如果没有,则继续循环,如果有了则开始创建线程。

27、Spring是什么

Spring是一个开源框架

Spring为简化企业应用开发而生

28、谈谈你对AOP的理解

切面编程,解耦合,不破坏代码结构

29、谈谈你对IOC的理解

控制反转,传统是new一个对象,而用了spring交给spring去管理,创建对象。 第一步:编写applicationContext.xml文件,固定的,不需要自己创建。找个项复制来就行。 第二步:在此文件中配置想交给spring容器管理的对象实例。 第三步:加载applicationContext.xml文件,得到applicationContext对象实例, 第四步:调用getBean方法拿到配置的实例对象。

30、BeanFactory和ApplicationContext有什么区别

BeanFactory:在启动中不会实例化Bean,在拿取的时候才会。

ApplicationContext:启东时就会实例化。

31、springBean生命周期

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

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

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

如果bean实现了BeanFactoryAware接口,工厂传递自身的实例来调用setBeanFactory()

如果存在与bean关联的任何BeanPostProcessors,则调用preProcessBeforeiniyialization()方法

如果bean指定了init方法(<bean>的init-method属性),那么将调用他。

如果存在与bean关联的任何BeanPostProcessors,则将调用postProcessAfterinitialization()方法

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

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

32、spring benan的作用域

Singleton:每个spring ioc容器仅有一个单实例

prototype:每次请求都会产生一个新的实例

Request:每次HTTP请求都会产生一个新的实例,且该bean仅在当前Http请求有效

session:每次HTTP请求都会产生新的bean,且只在当前Http Session有效

global-session:在一个全局的Http Session中一个bean对应一个实例。(该作用域仅在基于web的Spring ApplicationContext情形下有效)

33、Spring框架中的单例Bean是线程安全的吗?

不是,Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的Spring bean并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用域由“singleton”变更为“prototype”。

34、Spring框架中都用到了那些设计模式

代{过}{滤}理模式—在AOP和remoting中被用的比较多。

单例模式—在spring配置文件中定义的bean默认为单例模式。

模板方法—用来解决代码重复的问题。

工厂模式—BeanFactory用来创建对象的实例。

适配器--spring aop

装饰器--spring data hashmapper

观察者-- spring 时间驱动模型

回调--Spring ResourceLoaderAware回调接口

35、事务的并发问题

脏读:一个事务读取到了另一个事物还未提交的数据

虚度:一个事物多次读取同一行数据,读到了不同的结果

幻读:一个事务多次读取同一张表,读到了不同的行数

36、Spring事务的实现方式以及隔离级别

实现方式:加上一个注解@Transactional

隔离级别:

对未提交:啥也不能解决,任由脏读发生

读已提交:解决了脏读问题

可重复读:解决了脏读、幻读(spring默认隔离级别)

串行化度:解决了脏读、虚度、幻读,但是性能差

37、spring事务的传播机制

【掌握】PROPAGATION_REQUIRED: 表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务。绝大多数情况都是用这个

【掌握】 PROPAGATION_SUPPORTS: 表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行,如果没有事务,我也不会创建。有很小一部分会用到这个传播行为

剩下五个了解,几乎用不到。

PROPAGATION_MANDATORY 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常

PROPAGATION_REQUIRED_NEW 表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当 前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager

PROPAGATION_NOT_SUPPORTED 表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager

PROPAGATION_NEVER 表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常

PROPAGATION_NESTED 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务

38、Spring事务什么时候失效

数据库引擎不支持事务

@transactional加在private方法上(@Transactional只能加在public方法上,如果需要在private方法中加入事务,可以使用Aspect配transactionManager使用.)

异常被catch

异常类型错误

没有被Spring管理

没有配置TransactionManager

39、什么是bean的自动装配,有哪些方式

开启自动装配,只需要在xml配置文件<bean>中定义"autowire"属性。

autowire属性有五种装配方式:

no-这是默认设置,表示没有自动装配

byName-根据bean属性名称进行自动装配。

byType-根据bean的类型进行自动装配

contructor 类似byType,不过应用于构造器的参数,如果一个bean与构造器参数的类型相同,则自动装配,否则导致异常

autodetect:如果有默认构造器就是用contructor进行装配,否则使用byType进行自动装配

40、Spring boot、SpringMVC和Spring有什么区别

SpringFrame SpringFramework 最重要的特征是依赖注入。所有 SpringModules 不是依赖注入就是 IOC 控制反转。 当我们恰当的使用 DI 或者是 IOC 的时候,我们可以开发松耦合应用。松耦合应用的单元测试可以很容易的进行。

SpringMVC Spring MVC 提供了一种分离式的方法来开发 Web 应用。通过运用像 DispatcherServelet,MoudlAndView 和 ViewResolver 等一些简单的概念,开发 Web 应用将会变的非常简单。

SpringBoot Spring 和 SpringMVC 的问题在于需要配置大量的参数。

41、SpringMVC工作流程

用户发送请求到前端控制器 DispatcherServlet

dispatcherServlet 收到请求调用HandlerMapping处理映射器

HandlerMapping找到具体的处理器,生成处理器及拦截器一并返回给DispatcherServlet

DispatcherServlet 调用HandlerAdapter处理适配器

HandlerAdpter经过适配器调用具体的controller

Controller执行完成返回ModelAndView

HandlerAdapter将controller执行结果返回给dispatcherServlet

DispatcherServlet将ModelAndView传给视图解析器ViewReslover

ViewReslover解析后返回具体的视图view

前端控制器根据视图进行视图渲染

最后DispatcherServlet响应给客户

42、spring中的九大主键

HandlerMapping:处理映射器

HandelrAdapter:适配器

HandlerExeptionReslover:捕获异常,交给render方法进行渲染

ViewResplver:视图解析器

RequestToViewNameTranslator:根据ViewNma查钊View

LocaleResolver:国际化

ThemeRsolver:解析主题

MultiparReslover:文件上传

FlashMapManager:用来管理Flash,主要用在重定向传递参数

43、springboot自动配置原理

Spring spi 自动配置由各个starter提供,使用@Configuration+@Bean定义配置类,放到META-INF/spring。factories下 使用spring spi烧苗平META-INF/搜spring.factories下的配置类 使用@import导入自动配置类 @Configuration是一个符合注解,复合注解里边有一个@EnableAutoConfiguration,这个注解的作用就是开启自动装配。

44、如何理解springboot中的Starter

使用spring+SpringMVC,如果需要映入mybatis等框架,需要到xml中定义mybatis需要的bean

starter就是定义一个starter的jar包,写一个@Configuration配置类,将这些bean定义在里面,然后在starter包的META-IN/spring。factories中写入该配置类,springboot会按照约定来加载该配置类

开发人员只需要将相应的starter包依赖拖进应用,进行相应的属性配置,就可以直接进行代码开发,使用对应的功能。

45、什么事嵌入式服务器?为什么要使用嵌入式服务器

节省了下载安装tomcat,应用也不需要再打war包,然后放到webapp目录下运行

只需要安装了java虚拟机,就可以直接在上面部署应用程序了

springboot已经内置了tomcat.jar,运行main方法时会去启动tomcat,并利用tomcat的spi机制加载SpringMVC

46、mybatis的优缺点

基于SQL语句编程,解除sql与程序代码的耦合,并重用

与JDBC相比,消除了大量冗余代码

很好的与各种数据库兼容

能够与spring很好地集成

缺点:

sql语句的编写工作量大,对开发人员编写sql语句的功底有一定要求

sql语句因爱数据库,移植性差,不能随意更换数据库

47、#{}和${}的区别

{}:预编译,占位符是以拼接字符连接,提高安全性

${}:字符串替换,是拼接符,容易造成sql注入

48、简述Mybatis的插件运行原理,如何编写一个插件

Mybatis 仅可以编写针对 ParameterHandler、ResultSetHandler、StatementHandler、Executor 这 4 种接口的插件,Mybatis 使用 JDK 的动态代{过}{滤}理,为需要拦截的接口生成代{过}{滤}理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是 InvocationHandler 的 invoke()方法,当然,只会拦截那些你指定需要拦截的方法。 编写插件:实现 Mybatis 的 Interceptor 接口并复写 intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。

49、索引的基本原理

索引用来快速的寻找那些具有特定值的记录,如果没有索引,一般来说执行查询时遍历整张表

索引的原理就是把无序的数据编程有序的查询

50、java创建对象的几种方式

有4种显式地创建对象的方式: 1.用new语句创建对象,这是最常用的创建对象的方式。 2.运用反射手段,调用Java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。 3.调用对象的clone()方法。 4.运用反序列化手段,调用java.io.ObjectInputStream对象的readObject()方法.

52、加载ApplicationContext.xml文件的方式有哪些?

ClassPathXmlApplicationContext 对象加载

从classpath路径下面去加载配置文件

FileSystemXmlApplicationContext

从系统磁盘中加载配置文件

52、Spring创建对象

有参构造:就是需要参数才能够创建对象

无参构造:参构造就是利用反射类的newinstance方法创建对象。

静态工厂:创建一个工厂类,直接类名.方法调用

非静态工厂:先把工厂实例创建,因为非静态方法只能被实例调用

53、依赖注入

set注入

构造函数注入

注解注入:@Resource和@Autowired注解注入

54、AOP底层原理

就是动态代{过}{滤}理

JDK动态代{过}{滤}理和CGLIB动态代{过}{滤}理:

JDK动态代{过}{滤}理:首先是利用反射来实现的,它是面向接口的,也就是被代{过}{滤}理的目标类需要实现接口才可以被代{过}{滤}理,反射的缺点就是性能不高。

重要方法

public static Object newProxyInstance(ClassLoader loader,

Class<?>[] interfaces,

InvocationHandler h)

有三个参数,类加载器,接口反射类的数组,InvocationHandler

代{过}{滤}理类要实现的接口就是InvocationHandler。

55、全局异常捕获

@ControllerAdvice:如果有页面返回,那么就是用@ControllerAdvice

@RestControllerAdvice:如果只是返回JSON数据,那么就用@RestControllerAdvice

56、实现拦截器的步骤

实现HandlerInterceptor接口,覆写其三个方法,并且交给Spring容器管理,也就是加上@Component注解。其中三个方法的名称:

boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)//在控制器方法请求之前执行

void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView)//在控制器方法执行完成之后执行。

void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex)//视图渲染之后执行

57、SpringMVC和Spring容器的关系

在Spring整体框架的核心概念中,容器是核心思想,就是用来管理Bean的整个生命周期的。Spring和SpringMVC的容器存在父子关系,即Spring是父容器,SpringMVC是其子容器,子容器可以访问父容器的对象,父容器不能访问子容器的类。**例如:Controller中能调用Service,但是Service不能调用Controller。Spring父容器负责所有其他非@Controller注解的Bean的注册,而SpringMVC只负责@Controller注解,处理器映射、视图解析器的Bean的注册,使得他们各负其责、明确边界。配置到子容器的只能是子容器自己访问,配置到父容器的,父子容器都能访问。

58、mysql锁的类型有哪些

基于所得属性分类:共享锁,排它锁

基于锁的粒度分类:行级锁,表级锁,页级锁,间歇锁,临建锁

59、事务的特性和隔离级别

事务基本特性ACID分别是:

原子性:要么全部成功,要么要不失败

一致性:事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少

隔离性:一个事务的修改在最终提交前对其他事物是不可见的

持久性:一个事务一旦提交,事物的操作便永久性的保存在DB中。即使此时再执行回滚操作也不能撤消所做的更改

Redis

60、Rides中的RDB和AOF机制

RDB:(快照持久化,默认开启),Redis创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本(Redis主从结构,主要用来提高Redis性能),还可以将快照留在原地以便重启服务器的时候使用。

AOF:AOF持久化 的实时性更好,默认没有开启,开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof。

61、redis 内存淘汰机制

redis 提供 6种数据淘汰策略:

volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)

allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!

62、redis为什么是单进程单线程

因为单线程代码清晰,线程安全,不用去考虑各种锁

63、为什么redis需要把所有数据放到内存中?

redis为了达到最快的读写速度,将数据都读到内存中,并通过异步的方式将 数据写入磁盘;所以redis具有快速和数据持久化的特征;

64、redis支持的数据类型

string值是字符串类型

list 值是一个集合

set 值是一个无重复数据的集合

sorted set 值是一个无重复数据并且排序的集合

hash 值可以理解是一个对象;

65、是否使用过Redis集群,集群的原理是什么?

Redis Sentinal着眼于高可用,在master宕机时会自动将slave提升为master继续提供服务。哨兵 Redis Cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。

66、使用redis有哪些好处?

(1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1) (2) 支持丰富数据类型,支持``string``,list,``set``,sorted ``set``,hash (3) 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行 (4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

67、redis的回收策略

最近最少使用的数据淘汰,将要过期的数据淘汰,已经过期的数据淘汰

68、redis 设置过期时间

我们 set key 的时候,都可以给一个 expire time,就是过期时间,通过过期时间我们可以指定这个 key 可以存活的时间。

定期删除:redis默认是每隔 100ms 就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。注意这里是随机抽取的。为什么要随机呢?你想一想假如 redis 存了几十万个 key ,每隔100ms就遍历所有的设置过期时间的 key 的话,就会给 CPU 带来很大的负载!

惰性删除 :定期删除可能会导致很多过期 key 到了时间并没有被删除掉。所以就有了惰性删除。假如你的过期 key,靠定期删除没有被删除掉,还停留在内存里,除非你的系统去查一下那个 key,才会被redis给删除掉。这就是所谓的惰性删除,也是够懒的哈!

69、缓存雪崩、缓存穿透、缓存击穿

缓存雪崩:缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。

解决办法

事前:尽量保证整个 redis 集群的高可用性,发现机器宕机尽快补上。选择合适的内存淘汰策略。

事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL崩掉

事后:利用 redis 持久化机制保存的数据尽快恢复缓存

缓存穿透:一般是黑客故意去请求缓存中不存在的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。

解决办法:

有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法(我们采用的就是这种),如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

缓存击穿:缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力

解决办法

设置热点数据永远不过期。

加互斥锁,互斥锁参考代码如下:

public static String getData(String key) throws InterruptedException{
//从缓存读取数据
String result = getDataFromRedis(key);
//缓存中不存在数据
if (result == nul1){
//去获取锁,获取成功,去数据库取数据
if (reenLock.tryLock()){
//从数据库获取数据
result = getDataFromMysql(key);
//更新缓存数据
if(result != null){
setDataToCache(key,result);
}
//释放锁
rennLock.unlock();
}
//获取锁失败
else{
//暂停100ms再重新去获取数据
Thread.sleeo(100);
result = getData(key);
}
}
return result;
}

说明:

1)缓存中有数据,直接走上述代码13行后就返回结果了

2)缓存中没有数据,第1个进入的线程,获取锁并从数据库去取数据,没释放锁之前,其他并行进入的线程会等待100ms,再重新去缓存取数据。这样就防止都去数据库重复取数据,重复往缓存中更新数据情况出现。 3)当然这是简化处理,理论上如果能根据key值加锁就更好了,就是线程A从数据库取key1的数据并不妨碍线程B取key2的数据,上面代码明显做不到这点

70、Redis事务

Redis 通过 MULTI、EXEC、WATCH 等命令来实现事务(transaction)功能。在传统的关系式数据库中,常常用 ACID 性质来检验事务功能的可靠性和安全性。在 Redis 中,事务总是具有原子性(Atomicity)、一致性(Consistency)和隔离性(Isolation),并且当 Redis 运行在某种特定的持久化模式下时,事务也具有持久性(Durability)。

71、Shiro

登录流程: 首先前端用户传入用户名个密码,后台创建UsernamePasswordToken,将用户名和密码封装到这个对象中,然后用SecuirityUtil.getSubject()获得Subject对象,Subject对象就是shiro用来登录的对象,调用login(token)方法来执行登录操作,就会进入UserRealm中的dogetAuthcation认证方法,对login方法进行异常捕获,如果抛出异常,则登录失败,如果没有抛出异常,doGetAuthcation返回一个简单的登录信息,表示用户登录成功。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值