• 大量面试题


    面向对象的特征:继承、封装和多态

    继承:增加程序的重用性。比如一个学生类继承人类,人类的许多属性就不需要再次定义。

    封装:将对象属性封装起来,只暴露需要的接口给其他类使用。对类进行修改时,不改变接口声明,保证了模块之间的相对独立性。

    多态:实现多态的两个方法是覆盖和重载。许多设计模式都是利用了多态这一特性。

    final, finally, finalize 的区别

    final:用final修饰类表示该类不能继承,修饰方法表示方法不可覆盖,修饰属性表示属性不能被第二次赋值。

    finally:在异常处理时被finally包裹的操作是否捕获异常都一定会执行。

    finalize:finalize是一个方法名,在gc时可能会被调用,其调用条件为类重写了这个方法且未被调用过。

    Exception、Error、运行时异常与一般异常有何异同

    Exception和Error都继承于Throwable: Error一般与程序无关,而是java程序运行时系统的内部错误;Exception分为RuntimeException运行时异常和普通异常:运行时异常一般是程序编写错误,而普通异常与程序无关,而是其他问题例如IO导致的异常,需要用try-catch包裹。

    请写出5种常见到的runtime exception

    常见的运行时异常:

    ClassNotFoundException

    NullPointerException

    NumberFormatException

    IndexOutOfBoundsException

    ClassCastException

    int 和 Integer 有什么区别,Integer的值缓存范围

    int是基本数据类型,采用值传递方式,Integer是int的包装类型,采用引用传递方式。缓存范围为 -128~127.

    比较两个Integer大小时:

    1. 如果都是new出来的变量,则两个变量==比较结果一定为false,因为==比较的是两个变量的地址值;

    2. 如果一个是new出来的变量,一个是直接赋值,则两个变量==比较一定为false;

    3. 一个Integer和一个int比较,只要数值相等,==结果为true,因为此时Integer对象为被自动拆箱为int。

    4. 两个直接赋值的Integer比较,若值相等且在缓存范围内,==结果为true。

    包装类,装箱和拆箱

    包装类是对八大基本数据类型(byte,short,boolean,char,int,long,float,double)的包装。

    装箱是指将基本类型转换为包装类型;拆箱是指将包装类型转换为基本类型。

    以下几种情况会发生自动装箱或自动拆箱:

    1. Integer integer = 100;发生自动装箱,即Integer integer = Integer.valueOf(100);

    2. int i = integer;发生自动拆箱

    3. 遇到算数运算符,如:++,--,>>等,对包装类自动拆箱

    4. 遇到除==,!=的关系运算符,如:>,<=等,对包装类自动拆箱

    5. 遇到==,!=关系运算符,遇到数字常量或算数表达式时,对包装类型自动拆箱。

    String、StringBuilder、StringBuffer

    String:不可变类,适用于对字符串改变不频繁的场景。

    StringBuffer:线程安全,适用于对字符串改变频繁的多线程场景。

    StringBuilder:线程不安全,适用于对字符串改变频繁的单线程场景。

    重载和重写的区别

    1. 重载发生在同一个类当中,重写发生在子类和父类当中

    2. 重载必须保证方法参数不同,而重写的方法参数相同。

    抽象类和接口有什么区别

    1. 一个类只能继承一个抽象类而可以实现多个接口。

    2. 抽象类中的方法可以是抽象方法也可以是被实现的普通方法,而接口中的方法不能被实现。

    3. 一个类继承抽象类表示is-a关系,而实现一个接口表示is-like-a关系,所以关注一个类的本质时选择继承抽象类,而关注方法时去实现接口。

    4. 接口中的属性默认为static类型,而抽象类中不是。

    说说反射的用途及实现

    反射类在java.lang.reflect包里面,主要有三个用途:

    1. 通过反射创建对象
    2. 通过反射获得类中的所有属性
    3. 通过反射调用类中的方法。

    可以通过反射实现动态代理。

    其本质就是通过获取JVM内(一般在方法区)的信息获得对象信息。

    HTTP请求的GET与POST方式的区别

    Get:直接把请求参数凡在URL中,用户可见,有注入危险,有长度限制。

    Post:将请求参数放在请求体中。

    Session与Cookie区别

    Session在服务端,安全,但增加服务端压力。

    Cookie在客户端,不安全。

    MVC设计思想

    分层思想,减小程序间的耦合度。

    M:model,一般是指业务逻辑层。

    V:view(视图),一般是指jsp部分,用于对响应结果的渲染,然后展示给用户。

    C:controller(控制),一般指action控制层,用于接收客户端请求并分析请求参数然后交给业务逻辑层处理。

    equals与==的区别

    ==直接比较两个对象的地址值;equals是java方法,重写后一般用来比较两个对象里面的具体值。

    hashCode和equals方法的区别与联系

    hashCode求对象的哈希值,equals方法一般用于比较两个对象值是否相等:HashCode相等的对象equals()结果不一定为true,反之equals()结果为true的两个对象hashCode值一定相等。

    在HashMap等容器中,进行put操作时,会求对象key的hashcode值,hashCode一样的对象放在table的同一个索引中,进一步执行equals方法,若所得结果为true,则会用新的value覆盖原来的value值。

    什么是Java序列化和反序列化,如何实现Java序列化?或者请解释Serializable 接口的作用

    Java的序列化就是将java对象按照一定规则转换为二进制字节数组,反序列化就是将二进制字节数组按照规则重新转换为java对象。

    Serializable接口是一个标识接口,内部没有任何方法。实现了Serializable接口的对象可以被序列化,从而在网络中得以传输。

    Object类中常见的方法,为什么wait  notify会放在Object里边?

    常见方法:wait,notify,equals,toString,hashCode

    因为wait和notify方法由锁对象调用,而任何对象都可以作为锁对象,所以wait,notify会放在Object里边

    Java的平台无关性如何体现出来的

    其他语言如c语言之所以没有平台无关性是因为c语言会被编译为机器语言指令供硬件执行,而不同操作系统又有着不同的指令。而java虚拟机则实现了硬件到操作系统的缓冲。Java实现了一处编译,到处运行。其编译出的字节码文件可以在不同操作系统的jvm上运行。

    JDK和JRE的区别

    JRE是java程序的运行环境,包括JVM和java类库的class文件,面向java程序的使用者

    JDK 是java程序的开发工具,包括了JRE,面向Java程序的开发者。

    Java 8有哪些新特性

    https://blog.csdn.net/u014470581/article/details/54944384

    https://blog.csdn.net/54powerman/article/details/73188951

    Set和hashCode以及equals方法的联系

    HashSet底层是通过hashmap来实现的,调用add方法时实际上就是调用了hashmap的put方法。Hashmap调用put方法时会先计算key元素的哈希值来确定其索引位置,然后通过equals将key元素和该索引位置的每个节点的key元素依次比较,若结果都为false,则插入尾部,否则覆盖。

    HashMap 的工作原理及代码实现,什么时候用到红黑树(面了5家,被问4次)

    Hashmap底层原来使用数组加链表的方式实现,Jdk1.8开始,hashmap底层改为数组加链表或者红黑树,当某一索引位置的节点个数大于8时,就会采用红黑树。

    ConcurrentHashMap 的工作原理及代码实现,如何统计所有的元素个数(ConcurrentHashMap也是高频题)

    ConcurrentHashMap中有一个modCount变量,用于记录对segment中元素个数造成影响的操作个数。统计所有元素个数,就是对整个容器遍历两次,看两次modCount变量值是否相等,如果相等,统计出来的就是正确的元素个数,否则需要对整个容器进行锁定,通过同步锁定再一次统计元素个数。

    Arraylist与LinkedList默认空间是多少;

    ArrayList默认空间为10,扩容规则 newCapacity = oldCapacity+ oldCapacity/2+1

    LinkedList底层实现为链表,无初始大小,无扩容机制。

    Arraylist与LinkedList区别与各自的优势List 和 Map 区别;

    ArrayList:底层由数组实现,适合用于经常查找元素的场合,查找复杂度为O(n)

    LinkedList:底层由链表实现,适合用于经常增删元素的场合,增删复杂度为O(n)

    Map里面的元素是Key-Value的形式存在的,key不允许重复

    谈谈HashMap,哈希表解决hash冲突的方法;

    HashMap:jdk1.7使用数组+链表实现;jdk1.8改良为数组+红黑树。

    哈希表解决hash冲突:

    1. 开放地址法
    2. 链表法
    3. 二次哈希法

    Java Collections和Arrays的sort方法默认的排序方法是什么;

    https://blog.csdn.net/yangzhongblog/article/details/8184707

    JDK1.7以前采用归并排序,JDK1.7及以后使用TimeSort

    引用计数法与GC Root可达性分析法区别;

    引用计数法:计算对象被引用的次数,次数等于0时回收,当出现相互引用时,会出现无法回收导致内存泄漏问题。

    GC Root可达性分析:分析对象到GC Root是否有一条可达的路径,如果没有则对他进行回收

    可作为GC Root的对象有:

    1. 虚拟机栈中引用的对象
    2. 方法区中的类静态属性引用的对象
    3. 方法区中常量引用的对象
    4. Native方法中引用的对象

    浅拷贝和深拷贝的区别;

    浅拷贝:拷贝对象的引用

    深拷贝:拷贝对象的值,深拷贝之后的两个对象无引用关联

    如何实现深拷贝:实现Cloneable接口,重写Object的clone()方法。重写clone方法时,如果类中成员变量都是基本类型,则调用父类的clone()方法返回即可,如果存在引用类型则需要对该引用类型成员变量调用其clone()方法。

    String s="abc"和String s=new String("abc")区别;

    String s = “abc”:在栈中开辟一个空间存放引用s,在常量池中寻找“abc”常量,如果有,s就直接指向这个常量,如果没有,则在常量池中创建一个,然后s指向这个常量。

    String s=new String("abc"):在栈中开辟一个空间存放引用s,在堆中开辟一个新的空间,存放一个新建的对象“abc”,s指向这个堆中的对象。第一次执行这句话,虚拟机中新创建了两个“abc”一个在堆中,一个在方法区中。

    toString()方法什么情况下需要重写;

    object的toString()方法是返回了类名+@+对象16进制的哈希值,如果对象需要输出自己定制的格式就需要重写toString()方法。

    判断对象相等时,什么情况下只需要重写 equals(),什么情况下需要重写 equals(),hashcode()?

    放在HashMap、HashSet等容器中的对象需要重写hashcode方法,因为他们执行put方法时需要先根据对象的hashcode值决定对象要放入的数组位置,然后才执行equals方法判断其是否相等。

    Set内存放的元素为什么不可以重复,内部是如何保证和实现的?

    如何实现:set内部依靠map来实现,对set的操作实际上是对map的key进行操作,唯一性通过Hashcode+equals实现。

    如何保证分布式缓存的一致性(分布式缓存一致性hash算法)?分布式session实现?

    一致性hash算法:构造一个长度为232的整数环,将机器节点分布在圆环上,处于圆环上的数据被顺时针最近的机器管理。这样增删机器节点不会造成过多的数据无法命中问题。

    分布式session实现:使用redis模拟session信息。Redis随机生成session_id作为cookie信息返回,之后用户携带的cookie信息就记录了用户的状态。

    说一下TreeMap的实现原理?

    TreeMap的实现就是红黑树的实现,放入TreeMap的类需要继承Comparable类,TreeMap通过Comparable的compareTo方法的返回值来确定对象的位置,如果该方法返回了0,则判定新对象和原来的对象相等,会用新的value覆盖原来的value。

    红黑树的性质?红黑树遍历方式有哪些?如果key冲突如何解决?setColor()方法在什么时候用?什么时候会进行旋转和颜色转换?

    性质:

    1. 节点为黑色或者红色
    2. 根节点为黑色
    3. 红色节点的子节点不能为红色
    4. 叶子节点(Nil节点)为黑色
    5. 从根节点到叶子节点路径上的黑色节点一样多

    Key冲突:用新的value覆盖旧的value

    setColor方法:要将刚插入树的节点设置为红色

    如果插入节点的父节点为红色,则将插入节点作为当前节点并分情况进行下面的操作:

    1. 如果当前节点的叔节点为红色,则将父节点和叔节点同时置为黑色,祖父节点涂为红色,且将当前节点的祖父节点作为当前节点,判断条件进入步骤一或二或三。
    2. 如果当前节点的叔节点为黑色且当前节点为右子节点,以当前节点的父节点作为当前节点并以当前节点作为支点进行左旋,判断条件进入步骤一或二或三。
    3. 如果当前节点的叔节点为黑色且当前节点为左子节点,将其父节点设为黑色,祖父节点设为红色,以祖父节点为支点进行右旋,判断条件进入步骤一或二或三。

    反射的作用与实现原理;

    通过Class对象获得class的信息。在运行状态中,对于任何一个类,都能知道这个类的所有属性和方法;对于任何一个对象,都能调用这个对象的所有属性和方法。

    作用:动态获取类的属性和方法,动态调用对象的属性和方法

    实现原理:类加载时虚拟机读入class的二进制字节流,将其解析为Class对象,存入方法区。程序运行时,只要获得这个Class对象,就能知道这个类的所有属性和方法。

    Java中的回调机制;

    http://www.php.cn/java-article-355640.html

    一个类A调用另一个类B的方法,给被调用类的方法中传入一个A对象,在被调用方法中完成自己的处理逻辑后调用传入A对象的方法,这就完成了一次回调。

    设计模式原则

    https://blog.csdn.net/zhengzhb/article/details/7296944 

    JMM里边的原子性、可见性、有序性是如何体现出来的,JMM中内存屏障是什么意思。

    原子性:原子操作要么都成功要么都失败,JMM里面通过锁来保证原子性

    可见性:线程对于一个变量的修改能被其他线程看到,JMM的volatile变量具有可见性——一个volatile变量的读总能看到其他线程对这个volatile变量最后的写。

    有序性:happens-before规则来保证

    内存屏障:用来阻止语句重排序。

    线程和进程的概念、并行和并发的概念

    进程是资源分配的最小单位,它拥有独立的地址空间,进程之间相互独立。

    线程是cpu调度的最小单位,它与同一个进程内的其他线程共享一个地址空间。

    并发是指两件及以上的事件在同一时间间隔内同时发生,但在同一时刻只有一件事在发生;而并发是指同一时刻有两件及以上的事情在发生。

    创建线程的方式及实现

    继承Thread、实现Runable

    ArrayList和LinkList的删除一个元素的时间复杂度;

    ArrayList是O(N),LinkList是O(1)

    CopyOnWriteArrayList是什么;

    写时复制的容器:在往容器中添加元素时,将容器复制一份出来再进行添加,这样不会影响其他线程的读过程,做到了读写分离。适用于读多写少的场景。

    序列化和反序列化底层如何实现的

    ObjectOutputStream 、ObjectInputStream、 readObject 、writeObject

    调用ObjectOutputStream 的wirteObject(Object obj)方法时,只有实现了序列化接口的obj对象,被写入文件,否则会报错,写入文件时会将serialVersionUID写入文件,作为反序列化时判断是否是同一个类的标准。

    反序列化时,调用ObjectInputStream的readObject ()方法,反序列化时系统会去检测文件中的serialVersionUID,判断它是否与当前类的serialVersionUID一致,如果一致就说明序列化类的版本与当前类版本是一样的,可以反序列化成功,否则失败。

    如何调试多线程的程序;

    多线程调试的时候,只有断点所在行的线程会处于suspend状态,其他线程都会处于run的状态,通过给其他线程设置睡眠时间模拟调试状态。

    一个线程连着调用start两次会出现什么情况?

    由于状态只有就绪、阻塞、执行,状态是无法由执行转化为执行的,所以会报不合法的状态!IllegalThreadStateException

    wait方法能不能被重写?能不能被中断;

    wait是final类型的,不可以被重写,不仅如此,notify和notifyall都是final类型的。

    可以被中断,调用线程的interrupt方法即可。

    重入锁的概念,重入锁为什么可以防止死锁

    重入锁:被一个线程持有的锁可再次被这个线程获得。

    考虑一个场景,子类的同步方法调用父类的同步方法:两个方法的锁对象都是子类的对象(this),这样调用的时候由于可重入就不会发生死锁。但不能防止所有的死锁,比如A线程持有锁A请求锁B,B线程持有锁B请求锁A。

    volatile 实现原理

    禁止指令重排:禁止volatile写与前面的任何读写重排序;禁止volatile读与后面的任何读写重排序;静止volatile写与后面的volatile读重排序。

    刷新内存:在某个线程写一个volatile变量时,JMM会把该线程的所有变量刷新到主内存;在某个线程读一个volatile变量时JMM会吧该线程的所有变量置为无效,必须从主内存读取。

    synchronized 实现原理

    Synchronized包括同步方法和同步代码块,成员同步方法的锁对象是this即当前对象本身,静态同步方法的锁是类。

    每个锁对象都有一个对象监视器,进入临界区之前,监视器会判断当前锁是否已经被其他线程占有,若当前锁对象没有被其他线程占有(位被占有或者被当前线程占有),则进入临界区,并将锁对象的状态值加1,否则,当前线程转化为同步阻塞状态,等待其他线程释放该锁对象;退出临界区之前,监视器会将当前锁对象状态值减1,并判断其是否为0,若为0,则释放当前锁并通知同步等待池。

    synchronized 与 lock 的区别

    Synchronized是java关键字,lock是一个类。

    Lock可以实现类有许多获得锁信息的方法,获得锁的时候可设置公平/非公平锁,可中断等。

    最重要的一点区别是,synchronized是悲观锁,而lock是乐观锁。

    AQS同步队列

    是用来构建锁或者其他同步组件的基础框架。内部使用一个int来记录队列的状态值,并通过修改和获取这个状态值来表明获得/释放锁是否成功。内部还维护着一个队列,用来存放处于同步等待的线程。

    CAS无锁的概念、乐观锁和悲观锁,乐观锁的业务场景及实现方式

    乐观锁和悲观锁是两种概念上的锁:

    乐观锁:每次取一个数据进行操作之前假设过程中不会有其他线程修改     这个数据,而是等操作完了之后才将原值和期望原值进行对比。CAS是一个实现乐观锁的方式。适用于竞争不高的多线程环境。

    悲观锁:每次取一个数据进行操作之前都假设过程中会有其他线程修改     这个数据,所以要在操作之前锁定这个数据,不让其他线程访问。     Synchronized是实现悲观锁的。适用于竞争激烈的多线程环境。

    常见的原子操作类

    AtomicInteger、AtomicLong、AtomicBoolean

    AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray、AtomicReference、AtomicIntegerFieldUpdater

    什么是ABA问题,出现ABA问题JDK是如何解决的

    ABA问题是CAS操作的一个问题,CAS操作是通过比较特定内存位置的值和预期原值相比较,如果相等则说明操作过程中该内存位置的值没有被其他线程修改,就将该内存位置的值更新为计算所得新值。否则,循环这个操作。而ABA问题就是比如该内存位置原值为A,被别的线程修改了两次(A-B-A),比较发现满足“特定内存位置的值和预期原值相等”条件。但实际上该值已经被其他线程修改了。JDK通过增加版本号方式解决该问题,(A1-B2-A3,A1!=A3)

    Java 8并法包下常见的并发类

    并发包由3个包组成,分别是:

    java.util.concurrent(前面讲的并发工具类、线程池、并发容器-concurrentHashMap、),java.util.concurrent.automic(原子操作类),java.util.concurrent.locks(各种锁)

    偏向锁、轻量级锁、重量级锁、自旋锁的概念

    偏向锁:从始至终最多只能被一个线程占有,偏向于第一个访问锁的线程。所对象的对象头锁标志为01.

    轻量级锁:自旋锁和volatile锁都是一种轻量级锁,不阻塞线程。

    重量级锁:synchronized锁

    自旋锁:在竞争不激烈的多线程环境中,使用自旋锁自旋获得锁对象,可以减少线程挂起和恢复的时间。

    可参考:《Java多线程编程核心技术

    JVM运行时内存区域划分

    程序计数器:线程私有,记录当前栈帧执行到哪一条指令

    Java虚拟机栈、native栈

    方法区、堆

    内存溢出OOM和堆栈溢出SOE的示例及原因、如何排查与解决

    OOM:Out Of Memory

    方法区:一般发生在方法区的永久代,由于使用了太多的第三方jar包,     导致加载太多类从而永久代内存溢出

    堆:检查是否有内存泄露,如果没有检查堆内存是否可以调大以及检查     程序是否创建过多不合适的大对象。

    栈:-Xss设置过大而总的栈内存有限导致无法创建更多线程,只发生在     多线程情况下。

    SOE:StackOverflowError

    栈:-Xss设置太小(栈内定义了太多变量,递归深度太深)

    如何判断对象是否可以回收或存活

    1. 引用计数法
    2. 可达性分析(JVM使用):分析对象是否可达(是否在GC root引用链上),若可达则不做处理;若不可达且未被标记过则将其放入等待回收队列,稍后会有Finalizer线程检查其finalize方法是否被重写且未被调用过,若不是则直接回收,若是,则调用其finalize方法。

    常见的GC回收算法及其含义

    复制算法:在新生代使用,JVM将新生代分为eden+2个survivor,使用Eden和一个survivor,另一个survivor存放回收后依然存活的对象。

    标记-清除算法:在老年代使用,将要回收的对象标记起来,然后统一清除。

    标记-整理算法:在老年代使用,将要回收的对象标记起来,然后让仍然存活的对象往一个方向移动,最后将标记的对象回收。

    常见的JVM性能监控和故障处理工具类:jps、jstat、jmap、jinfo、jconsole等

    JVM性能调优

    https://blog.csdn.net/snow_7/article/details/52291979

    类加载器、双亲委派模型、一个类的生命周期、类是如何加载到JVM中的

    双亲委派模型:当一个类收到加载类请求时,将这个请求委托给父类执行,直到委托给顶层父类,然后该类尝试执行请求,若加载类失败,则将该请求重新返还给子类,一直到原来收到加载请求的类调用findclass方法加载。

    类加载的过程:加载、验证、准备、解析、初始化

    加载:通过类加载器根据提供的类全限定名寻找指定的二进制字节流,将二进制字节流加载到JVM的方法区中,并转换为一个class对象实例。

    链接:将二进制字节流合并到JVM的运行时状态

    验证:验证数据信息是否符合规范

    准备:将类中的静态对象初始化为默认值(static final 例外,在此阶段就会给其赋值为实际值)

    解析:

    初始化:按照父类静态变量,父类静态块,子类静态变量,子类静态块,父类成员变量,父类构造块,父类构造方法,子类成员变量,子类构造块,子类构造方法的顺序执行初始化。

    强引用、软引用、弱引用、虚引用

    强引用:在程序中普遍存在的类似于 A a = new A()这样的引用

    软引用:如果虚拟机内存不足,就会被gc回收的引用

    弱引用:无论虚拟机内存是否充足,只要发动了gc就会被回收

    虚引用:相当于没有引用,只是为了在被回收时收到一个系统通知。

    设计模式的的六大原则及其含义

    单一职责原则:一个类只负责一个职责。

    里氏替换原则:通过子类继承父类对一个程序增加功能时,子类拓展自己的方法而不要重写父类方法避免影响原来的功能。

    比如:一个类A实现了加法方法method1,现在客户端需要添加减法功能,由类B继承A,并扩展减法方法method2,而不能重写method1,避免客户端调用B.method1()时影响加法功能。

    依赖倒转原则:高层模块不应依赖低层模块,二者都应该依赖其抽象。

    比如:类Teacher执行方法teach(Math)时需要依赖类Math,现在Teacher类要扩展方法teach(English)此时就要修改类Teacher,这是不合理的,应该将teach(Math)改为teach(Subject),再由Math和English实现接口Subject,这样Teacher拓展教授其他课程时,只要创建新类实现Subject接口即可而不需要修改Teacher类。

    接口隔离原则:建立单一的接口而不要建立庞大臃肿的接口,尽量细化接口,接口中的方法应该尽量少(但不可过少,避免一个类需要实现过多接口)

    比如:接口I内有方法method1,method2,method3,method4,method5。类A用到方法method1,method2,method5,类B用到方法method3,method4,method5,而两个类实现接口I时必须实现接口中的5个方法。应该将接口I拆分为接口I1(method1,method2)、I2(method3,method4),I3(method5),再使类A实现接口I1,I3,类B实现接口I2,I3.

    迪米特原则:一个类只与自己的直接相关类通信,实现低耦合。

    比如:当前有类A(总公司),类B(分公司),类C(总公司员工),类D(分公司员工)。类A需要获得该公司所有员工的信息,但不应该让A依赖D,而应该让A依赖B,B依赖D,这样分公司员工产生变化时不会影响总公司的类。

    开闭原则:一个软件实体应该对拓展开放,对修改关闭。

    常见的单例模式以及各种实现方式的优缺点,哪一种最好,手写常见的单例模式

    https://blog.csdn.net/CCCCC_SSSSS/article/details/80978121

    Spring中用到了哪些设计模式

    代理模式:spring AOP中JDK动态代理就是利用代理模式技术实现的。

    代理对象Proxy实现被代理对象Target类实现的接口I,并对接口I中的方法进行增强。

    策略模式:根据不同的Context环境选择不同的代理方法(JDK/Cglib)

    MyBatis中用到了哪些设计模式

    工厂模式:Mybatis中的资源加载使用的就是工厂模式,根据传入的DataSource类型返回不同的资源工厂,如JDBCDataSourceFactory、HibernateDataSourceFactory。

    克鲁斯卡尔算法、普林母算法、迪克拉斯算法

    Kruskal算法(最小生成树):

    将图中的所有边按照权重从小到大排序。

    依次选择每条边,如果这条边的两个定点有其一不在最小生成树中,则将这条边加入最小生成树。

    循环第二步,直到树中包含了图中所有的顶点为止。

    Prime算法(最小生成树):

    在图中选取任意节点为根节点。

    寻找与树中相连且权重最小的边加入最小生成树,加入树的边不能形成环路,否则丢弃掉该边

    循环第二步,直到树中包含了图中所有的顶点为止。

    Dijkstra(最短路径):使用广度优先搜索,权重不能为负值

    确定图中的起始点(V0)并将其标记,记录起点的路径长为0.其他所有节点的路径长为正无穷。

    循环寻找与被标记相连的边,计算边的另一头顶点距离起点的路径长len=min(原来的len,标记点len+边权重),选择该次循环后距离起点最近的顶点对其进行标记。

    直到所有的顶点都被标记

    什么是一致性Hash及其原理、Hash环问题

    https://blog.csdn.net/lihao21/article/details/54193868

    常见的排序算法和查找算法:快排、折半查找、堆排序等

    BIO、NIO、AIO的概念

    BIO:阻塞IO。线程发起IO请求,阻塞线程,等待IO数据准备完成,线程被唤醒。

    NIO:非阻塞IO。线程发起IO请求,若IO数据已准备完成则直接返回,否则通过轮询的方式等待IO数据准备完成再返回。

    AIO:异步IO。线程发起IO请求,不管IO数据准备如何直接返回。

    什么是长连接和短连接

    长连接:服务端和客户端建立连接后完成一次请求保持连接,下次发起请求无需重新建立连接。

    短连接:服务端和客户端建立连接后完成一次请求连接断开。

    Http1.0与Http1.1的区别:

    http1.0默认短连接,如需长连接要手动发送keep-alive参数,二http1.1默认长连接;

    http1.1先只发送header信息,通过权限验证后才发送body信息,如果无法通过权限验证(401)则不发生body,节约了带宽;

    http1.0无host域,无法设置虚拟站点共享一个ip。

    Http2.0与Http1.1的区别:

    http2.0支持多路复用,做到同一个连接并发处理多个请求

    http2.0支持header数据压缩

    http2.0支持推送。

    三次握手和四次挥手、为什么挥手需要四次

    第一次挥手:客户端发送停止请求

    第二次挥手:服务端发送确认停止响应

    第三次挥手:服务端处理完客户端请求停止前发送的请求,告诉客户端可以断开连接了。

    第四次挥手:客户端收到服务端的断开连接请求,发送确认断开,在2msl(最长报文段寿命)后断开连接。而服务端在收到低四次挥手报文时立即断开连接。

    如果没有第四次挥手,服务端即在第三次挥手请求发出时立即断开连接,若此次请求在传输过程丢失,客户端将永远无法收到断开请求保持连接。

    从游览器中输入URL到页面加载的发生了什么?

    https://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&mid=2247483724&idx=1&sn=e58dd30d124971c795584e8673d6cc71&chksm=e9c5f8fddeb271ebebbb6c350ed1abc252f1f26b4f35c4ce36e10bde9659a37520feabed2290&scene=21#wechat_redirect

    AtomicInteger底层实现原理;

    提供的常用方法:

    1. int addAndGet(int delta):以原子的方式将输入的数值与实例中的值相加,并放回结果。
    2. Boolean compareAndSet(int except, int update):如果输入的值等于预期值,则以原子方式将改之设置为输入的值。
    3. Int getAndIncrement():以原子方式将当前值加1,返回自增前的值。

        底层都是通过是Unsafe包的native方法完成的。

    synchronized与ReentraLock哪个是公平锁;

    ReentraLock可设置为公平锁,synchronized是非公平锁。

    CAS机制会出现什么问题;

    https://blog.csdn.net/liangwenmail/article/details/80832580

    1. ABA问题
    2. 循环时间开销大
    3. 只能保证一个共享变量的原子操作

    用过并发包下边的哪些类;

    1. CountDownLatch
    2. CyclicBarrier

    一个线程连着调用start两次会出现什么情况?

    线程无法从可运行状态转换为可运行状态,因此会报错

    wait方法能不能被重写,wait能不能被中断;

    wait是final方法,不能被重写;可以被中断

    线程池的实现?四种线程池?重要参数及原理?任务拒接策略有哪几种?

    线程池的好处:线程的创建和关闭都十分消耗资源,使用线程池可降低资源消耗;任务来临时,若池中存在空闲线程,可减小响应时间;提高线程的可管理性。

    线程池的实现:

    1.  
      ThreadPoolExecutor
    2.  
       
    3.  
      (corePoolSize,
    4.  
       
    5.  
      maximumPoolSize,
    6.  
       
    7.  
      keepAliveTime,
    8.  
       
    9.  
      unit,
    10.  
       
    11.  
      workQueue);

    创建线程池以后:提交任务,若线程池内线程数量小于corePoolSize,则创建新的线程执行任务;若线程池内数量大于corePoolSize,且队列未满,则将任务放入队列;若队列已满且线程池内数量小于maximumPoolSize,则创建新的线程执行任务,否则按照拒绝策略处理该任务。

    线程池中存在空闲(没有任务执行)的线程时,若空闲时间已达到keepAliveTime,且池内线程大于corePoolSize,则关闭多余的线程。

    拒绝策略:

    1. 丢弃任务,抛出异常
    2. 拒绝执行,不抛异常
    3. 丢弃缓存队列中最老的任务,并且重新尝试提交新任务
    4. 重试添加当前任务,直到成功

    四种线程池:

    1. FixedThreadPool:核心线程数=最大线程数;无界队列
    2. SingleThreadPool:核心线程数=最大线程数=1;无界队列
    3. CacheThreadPool:核心线程数=0;最大线程数=max;无容量队列
    4. ScheduleThreadPool:核心线程数=n;最大线程数=max;延时队列

    线程状态以及API怎么操作会发生这种转换;

    1. 新建
    2. 就绪:新建线程调用start()或者运行线程时间片用完
    3. 阻塞:
      1. 普通阻塞:join、sleep、
      2. 等待阻塞:wait
      3. 同步阻塞:遇到同步块
    4. 运行:就绪状态的线程获得CPU时间片
    5. 死亡:run方法结束或异常退出

    常用的避免死锁方法;

    死锁产生的四个必要条件是:

    1. 互斥条件:对所分配的资源进行排他性控制,即在一段时间内某资源仅为一进程使用。
    2. 请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放
    3. 不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。
    4. 环路等待条件:发生死锁时,必然存在一个进程——资源的环形链。

    避免死锁:

    1. 避免一个线程同时获取多个锁
    2. 尝试使用定时锁或者非阻塞的获取锁

    Minor GC与Full GC分别在什么时候发生?

    minorGC发生在新生代,当新生代剩余空间不足时,会触发minorGC,回收eden和一个survivor内的对象,回收以后仍然存活的对象会放入新生代的另一个survivor中。

    FullGC发生在整个堆中,老年代剩余连续空间不足会发生FullGC,剩余空间不足有两种判别标准:

    1. 若允许空间担保分配:当老年代剩余的连续空间大于历次晋升的平均大小时,不会发生FullGC,而是发生minorGC,此时若minorGC后若晋升的对象大小大于老年代剩余的连续空间,则再触发fullGC。

    2. 若不允许空间担保分配:当老年代剩余的连续空间大小小于新生代中的对象总大小时,便会触发fullGC。

    GC收集器有哪些?CMS收集器与G1收集器的特点。

    新生代有三种GC收集器,采用复制算法:

    1. Serial new:一种单线程的新生代垃圾收集器,工作时会暂停其他所有线程。
    2. Par new:serial new的多线程版本,工作时也会暂停其他所有线程。
    3. Parallel scavenge:以吞吐量为目标的多线程新生代垃圾收集器,适用于不与用户交互的后台垃圾收集。

    老年代也有三种GC收集器,采用标记/清除算法或者标记/整理算法:

    1. Serial old:serial new的老年版本——标记/整理
    2. Par old:Parallel scavenge的老年版本——标记/整理
    3. CMS:

    为什么JVM调优经常会将-Xms和-Xmx参数设置成一样;

    减轻伸缩堆带来的压力。因为剩余空间占到当前总空间的70%及以上时,会收缩堆大小,直到-Xms;剩余空间不足当前总空间的40%时,会扩展堆大小,直到-Xmx

    Java内存模型,方法区存什么;

    类的版本,字段,方法,接口和常量池,常量池中存着常量和符号引用

    CMS垃圾回收过程;

    CMS是一种并发的垃圾回收器,使用标记-清除算法,用在老年代,一般与parNew结合使用。回收过程分为4步:

    1. 初次标记
    2. 并发标记
    3. 重新标记
    4. 并发回收

    其中,初次标记和重新标记需要stop the world,但这两个过程需要的时间较短,而并发标记和并发回收是和工作线程并发执行的,所需时间较长。

    Full GC次数太多了,如何优化;

    引发Full GC的原因主要有以下几种:

    1. 老年代剩余连续空间大小小于新生代历次minor GC后回收晋升到老年代的平均大小(无法空间担保)
    2. 空间担保失败,引发Full GC
    3. 永久代满

    优化检查:

    1. 查看自己写的程序是否大对象频繁回收
    2. 调大堆大小:-Xmx和-Xms
    3. 适当增加新生代比例:XX:NewRatio=n

    直接内存如何管理的;

    直接内存不属于虚拟机运行时数据区的一部分,其大小自然不受java虚拟机堆限制,但会受到本机总内存大小限制。其大小可以通过-XX:MaxDirectMemorySize来设置,否则默认大小和堆大小一样大。回收只有等到虚拟机触发Full GC时才顺便对直接内存进行回收,或手动System.gc(),否则会报内存溢出异常。

    Java线程池使用无界任务队列和有界任务队列的优劣对比;

    使用无界队列,则maxPoolSize参数无效,除非资源耗尽,否则任务可以无止尽的加入到无界队列中,如果任务执行速度慢于队列添加任务的时间,那么有可能耗尽系统资源。

    使用有界队列,当有界队列放满,线程池内线程数又大于maxPoolSize时,需要选择拒绝策略来执行。

    CountDownLatch和CyclicBarrier的区别;

    两者都是JDK封装的并发工具类,均使用计数的方法阻塞线程。CountDownLatch的计数器不可重置,而CyclicBarrier可以,故CyclicBarrier适用于更复杂的业务场景。

    Java中有哪些同步方案

    重量级锁synchronized,显式锁reentrantlock,并发容器concurrentHashMap、concurrentLinkedQueue, CAS,轻量级锁Volatile,AQS

    如果你的项目出现了内存泄露,怎么监控这个问题呢;

    使用MAT工具定位内存泄漏出现的位置,然后优化程序

    https://blog.csdn.net/lc0817/article/details/67014499

    标记清除和标记整理的区别和优缺点,为何标记整理会发生stop the world;

    标记清除是在回收时先标记需要回收的对象,标记完成后对这些被标记的对象进行统一回收,容易出现空间碎片较多的情况;而标记整理比标记清除多了一步,即在标记完成后,将未被标记的对象移到一边,然后将边界后的所有被标记对象回收,这样能避免出现空间碎片,但是需要stop the world。因为如果与工作线程并发执行,工作线程中会不断产生新的对象,无法标记出回收边界。

    线程池,如何根据CPU的核数来设计线程大小,如果是计算机密集型的呢,如果是IO密集型的呢?

    CPU密集型:size = cpu核数 + 1

    IO密集型:size = cpu核数 * 2

    多个线程同时读写,读线程的数量远远大于写线程,你认为应该如何解决并发的问题?你会选择加什么样的锁?

    方案一:读写锁reentrantWriteReadLock

    方案二:WriteOnCopy,写时复制出一份,加锁修改,然后覆盖;读不加锁

    线程池内的线程如果全部忙,提交一个新的任务,会发生什么?队列全部塞满了之后,还是忙,再提交会发生什么?

    添加到任务队列中;如果线程池中线程数量小于maxPoolSize,则创建新线程,否则执行4种拒绝策略:

    synchronized关键字锁住的是什么东西?在字节码中是怎么表示的?在内存中的对象上表现为什么?

    锁对象的对象头。字节码中用monitorenter和monitorexit。

    wait/notify/notifyAll方法需不需要被包含在synchronized块中?这是为什么?

    https://blog.csdn.net/haluoluo211/article/details/49558155

    需要,这三个方法都是object的方法,由锁对象执行,持有该锁对象的代码块才能调用这几个方法。

    让你设计一个cache如何设计;

    https://blog.csdn.net/xuchishao/article/details/48292197

    内容转自:https://blog.csdn.net/CCCCC_SSSSS/article/details/86672145

  • 相关阅读:
    Voiceover “眼里” 的HTML5标签
    Edge浏览器默认地址被百度劫持
    How to fix "ReferenceError: primordials is not defined" error
    php 读文件
    jsconfig.json: Unexpected token ] in JSON at position
    公司入域电脑更新遇到 0x8024401c 解决办法
    颜色计算
    Terminal 美化
    highcharts 查看配置
    cra
  • 原文地址:https://www.cnblogs.com/xiao-lin-unit/p/13657135.html
Copyright © 2020-2023  润新知