大家好,又见面了,我是你们的朋友全栈君。
java面试题现在走向了八股文的路子,基础知识点和高频知识点还是比较多的,但是牢牢背下来又显得死板,所以还是需要大家通过日常的积累和沉淀才能牢牢把握住,知识就是财富。加油吧。。。
Java基础
1.HashMap的源码,实现原理,JDK8中对HashMap做了怎样的优化。
2.HaspMap扩容是怎样扩容的,为什么都是2的N次幂的大小。
3.HashMap,HashTable,ConcurrentHashMap的区别。
点击查看
4.极高并发下HashTable和ConcurrentHashMap哪个性能更好,为什么,如何实现的。
- HashTable使用一把锁处理并发问题,当有多个线程访问时,需要多个线程竞争一把锁,导致阻塞
- ConcurrentHashMap则使用分段,相当于把一个HashMap分成多个,然后每个部分分配一把锁,这样就可以支持多线程访问
5.HashMap在高并发下如果没有处理线程安全会有怎样的安全隐患,具体表现是什么。
-
多线程put时可能会导致get无限循环,具体表现为CPU使用率100%;
原因:在向HashMap put元素时,会检查HashMap的容量是否足够,如果不足,则会新建一个比原来容量大两倍的Hash表,然后把数组从老的Hash表中迁移到新的Hash表中,迁移的过程就是一个rehash()的过程,多个线程同时操作就有可能会形成循环链表,所以在使用get()时,就会出现Infinite Loop的情况
-
多线程put时可能导致元素丢失
原因:当多个线程同时执行addEntry(hash,key ,value,i)时,如果产生哈希碰撞,导致两个线程得到同样的bucketIndex去存储,就可能会发生元素覆盖丢失的情况
6.java中四种修饰符的限制范围。
访问权限 | 本类 | 本包 | 不同包子类 | 不同包非子类 |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | |
default | √ | √ | ||
private | √ |
7.Object类中的方法。
-
1),构造函数
-
2),hashCode和equale函数用来判断对象是否相同,
equale()用于确认两个对象是否相同。hashCode()用于获取对象的哈希值,这个值的作用是检索,具体的作用可以参考这里。哈希值相同的对象不一定equale(),equale()返回true的两个对象一定相同。
-
3),wait(),wait(long),wait(long,int),notify(),notifyAll()
这几个函数体现的是Java的多线程机制
在使用的时候要求在synchronize语句中使用
wait()用于让当前线程失去操作权限,当前线程进入等待序列
notify()用于随机通知一个持有对象的锁的线程获取操作权限
notifyAll()用于通知所有持有对象的锁的线程获取操作权限
wait(long) 和wait(long,int)用于设定下一次获取锁的距离当前释放锁的时间间隔 -
4),toString()和getClass,
toString()返回一个String对象,用来标识自己
getClass()返回一个Class对象,如果打印出来会发现结果是如下格式class package.name.xxx
因为返回的是一个class对象,后面可以跟class类的方法。用的是谁的构造函数,那么getClass返回的就是谁的类型。
getClass()经常用于java反射机制 -
5),clone()
clone()函数的用途是用来另存一个当前存在的对象。
-
6),finalize()用于在垃圾回收
这个函数在进行垃圾回收的时候会用到,匿名对象回收之前会调用到,具体的例子如下所示
package com.ziyear; public class Test { public static void main(String[] args) { new Test(); System.gc(); } @Override protected void finalize() throws Throwable { System.out.println("This is Test finalize()"); } }
输出:
This is Test finalize()
8.接口和抽象类的区别,注意JDK8的接口可以有实现。
参数 | 抽象类 | 接口 |
---|---|---|
默认的方法实现 | 它可以有默认的方法实现 | 接口完全是抽象的,他不存在方法的实现,1.8后它可以有默认的方法实现 |
实现 | 子类使用extends关键字来继承抽象类,如果子类不是抽象类的话,他需要提供抽象类中所有声明的方法的实现 | 子类使用关键字implements来实现接口,他需要提供接口中所有生命的方法的实现,1.8排除默认实现的方法 |
构造器 | 抽象类中可以有构造器 | 接口中不能有构造器 |
与正常java类的区别 | 除了你不能实例化抽象类外,它和普通java类没有任何区别 | 接口是完全不同的类型 |
访问修饰符 | 抽象方法可以有pubic,protected这些修饰符 | 接口方法默认修饰符是public,你不可以使用其他修饰符,1.8增加default修饰默认实现 |
main方法 | 抽象类中可以有main方法并可以运行它 | 接口中没有main方法,因此我们不能运行它 |
多继承 | 抽象类可以继承一个类实现多个接口 | 接口只能继承一个或多个接口 |
速度 | 它比接口速度要快 | 接口速度稍慢,因为它需要时间去寻找在类中实现的方法 |
添加新方法 | 如果你往抽象类中添加新方法,你可以给他提供默认的实现,因此你不需要改变你现在的代码 | 如果你往接口中添加新的方法,你必须改变实现接口的实现类,1.8后如果在接口中添加默认实现的方法则不需要. |
变量 | 和普通java类相同 | 接口中只能有static、final变量,不能有其他变量。 |
9.动态代理的两种方式,以及区别。
-
若目标对象实现了若干接口,使用JDK的java.lang.reflect.Proxy类代理。
利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
优点:因为有接口,所以使系统更加松耦合
缺点:为每一个目标类创建接口 -
若目标对象没有实现任何接口,使用CGLIB库生成目标对象的子类。
利用ASM(开源的Java字节码编辑库,操作字节码)开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。
优点:因为代理类与目标类是继承关系,所以不需要有接口的存在。
缺点:因为没有使用接口,所以系统的耦合性没有使用JDK的动态代理好。 -
总结:
JDK代理只能对实现接口的类生成代理,CGlib是针对类实现代理,对指定的类生成一个子类,并覆盖其中的方法,这种通过继承类的实现方式,不能代理final修饰的类。
JDK代理使用的是反射机制实现aop的动态代理,CGLIB代理使用字节码处理框架asm,通过修改字节码生成子类。所以jdk动态代理的方式创建代理对象效率较高,执行效率较低,cglib创建效率较低,执行效率高;
JDK动态代理机制是委托机制,具体说动态实现接口类,在动态生成的实现类里面委托hanlder去调用原始实现类方法,CGLIB则使用的继承机制,具体说被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。
10.Java序列化的方式。
- Json序列化
- FastJson序列化
- ProtoBuff序列化
几种Java序列化方式的实现
深入学习java序列化
11.传值和传引用的区别,Java是怎么样的,有没有传值引用。
传值还是传引用?
Java中没有引用传递,Java所有操作都是传值操作!都是传值操作!都是传值操作!重要的事情说三遍。
12.一个ArrayList在循环过程中删除,会不会出问题,为什么。
一个ArrayList在循环过程中删除,会不会出问题,为什么?
for循环遍历,存在漏删
foreach循环删除,抛出异常ConcurrentModificationException
foreach循环删除集合中倒数第二个对象时不会发生ConcurrentModificationException异常
13.@transactional注解在什么情况下会失效,为什么。
@transactional注解在什么情况下会失效,为什么。
默认情况下,Spring会对unchecked异常进行事务回滚
类似的还有norollbackFor,自定义不回滚的异常 等;
数据结构和算法
1.B+树。
2.快速排序,堆排序,插入排序(其实八大排序算法都应该了解)
3.一致性Hash算法,一致性Hash算法的应用。
对一致性Hash算法,Java代码实现的深入研究
白话解析:一致性哈希算法
JVM
1.JVM的内存结构。
全面理解Java内存模型(JMM)及volatile关键字
2.JVM方法栈的工作过程,方法栈和本地方法栈有什么区别。
-
虚拟机栈(方法栈)
与程序计数器一样,Java虚拟机栈也是线程私有的,它的生命周期与线程相同。虚拟机描述的是Java方法执行的内存模型:
每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应这一个栈帧在虚拟机栈中入栈到出栈的过程。
局部变量表存放了编译器可知的各种基本数据类型,对象引用类型,它不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置和returnAddress类型(指向了同一条字节码指令的地址)。
其中64位长度的long和double类型的数据会占用2个局部变量空间,其余的数据类型只占用一个。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配出多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变脸表的大小。
在Java虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展(当前大部分的Java虚拟机都可以动态扩展,只不过Java虚拟机规范中也允许固定长度的虚拟机栈),如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。 -
本地方法栈
本地方法栈和虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈是非虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机执行Native方法服务的。在虚拟机规范中对本地方法栈中方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机直接将本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法栈区域会抛出StackOverflowError异常和OutOfMemoryError异常。
3.JVM的栈中引用如何和堆中的对象产生关联。
对象生成时,产生的首地址存储在栈中,这样两者就关联起来了。
4.可以了解一下逃逸分析技术。
5.GC的常见算法,CMS以及G1的垃圾回收过程,CMS的各个阶段哪两个是Stop the world的,CMS会不会产生碎片,G1的优势。
常见GC算法,CMS以及G1的垃圾回收过程,CMS的各个阶段哪两个是Stop the world的,CMS会不会产生碎片,G1的优势。
为什么CMS两次标记时要 stop the world
详解 JVM Garbage First(G1) 垃圾收集器
CMS-initial-mark 初始标记和CMS-remark 重新标记会Stop the world
由于CMS采用标记清除算法,默认并不使用标记整理算法,可能会产生很多碎片,因此,这些碎片无法完成大对象向老年带转移,因此需要进行CMS在老年带的Full GC来合并碎片。
- G1是一款面向服务端应用的垃圾收集器。G1具备如下特点:
1、并行于并发:G1能充分利用CPU、多核环境下的硬件优势,使用多个CPU(CPU或者CPU核心)来缩短stop-The-World停顿时间。部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让java程序继续执行。
2、分代收集:虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但是还是保留了分代的概念。它能够采用不同的方式去处理新创建的对象和已经存活了一段时间,熬过多次GC的旧对象以获取更好的收集效果。
3、空间整合:与CMS的“标记–清理”算法不同,G1从整体来看是基于“标记整理”算法实现的收集器;从局部上来看是基于“复制”算法实现的。
4、可预测的停顿:这是G1相对于CMS的另一个大优势,降低停顿时间是G1和CMS共同的关注点,但G1除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,
5、G1运作步骤:
1、初始标记;2、并发标记;3、最终标记;4、筛选回收
上面几个步骤的运作过程和CMS有很多相似之处。初始标记阶段仅仅只是标记一下GC Roots能直接关联到的对象,并且修改TAMS的值,让下一个阶段用户程序并发运行时,能在正确可用的Region中创建新对象,这一阶段需要停顿线程,但是耗时很短,并发标记阶段是从GC Root开始对堆中对象进行可达性分析,找出存活的对象,这阶段时耗时较长,但可与用户程序并发执行。而最终标记阶段则是为了修正在并发标记期间因用户程序继续运作而导致标记产生变动的那一部分标记记录,虚拟机将这段时间对象变化记录在线程Remenbered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set Logs里面,最终标记阶段需要把Remembered Set Logs的数据合并到Remembered Set中,这一阶段需要停顿线程,但是可并行执行。最后在筛选回收阶段首先对各个Region的回收价值和成本进行排序,根据用户所期望的GC停顿时间来制定回收计划。
6.标记清除和标记整理算法的理解以及优缺点。
-
第一种:标记清除
它是最基础的收集算法。
原理:分为标记和清除两个阶段:首先标记出所有的需要回收的对象,在标记完成以后统一回收所有被标记的对象。
特点:(1)效率问题,标记和清除的效率都不高;(2)空间的问题,标记清除以后会产生大量不连续的空间碎片,空间碎片太多可能会导致程序运行过程需要分配较大的对象时候,无法找到足够连续内存而不得不提前触发一次垃圾收集。
地方 :适合在老年代进行垃圾回收,比如CMS收集器就是采用该算法进行回收的。 -
第二种:标记整理
原理:分为标记和整理两个阶段:首先标记出所有需要回收的对象,让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
特点:不会产生空间碎片,但是整理会花一定的时间。
地方:适合老年代进行垃圾收集,parallel Old(针对parallel scanvange gc的) gc和Serial old收集器就是采用该算法进行回收的。
7.eden survivor区的比例,为什么是这个比例,eden survivor的工作过程? JVM如何判断一个对象是否该被GC,可以视为root的都有哪几种类型? Java有没有主动触发GC的方式(没有)?Java是否可以GC直接内存。?
8.强软弱虚引用的区别以及GC对他们执行怎样的操作。
从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。
-
强引用
如果一个对象具有强引用,那么垃圾回收器绝不会回收它。哪怕内存空 间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。 -
软引用
如果一个对象只具有软引用,如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。 -
弱引用
如果一个对象只具有弱引用,垃圾回收器一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。 -
虚引用
“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。 虚引用主要用来跟踪对象被垃圾回收的活动。
9.Java类加载的过程。
10.双亲委派模型的过程以及优势。
-
双亲委派模型的实现过程:
实现双亲委派模型的代码都集中在java.lang.ClassLoader的loadClass()方法中:
首先会检查请求加载的类是否已经被加载过;
若没有被加载过:
递归调用父类加载器的loadClass();
父类加载器为空后就使用启动类加载器加载;
如果父类加载器和启动类加载器均无法加载请求,则调用自身的加载功能。 -
双亲委派模型的优点:
Java类伴随其类加载器具备了带有优先级的层次关系,确保了在各种加载环境的加载顺序。
保证了运行的安全性,防止不可信类扮演可信任的类。
11.常用的JVM调优参数。
12.dump文件的分析。
Java内存泄漏分析系列之六:JVM Heap Dump(堆转储文件)的生成和MAT的使用
JConsole
Jhat
GcViewer
IBM Heap Analyzer
多线程
1.Java实现多线程有哪几种方式。
-
继承Thread类
-
实现Runable接口
-
实现Callable接口
-
使用ExecutorService、Callable、Future实现有返回结果的线程
2.Callable和Future的了解。
Java多线程编程:Callable、Future和FutureTask浅析
3.线程池的参数有哪些,在线程池创建一个线程的过程。
4.volitile关键字的作用,原理。
5.synchronized关键字的用法,优缺点。
6.Lock接口有哪些实现类,使用场景是什么。
7.悲观锁,乐观锁,优缺点,CAS有什么缺陷,该如何解决。
8.ABC三个线程如何保证顺序执行。
9.线程的状态都有哪些。
线程的五大状态
10.sleep和wait的区别。
- 对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。
- sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。
- 在调用sleep()方法的过程中,线程不会释放对象锁。
- 而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。
11.notify和notifyall的区别。
先说两个概念:锁池和等待池
- 锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。
- 等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池中
Reference:java中的锁池和等待池
然后再来说notify和notifyAll的区别
- 如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
- 当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争
- 优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
Reference:线程间协作:wait、notify、notifyAll
综上,所谓唤醒线程,另一种解释可以说是将线程由等待池移动到锁池,notifyAll调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。而notify只会唤醒一个线程。
12.ThreadLocal的了解,实现原理。
13.Fork/Join框架介绍及实例讲解
Fork/Join框架详解
JAVA中的Fork/Join框架
Fork/Join框架及其性能介绍
运用ForkJoin多线程框架实现归并排序
14.CountDownLatch、CyclicBarrier和 Semaphore
CountDownLatch、CyclicBarrier和 Semaphore
15.AQS
Java并发之AQS详解
数据库相关
1.常见的数据库优化手段
2.索引的优缺点,什么字段上建立索引
3.数据库连接池。
4.数据库事务。
5.数据库锁。
计算机网络
1.TCP,UDP区别。
- TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
- TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
- TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
- 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
- TCP首部开销20字节;UDP的首部开销小,只有8个字节
- TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
2.三次握手,四次挥手,为什么要四次挥手。
3.长连接和短连接。
-
在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等),每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。
-
而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:
Connection:keep-alive
-
在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。
-
HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。
4.连接池适合长连接还是短连接。
我的的理解最大连接数减去最小连接数为短连接,最小连接数是长连接。
设计模式
1.观察者模式
2.代理模式
3.单例模式,有五种写法,可以参考文章单例模式的五种实现方式
4.可以考Spring中使用了哪些设计模式
分布式相关
1.分布式事务的控制。
2.分布式锁如何设计。
【分布式缓存系列】集群环境下Redis分布式锁的正确姿势
3.分布式session如何设计。
分布式集群系统下的高可用session解决方案—Session共享
Shiro集成Redis实现分布式集群Session共享
4.dubbo的组件有哪些,各有什么作用。
- Dubbo需要四大基本组件:Registry、Monitor、Provider、Consumer。
- Provider:提供者
- Consumer:消费者
- registry:注册中心(相当于中介)
- monitor:监控中心
5.dubbo是如何利用接口就可以通信的。
6.Zookeeper的负载均衡算法有哪些。
zookeeper 负载均衡 核心机制-实现原理 包含ZAB协议
缓存相关
1.Redis有哪些适合的场景?
-
(1)、会话缓存(Session Cache)
最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗?
幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件。
-
(2)、全页缓存(FPC)
除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC。
再次以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。
此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。
-
(3)、队列
Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作。
如果你快速的在Google中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用Redis创建非常好的后端工具,以满足各种队列需求。例如,Celery有一个后台就是使用Redis作为broker,你可以从这里去查看。
-
(4),排行榜/计数器
Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可:
当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行:
ZRANGE user_scores 0 10 WITHSCORES
Agora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的,你可以在这里看到。
-
(5)、发布/订阅
最后(但肯定不是最不重要的)是Redis的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用Redis的发布/订阅功能来建立聊天系统!(不,这是真的,你可以去核实)。
2.redis支持哪些数据结构。
String、List、Set、Sorted Set、hashes
3.redis是单线程的么,所有的工作都是单线程么。
是的,都是单线程
redis为什么不用多线程(不划算呗)
(1)纯内存操作;
(2)多线程仍然会有上下文切换的损耗,虽然比进程切换损耗小;
(3)采用了非阻塞I/O多路复用机制
4.使用过Redis分布式锁么,它是什么回事?
先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。
这时候对方会告诉你说你回答得不错,然后接着问如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?
这时候你要给予惊讶的反馈:唉,是喔,这个锁就永远得不到释放了。紧接着你需要抓一抓自己得脑袋,故作思考片刻,好像接下来的结果是你主动思考出来的,然后回答:我记得set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用的!对方这时会显露笑容,心里开始默念:嗯,这小子还不错。
5.redis的部署方式,主从,集群。
redis单例、主从模式、sentinel以及集群的配置方式及优缺点对比
6.redis持久化策略。
框架相关
1.SpringMVC请求流程
2.Mybatis如何找到指定的Mapper的,如何完成查询的。
mybatis如何通过接口查找对应的mapper.xml及方法执行详解
3.Quartz是如何完成定时任务的。
4.自定义注解的实现。
5.Spring使用了哪些设计模式。
6.Spring的IOC有什么优势。
6.Spring的AOP有什么优势。
7.Spring如何维护它拥有的bean。
8.常用框架整理。
SpringIOC
Other
1.JDK8的新特性,流的概念及优势,为什么有这种优势。
【读书笔记】《写给大忙人看的Java SE 8》——Java8新特性总结
Java8新特性
一些小建议
1.可以去leetcode上刷题换换思路。
2.八大排序算法一定要手敲一遍(快排,堆排尤其重要)。
3.了解一些新兴的技术。
4.面试之后面试官都会问你有没有什么问题,千万不要没问题,也别傻乎乎的问一些敏感问题。
5.了解你要面试的公司的产品及竞争产品。
无论是哪家公司,都很重视高并发高可用的技术、重视基础和JVM。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,这样会不利于自己的发挥。在面试过程中也不应该只看中薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。
最后,希望大家都能找到适合自己的公司,开开心心的撸代码。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/156795.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...