zoukankan      html  css  js  c++  java
  • 200多道java常见面试题,包含各个方面,答案持续整理

    这份面试题包含了 19 个模块:Java 基础、容器、多线程、反射、对象拷贝、Java Web、异常、网络、设计模式、Spring/Spring MVC、Spring Boot/Spring Cloud、Hibernate、Mybatis、RabbitMQ、Kafka、Zookeeper、MySql、Redis、JVM 等。

    一、Java 基础

    1.JDK 和 JRE 有什么区别?

     这个问题其实只要弄清楚JDK和JRE是什么就知道答案了

    JRE是java运行时环境,包含了java虚拟机,java基础类库。是使用java语言编写的程序运行所需要的软件环境,是提供给想运行java程序的用户使用的,还有所有的Java类库的class文件,都在lib目录下,并且都打包成了jar.

    JDK是java开发工具包,是程序员使用java语言编写java程序所需的开发工具包,是提供给程序员使用的。JDK包含了JRE,同时还包含了编译java源码的编译器javac,还包含了很多java程序调试和分析的工具:jconsole,jvisualvm等工具软件,还包含了java程序编写所需的文档和demo例子程序。

    总结:简单来说,JRE可以支撑Java程序的运行,包括JVM虚拟机(java.exe等)和基本的类库(rt.jar等),JDK可以支持Java程序的开发,包括编译器(javac.exe)、开发工具(javadoc.exe、jar.exe、keytool.exe、jconsole.exe)和更多的类库(如tools.jar)等。

    2.== 和 equals 的区别是什么?

    这个题大多数时候出现在笔试中,当然,有的面试官也会问到。

    简单来讲,他们的区别有以下三方面:

    1.  ==是判断两个变量或实例是不是指向同一个内存空间,equals是判断两个变量或实例所指向的内存空间的值是不是相同 
    2.  ==是指对内存地址进行比较 , equals()是对字符串的内容进行比较
    3.  ==指引用是否相同, equals()指的是值是否相同

            用一张图来说明他们的关系(图片转载自https://blog.csdn.net/qq_36522306/article/details/80550210

     

    3.两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?

    这个题明显是不对的,反过来说就对了(前提是你重写了hashcode方法,如果没重写,也是不一定相等的)。但是一般情况下,如果是笔试时候遇到,答错误就行了,但如果是面试的时候问到,面试官肯定能会深究继续问为什么不对,这个时候你就要了解下他们的原理了。hashCode()返回该对象的哈希码值;equals()返回两个对象是否相等。 

    关于hashCode和equal是方法,有如下几点需要注意的:

    1、两个对象用equals()比较返回true,那么两个对象的hashCode()方法必须返回相同的结果。

    2、两个对象用equals()比较返回false,不要求hashCode()方法也一定返回不同的值,但是最好返回不同值,亿提搞哈希表性能。

    3、重写equals()方法,必须重写hashCode()方法,以保证equals方法相等时两个对象hashcode返回相同的值。

    4.final 在 java 中有什么作用?

    final作为Java中的关键字可以用于三个地方。用于修饰类、类属性和类方法。
    特征:凡是引用final关键字的地方皆不可修改!
    (1)修饰类:表示该类不能被继承;
    (2)修饰方法:表示方法不能被重写;
    (3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。

    5.java 中的 Math.round(-1.5) 等于多少?

    这种题一般也只会出现在笔试题中,但如果答错,也是相当掉分的,因为这是基础中的基础。

    Math.round(1.5)的返回值是2,Math.round(-1.5)的返回值是-1。四舍五入的原理是在参数上加0.5然后做向下取整。

    6.String 属于基础的数据类型吗?

    答案肯定是不属于,而且这里你要知道java的8中基础数据类型,并且知道他们的位数,取值范围。速记方法:知道了位数,他们的范围就知道了,就是2的-(位数-1)次幂~(位数-1)次幂-1

     

    7.java 中操作字符串都有哪些类?它们之间有什么区别?

            这个题,博主每次面试几乎都会被问到,有的面试官会问的比较深,所以要知道其原理,即为什么可变,为什么不可变,为什么线程安全,为什么线程不安全。

    String、StringBuffer、StringBuilder

    String因为底层是final修饰的,所以长度不可变

    StringBuffer、StringBuilder长度可变,但是他们两者也有差别,StringBuffer线程安全(底层方法都是synchronized关键字修饰的,所以线程安全),StringBuilder线程不安全

    8.String str="i"与 String str=new String("i")一样吗?

    答案肯定是不一样的,但是为什么呢,给大家举个栗子,大家看看就立马就明白了。

    String x = "张三";
    String y = "张三";
    String z = new String("张三");
    System.out.println(x == y); // true
    System.out.println(x == z); // false

    为什么会输出上边的结果呢,String x = "张三" 的方式,Java 虚拟机会将其分配到常量池中,而常量池中没有重复的元素,比如当执行“张三”时,java虚拟机会先在常量池中检索是否已经有“张三”,如果有那么就将“张三”的地址赋给变量,如果没有就创建一个,然后在赋给变量;而 String z = new String(“张三”) 则会被分到堆内存中,即使内容一样还是会创建新的对象。

    9.如何将字符串反转?

    最便捷的方式当然是使用StringBuffer或者StringBuilder的reverse 方法,其本质都调用了它们的父类 AbstractStringBuilder 的 reverse 方法实现。

    /**
         * 使用 StringBuilder
         * @param str
         * @return
         */
        public static String reverseStringByStringBuilderApi(String str) {
            if (str != null && str.length() > 0) {
                return new StringBuilder(str).reverse().toString();
            }
            return str;
        }

    当然,大佬也可以自己写逻辑反转

    /**
         * 自己实现
         * @param str
         * @return
         */
        public static String reverseString(String str) {
            if (str != null && str.length() > 0) {
                int len = str.length();
                char[] chars = new char[len];
                for (int i = len - 1; i >= 0; i--) {
                    chars[len - 1 - i] = str.charAt(i);
                }
                return new String(chars);
            }
            return str;
        }

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

    1. indexOf():返回指定字符的索引。
    2. charAt():返回指定索引处的字符。
    3. replace():字符串替换。
    4. trim():去除字符串两端空白。
    5. split():分割字符串,返回一个分割后的字符串数组。
    6. getBytes():返回字符串的 byte 类型数组。
    7. length():返回字符串长度。
    8. toLowerCase():将字符串转成小写字母。
    9. toUpperCase():将字符串转成大写字符。
    10. substring():截取字符串。
    11. equals():字符串比较。

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

    当然是不必须。

    1. 抽象类必须有关键字abstract来修饰。
    2. 抽象类可以不含有抽象方法
    3. 如果一个类包含抽象方法,则该类必须是抽象类

    12.普通类和抽象类有哪些区别?

    关键点:abstract修饰符(抽象方法)、具体实现过程、实例化、子类实现父类的抽象方法

    1. 普通类中不可含有抽象方法,可以被实例化;
    2. 抽象类,则抽象类中所有的方法自动被认为是抽象方法,没有实现过程(这一点在java8已经改了,抽象类可以有实现,具体可以去了解java8的新特性,也是经常被问的噢),不可被实例化;抽象类的子类,除非也是抽象类,否则必须实现该抽象类声明的方法

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

    这里就要参考第4题了,如果这题不会答,说明第4题没搞明白。

    答案是明显不行的,抽象类是要被继承的,如果被final修饰了,就没法继承了。

    14.接口和抽象类有什么区别?

    这个被问到的频率也很高

     

    15.java 中 IO 流分为几种?

    数据流是 Java 进行 I/O 操作的对象,它按照不同的标准可以分为不同的类别。

    1. 按照流的方向主要分为输入流和输出流两大类。
    2. 数据流按照数据单位的不同分为字节流和字符流。
    3. 按照功能可以划分为节点流和处理流。

    所有输入流类都是 InputStream 抽象类(字节输入流)和 Reader 抽象类(字符输入流)的子类。
    所有输出流类都是 OutputStream 抽象类(字节输出流)和 Writer 抽象类(字符输出流)的子类。

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

         这题自己去查吧,博主现在不想弄这个题的答案,哈哈哈哈

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

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

    二、容器(集合)

                       

    图片转载自https://blog.csdn.net/qq_35771266/article/details/97156939

    18.java 容器都有哪些?

      此题答案从上图中找

    19.Collection 和 Collections 有什么区别?

    1. Collcetion是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法。实现该接口的类主要有List和Set,该接口的设计目标是为各种具体的集合提供最大化的统一操作方式。
    2. Collections是针对集合类的一个包装类(工具类),它提供了一系列的静态方法以实现对各种集合的搜索、排序、线程安全化等操作,其中大多数方法都是用来处理线性表。 Collections类不能实例化,如同一个工具类,服务于Collection。若是在使用Collections类的方法时候,对应的collection的对象为null,则这些方法都会抛出 NullPointerException 。之前我们见到的包装类还有Arrays,它是为数组提供服务的。

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

    这个题比较复杂,要说的东西非常的多这里就简单的罗列下他们的主要区别,后续有空了再详细介绍。

    首先list与set都继承于Collection,list序列的形式存储元素。所以取出来的顺序可能和放入顺序不同。set的特点是无法存放重复的元素。map一个映射不能包含重复的键;每个键最多只能映射一个值。以键值对存放数据以上三个都是接口且不能被实例化。

    List:
    1.可以允许重复的对象。
    2.可以插入多个null元素。
    3.是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序。
    4.常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流行,它提供了使用索引的随意访问,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。
    Set:
    1.不允许重复对象
    2. 无序容器,你无法保证每个元素的存储顺序,TreeSet通过 Comparator 或者 Comparable 维护了一个排序顺序。
    3. 只允许一个 null 元素
    4.Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序容器。
    map:
    1.Map不是collection的子接口或者实现类。Map是一个接口。
    2.Map 的 每个 Entry 都持有两个对象,也就是一个键一个值,Map 可能会持有相同的值对象但键对象必须是唯一的。
    3. TreeMap 也通过 Comparator 或者 Comparable 维护了一个排序顺序。
    4. Map 里你可以拥有随意个 null 值但最多只能有一个 null 键。
    5.Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。(HashMap、TreeMap最常用)

    21.HashMap 和 Hashtable 有什么区别?

    HashMap和Hashtable是一组相似的键值对集合,它们的区别也是面试常被问的问题之一,我这里简单总结一下HashMap和Hashtable主要的2个区别:
    1、Hashtable是线程安全的,Hashtable所有对外提供的方法都使用了synchronized,也就是同步(所以性能上会比HashMap稍微慢一点),而HashMap则是线程非安全的
    2、Hashtable不允许空的key和value,空的value将导致空指针异常,而HashMap则无所谓,没有这方面的限制,可以允许有一个空的key,value可以允许有多个。

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

    TreeMap<K,V>的Key值是要求实现java.lang.Comparable,所以迭代的时候TreeMap默认是按照Key值升序排列的;TreeMap的实现也是基于红黑树结构。
    而HashMap<K,V>的Key值实现散列hashCode(),分布是散列的均匀的,不支持排序,数据结构主要是桶(数组),链表或红黑树。
    所以,查询的时候使用HashMap,增加、快速创建的时候使用TreeMap。

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

      这题直接参阅博主的另一篇文章吧,弄懂那个,hashmap的面试基本能够应对,此处不再赘述。https://www.cnblogs.com/hwtnet/p/12083440.html

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

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

    1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。 

    2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。 

    3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。 

    有可能还会被问到,当在ArrayList 和 LinkedList最后面插入一个元素的时候,谁的效率更高。回答ArrayList就可以了 。原因是ArrayList大概率不需要扩容(如果遇到需要扩容,那就不好说了),直接增加就行了,但是 LinkedList需要New一个Node对象来存放新元素,所以会比较慢。还有一种问法,同样是在尾部添加元素,就是当数据量在千万级别以下的时候,而且谁的效率高。大部分时候是LinkedList高,但当数据量超过千万以后,ArrayList 效率明显高于LinkedList,原因是当数据量大的时候,new一个对象的时间明显大于扩容的时间,那么就会出现ArrayList的效率比LinkedList高了。

    26.如何实现数组和 List 之间的转换?

    直接上代码吧,列出几种最简单以及最常见的方式,应该都看的懂

    数组转list
    public class ArrayToList {
        
        public static void main(String[] args) {
            
            //数组转list
            String[] str=new String[] {"hello","world"};
            //方式一:使用for循环把数组元素加进list,最原始的方法
            List<String> list=new ArrayList<String>();
            for (String string : str) {
                list.add(string);
            }
            System.out.println(list);
            
            //方式二: 最简单以及博主最推荐的方法
            List<String> list2=new ArrayList<String>(Arrays.asList(str));
            System.out.println(list2);
            //方式三:使用Collections.addAll()
            List<String> list3=new ArrayList<String>(str.length);
            Collections.addAll(list3, str);
            System.out.println(list3);
        }
    }

    List转数组

    public class ListToArray {
    
        public static void main(String[] args) {
            //list转数组
            List<String> list=new ArrayList<String>();
            list.add("hello");
            list.add("world");
            
            //方式一:使用for循环
            String[] str1=new String[list.size()];
            for(int i=0;i<list.size();i++) {
                str1[i]=list.get(i);
            }
            for (String string : str1) {
                System.out.println(string);
            }
            
            //方式二:使用toArray()方法
            //list.toArray(T[]  a); 将list转化为你所需要类型的数组
            String[] str2=list.toArray(new String[list.size()]);
            for (String string : str2) {
                System.out.println(string);
            } 
        }
    
    }

    27.ArrayList 和 Vector 的区别是什么?

    1. Vector 是线程安全的,也就是说是它的方法之间是线程同步的,而 ArrayList 是线程不安全的,它的方法之间是线程不同步的
    2. ArrayList与Vector都有一个初始的容量大小,当需要扩容时,Vector 默认增长为原来两倍,而 ArrayList 的增长为原来的 1.5 倍。

    28.Array 和 ArrayList 有何区别?

      Array 长度固定,但是效率非常的高,且只能存放同类型的对象,ArrayList长度动态不固定,但是效率相对较低,可以存放任何类型的对象,每个元素的类型不同都可以。

    29.在 Queue 中 poll()和 remove()有什么区别?

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

      Vector、Hashtable、ConcurrentHashMap(java.util.concurrent包下所有的集合类)、Stack

    31.迭代器 Iterator 是什么?

    迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。

    32.Iterator 怎么使用?有什么特点?

    Java中的Iterator功能比较简单,并且只能单向移动:
    (1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。
    (2) 使用next()获得序列中的下一个元素。
    (3) 使用hasNext()检查序列中是否还有元素。
    (4) 使用remove()将迭代器新返回的元素删除。
    Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。

    33.Iterator 和 ListIterator 有什么区别?

    答案见32题

    34.怎么确保一个集合不能被修改?

    可以使用 Collections. unmodifiableCollection(Collection c) 方法来创建一个只读集合,这样改变集合的任何操作都会抛出 Java. lang. UnsupportedOperationException 异常。

    List<String> list = new ArrayList<>();
    list. add("A");
    Collection<String> unmlist = Collections. unmodifiableCollection(list);
    unmlist. add("B"); // 运行时此行报错
    System. out. println(list.size());

    三、多线程

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

    (1) 并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。

    (2) 并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。

    (3) 在一台处理器上“同时”(这个同时实际上市交替“”)处理多个任务,在多台处理器上同时处理多个任务。如hadoop分布式集群

    举个栗子:

    顺序执行:你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。

    并发:你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。

    并行:你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。此处注意理解:是同时吃,同时说,要真严格的说的话,需要2张嘴才是并行。

    36.线程和进程的区别?

    进程:是执行中一段程序,即一旦程序被载入到内存中并准备执行,它就是一个进程。进程是表示资源分配的的基本概念,又是调度运行的基本单位,是系统中的并发执行的单位。
    线程:单个进程中执行中每个任务就是一个线程。线程是进程中执行运算的最小单位。
    一个线程只能属于一个进程,但是一个进程可以拥有多个线程。多线程处理就是允许一个进程中在同一时刻执行多个任务。

    37.守护线程是什么?

      守护线程,专门用于服务其他的线程的线程。如果其他的线程(即用户自定义线程)都执行完毕,连main线程也执行完毕,那么jvm就会退出(即停止运行)——此时,连jvm都停止运行了,守护线程当然也就停止执行了

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

      继承 Thread 类、实现 Runnable 接口、实现Callable接口,重写call()方法,通过Runnable实现类使用Thread。

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

    主要区别

    • Runnable 接口 run 方法无返回值;Callable 接口 call 方法有返回值,支持泛型
    • Runnable 接口 run 方法只能抛出运行时异常,且无法捕获处理;Callable 接口 call 方法允许抛出异常,可以获取异常信息

    40.线程有哪些状态?

     

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

      sleep() 和 wait() 的区别就是 调用sleep方法的线程不会释放对象锁,而调用wait() 方法会释放对象锁

    42.notify()和 notifyAll()有什么区别?

    notify(): 唤醒一个正在等待该对象的线程。(随机唤醒一个)
    notifyAll(): 唤醒所有正在等待该对象的线程。

    43.线程的 run()和 start()有什么区别?

    当你启动线程,使用start(),系统会把run()方法当成线程执行体来处理,这是正常的,也是正确的情况。但是,当你启动线程时,调用run()方法,系统run()方法会立即执行,但是这时候系统会把run()方法当成普通的方法,线程对象也当成一个普通对象。我的理解就是,他们都可以让run方法执行,但是,使用start()方法的话,run()就会被当做线程来使用,直接用run()方法的话,就是个普通方法而已。

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

    Executors目前提供了5种不同的线程池创建配置:

    1. newCachedThreadPool(),它是用来处理大量短时间工作任务的线程池,具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置时间超过60秒,则被终止并移除缓存;长时间闲置时,这种线程池,不会消耗什么资源。其内部使用SynchronousQueue作为工作队列。
    2. newFixedThreadPool(int nThreads),重用指定数目(nThreads)的线程,其背后使用的是无界的工作队列,任何时候最多有nThreads个工作线程是活动的。这意味着,如果任务数量超过了活动线程数目,将在工作队列中等待空闲线程出现;如果工作线程退出,将会有新的工作线程被创建,以补足指定数目nThreads。
    3. newSingleThreadExecutor(),它的特点在于工作线程数目限制为1,操作一个无界的工作队列,所以它保证了所有的任务都是被顺序执行,最多会有一个任务处于活动状态,并且不予许使用者改动线程池实例,因此可以避免改变线程数目。
    4. newSingleThreadScheduledExecutor()和newScheduledThreadPool(int corePoolSize),创建的是个ScheduledExecutorService,可以进行定时或周期性的工作调度,区别在于单一工作线程还是多个工作线程。
    5. newWorkStealingPool(int parallelism),这是一个经常被人忽略的线程池,Java 8 才加入这个创建方法,其内部会构建ForkJoinPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序。

      原文链接:https://blog.csdn.net/ITzhanghao/article/details/100151997

    45.线程池都有哪些状态?

    1. RUNNING:这是最正常的状态,接受新的任务,处理等待队列中的任务。线程池的初始化状态是RUNNING。线程池被一旦被创建,就处于RUNNING状态,并且线程池中的任务数为0。
    2. SHUTDOWN:不接受新的任务提交,但是会继续处理等待队列中的任务。调用线程池的shutdown()方法时,线程池由RUNNING -> SHUTDOWN。
    3. STOP:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。调用线程池的shutdownNow()方法时,线程池由(RUNNING or SHUTDOWN ) -> STOP。
    4. TIDYING:所有的任务都销毁了,workCount 为 0,线程池的状态在转换为 TIDYING 状态时,会执行钩子方法 terminated()。因为terminated()在ThreadPoolExecutor类中是空的,所以用户想在线程池变为 TIDYING时进行相应的处理;可以通过重载terminated()函数来实现。当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。
    5. TERMINATED:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。

    46.线程池中 submit()和 execute()方法有什么区别?

    1. execute() 只能执行 Runnable 类型的任务 ;submit() 可以执行 Runnable 和 Callable 类型的任务
    2. execute() 没有返回值;而 submit() 有返回值
    3. submit() 的返回值 Future 调用get方法时,可以捕获处理异常

    47.在 java 程序中怎么保证多线程的运行安全?

    • 修改线程模型。即不在线程之间共享该状态变量。一般这个改动比较大,需要量力而行。
    • 将对象变为不可变对象。有时候实现不了。
    • 在访问状态变量时使用同步,这是最常用的方式。 synchronized和Lock都可以实现同步。简单点说,就是在你修改或访问可变状态时加锁,独占对象,让其他线程进不来。这也算是一种线程隔离的办法。(这种方式也有不少缺点,比如说死锁,性能问题等等)
    • 其实有一种更好的办法,就是设计线程安全类。《代码大全》就有提过,问题解决得越早,花费的代价就越小。具体怎么实现大家自己去问度娘吧,这里不赘述。

    48.多线程锁的升级原理是什么?

    • 在所有的锁都启用的情况下线程进入临界区时会先去获取偏向锁,如果已经存在偏向锁了,则会尝试获取轻量级锁,启用自旋锁,如果自旋也没有获取到锁,则使用重量级锁,没有获取到锁的线程阻塞挂起,直到持有锁的线程执行完同步块;
    • 偏向锁是在无锁争用的情况下使用的,也就是在当前线程没有执行完之前,没有其它线程会执行该同步块,一旦有了第二个线程的争用,偏向锁就会升级为轻量级锁,如果轻量级锁自旋到达阈值后,没有获取到锁,就会升级为重量级锁;如果线程争用激烈,那么应该禁用偏向锁。

    49.什么是死锁?

      死锁,简单来讲,就是多个线程相互等待对方的资源而进入循环等待的一种状态。栗子:线程1已经持有锁A,要去获取锁B,线程2已经持有锁B,要去获取锁A,即两个线程都在等待获取对方持有的锁。

    50.怎么防止死锁?

    • 避免多次锁定。尽量避免同一个线程对多个 Lock 进行锁定。例如上面的死锁程序,主线程要对 A、B 两个对象的 Lock 进行锁定,副线程也要对 A、B 两个对象的 Lock 进行锁定,这就埋下了导致死锁的隐患。
    • 具有相同的加锁顺序。如果多个线程需要对多个 Lock 进行锁定,则应该保证它们以相同的顺序请求加锁。比如上面的死锁程序,主线程先对 A 对象的 Lock 加锁,再对 B 对象的 Lock 加锁;而副线程则先对 B 对象的 Lock 加锁,再对 A 对象的 Lock 加锁。这种加锁顺序很容易形成嵌套锁定,进而导致死锁。如果让主线程、副线程按照相同的顺序加锁,就可以避免这个问题。
    • 使用定时锁。程序在调用 acquire() 方法加锁时可指定 timeout 参数,该参数指定超过 timeout 秒后会自动释放对 Lock 的锁定,这样就可以解开死锁了。
    • 死锁检测。死锁检测是一种依靠算法机制来实现的死锁预防机制,它主要是针对那些不可能实现按序加锁,也不能使用定时锁的场景的。

      总的来说,知道了产生死锁的几大特性,然后去破坏这些特性中的任意一种就可以解决死锁的问题。

    51.ThreadLocal 是什么?有哪些使用场景?

    ThreadLocal 是线程本地存储,在每个线程中都创建了一个 ThreadLocalMap 对象,每个线程可以访问自己内部 ThreadLocalMap 对象内的 value。
    经典的使用场景是为每个线程分配一个 JDBC 连接 Connection。这样就可以保证每个线程的都在各自的 Connection 上进行数据库的操作,不会出现 A 线程关了 B线程正在使用的 Connection; 还有 Session 管理 等问题。

    52.说一下 synchronized 底层实现原理?

    从字节码中可知同步语句块的实现使用的是monitorenter 和 monitorexit 指令,其中monitorenter指令指向同步代码块的开始位置,monitorexit指令则指明同步代码块的结束位置,当执行monitorenter指令时,当前线程将试图获取 objectref(即对象锁) 所对应的 monitor 的持有权,当 objectref 的 monitor 的进入计数器为 0,那线程可以成功取得 monitor,并将计数器值设置为 1,取锁成功。如果当前线程已经拥有 objectref 的 monitor 的持有权,那它可以重入这个 monitor (关于重入性稍后会分析),重入时计数器的值也会加 1。倘若其他线程已经拥有 objectref 的 monitor 的所有权,那当前线程将被阻塞,直到正在执行线程执行完毕,即monitorexit指令被执行,执行线程将释放 monitor(锁)并设置计数器值为0 ,其他线程将有机会持有 monitor 。

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

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

    54.synchronized 和 Lock 有什么区别?

    1. 首先synchronized是java内置关键字,在jvm层面,Lock是个java类;
    2. synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
    3. synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
    4. 用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等 待就结束了;
    5. synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)
    6. Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

    55.synchronized 和 ReentrantLock 区别是什么?

    • synchronized 竞争锁时会一直等待;ReentrantLock 可以尝试获取锁,并得到获取结果
    • synchronized 获取锁无法设置超时;ReentrantLock 可以设置获取锁的超时时间
    • synchronized 无法实现公平锁;ReentrantLock 可以满足公平锁,即先等待先获取到锁
    • synchronized 控制等待和唤醒需要结合加锁对象的 wait() 和 notify()、notifyAll();ReentrantLock 控制等待和唤醒需要结合 Condition 的 await() 和 signal()、signalAll() 方法
    • synchronized 是 JVM 层面实现的;ReentrantLock 是 JDK 代码层面实现
    • synchronized 在加锁代码块执行完或者出现异常,自动释放锁;ReentrantLock 不会自动释放锁,需要在 finally{} 代码块显示释放

    PS:补充一个相同点,都可以做到同一线程,同一把锁,可重入代码块。

    56.说一下 atomic 的原理?

      这题没什么意思,各位自寻答案吧。

    四、反射

    57.什么是反射?

    58.什么是 java 序列化?什么情况下需要序列化?

    59.动态代理是什么?有哪些应用?

    60.怎么实现动态代理?

    五、对象拷贝

    61.为什么要使用克隆?

    62.如何实现对象克隆?

    63.深拷贝和浅拷贝区别是什么?

    六、Java Web

    64.jsp 和 servlet 有什么区别?

    65.jsp 有哪些内置对象?作用分别是什么?

    66.说一下 jsp 的 4 种作用域?

    67.session 和 cookie 有什么区别?

    68.说一下 session 的工作原理?

    69.如果客户端禁止 cookie 能实现 session 还能用吗?

    70.spring mvc 和 struts 的区别是什么?

    71.如何避免 sql 注入?

    72.什么是 XSS 攻击,如何避免?

    73.什么是 CSRF 攻击,如何避免?

    七、异常

    74.throw 和 throws 的区别?

    75.final、finally、finalize 有什么区别?

    76.try-catch-finally 中哪个部分可以省略?

    77.try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?

    78.常见的异常类有哪些?

    八、网络

    79.http 响应码 301 和 302 代表的是什么?有什么区别?

    80.forward 和 redirect 的区别?

    81.简述 tcp 和 udp的区别?

    82.tcp 为什么要三次握手,两次不行吗?为什么?

    83.说一下 tcp 粘包是怎么产生的?

    84.OSI 的七层模型都有哪些?

    85.get 和 post 请求有哪些区别?

    86.如何实现跨域?

    87.说一下 JSONP 实现原理?

    九、设计模式

    88.说一下你熟悉的设计模式?

    89.简单工厂和抽象工厂有什么区别?

    十、Spring/Spring MVC

    90.为什么要使用 spring?

    91.解释一下什么是 aop?

    92.解释一下什么是 ioc?

    93.spring 有哪些主要模块?

    94.spring 常用的注入方式有哪些?

    95.spring 中的 bean 是线程安全的吗?

    96.spring 支持几种 bean 的作用域?

    97.spring 自动装配 bean 有哪些方式?

    98.spring 事务实现方式有哪些?

    99.说一下 spring 的事务隔离?

    100.说一下 spring mvc 运行流程?

    101.spring mvc 有哪些组件?

    102.@RequestMapping 的作用是什么?

    103.@Autowired 的作用是什么?

    十一、Spring Boot/Spring Cloud

    104.什么是 spring boot?

    105.为什么要用 spring boot?

    106.spring boot 核心配置文件是什么?

    107.spring boot 配置文件有哪几种类型?它们有什么区别?

    108.spring boot 有哪些方式可以实现热部署?

    109.jpa 和 hibernate 有什么区别?

    110.什么是 spring cloud?

    111.spring cloud 断路器的作用是什么?

    112.spring cloud 的核心组件有哪些?

    十二、Hibernate

    113.为什么要使用 hibernate?

    114.什么是 ORM 框架?

    115.hibernate 中如何在控制台查看打印的 sql 语句?

    116.hibernate 有几种查询方式?

    117.hibernate 实体类可以被定义为 final 吗?

    118.在 hibernate 中使用 Integer 和 int 做映射有什么区别?

    119.hibernate 是如何工作的?

    120.get()和 load()的区别?

    121.说一下 hibernate 的缓存机制?

    122.hibernate 对象有哪些状态?

    123.在 hibernate 中 getCurrentSession 和 openSession 的区别是什么?

    124.hibernate 实体类必须要有无参构造函数吗?为什么?

    十三、Mybatis

    125.mybatis 中 #{}和 ${}的区别是什么?

    126.mybatis 有几种分页方式?

    127.RowBounds 是一次性查询全部结果吗?为什么?

    128.mybatis 逻辑分页和物理分页的区别是什么?

    129.mybatis 是否支持延迟加载?延迟加载的原理是什么?

    130.说一下 mybatis 的一级缓存和二级缓存?

    131.mybatis 和 hibernate 的区别有哪些?

    132.mybatis 有哪些执行器(Executor)?

    133.mybatis 分页插件的实现原理是什么?

    134.mybatis 如何编写一个自定义插件?

    十四、RabbitMQ

    135.rabbitmq 的使用场景有哪些?

    136.rabbitmq 有哪些重要的角色?

    137.rabbitmq 有哪些重要的组件?

    138.rabbitmq 中 vhost 的作用是什么?

    139.rabbitmq 的消息是怎么发送的?

    140.rabbitmq 怎么保证消息的稳定性?

    141.rabbitmq 怎么避免消息丢失?

    142.要保证消息持久化成功的条件有哪些?

    143.rabbitmq 持久化有什么缺点?

    144.rabbitmq 有几种广播类型?

    145.rabbitmq 怎么实现延迟消息队列?

    146.rabbitmq 集群有什么用?

    147.rabbitmq 节点的类型有哪些?

    148.rabbitmq 集群搭建需要注意哪些问题?

    149.rabbitmq 每个节点是其他节点的完整拷贝吗?为什么?

    150.rabbitmq 集群中唯一一个磁盘节点崩溃了会发生什么情况?

    151.rabbitmq 对集群节点停止顺序有要求吗?

    十五、Kafka

    152.kafka 可以脱离 zookeeper 单独使用吗?为什么?

    153.kafka 有几种数据保留的策略?

    154.kafka 同时设置了 7 天和 10G 清除数据,到第五天的时候消息达到了 10G,这个时候 kafka 将如何处理?

    155.什么情况会导致 kafka 运行变慢?

    156.使用 kafka 集群需要注意什么?

    十六、Zookeeper

    157.zookeeper 是什么?

    158.zookeeper 都有哪些功能?

    159.zookeeper 有几种部署模式?

    160.zookeeper 怎么保证主从节点的状态同步?

    161.集群中为什么要有主节点?

    162.集群中有 3 台服务器,其中一个节点宕机,这个时候 zookeeper 还可以使用吗?

    163.说一下 zookeeper 的通知机制?

    十七、MySql

    164.数据库的三范式是什么?

    165.一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 mysql 数据库,又插入了一条数据,此时 id 是几?

    166.如何获取当前数据库版本?

    167.说一下 ACID 是什么?

    168.char 和 varchar 的区别是什么?

    169.float 和 double 的区别是什么?

    170.mysql 的内连接、左连接、右连接有什么区别?

    171.mysql 索引是怎么实现的?

    172.怎么验证 mysql 的索引是否满足需求?

    173.说一下数据库的事务隔离?

    174.说一下 mysql 常用的引擎?

    175.说一下 mysql 的行锁和表锁?

    176.说一下乐观锁和悲观锁?

    177.mysql 问题排查都有哪些手段?

    178.如何做 mysql 的性能优化?

    十八、Redis

    179.redis 是什么?都有哪些使用场景?

    180.redis 有哪些功能?

    181.redis 和 memecache 有什么区别?

    182.redis 为什么是单线程的?

    183.什么是缓存穿透?怎么解决?

    184.redis 支持的数据类型有哪些?

    185.redis 支持的 java 客户端都有哪些?

    186.jedis 和 redisson 有哪些区别?

    187.怎么保证缓存和数据库数据的一致性?

    188.redis 持久化有几种方式?

    189.redis 怎么实现分布式锁?

    190.redis 分布式锁有什么缺陷?

    191.redis 如何做内存优化?

    192.redis 淘汰策略有哪些?

    193.redis 常见的性能问题有哪些?该如何解决?

    十九、JVM

    194.说一下 jvm 的主要组成部分?及其作用?

    195.说一下 jvm 运行时数据区?

    196.说一下堆栈的区别?

    197.队列和栈是什么?有什么区别?

    198.什么是双亲委派模型?

    199.说一下类加载的执行过程?

    200.怎么判断对象是否可以被回收?

    201.java 中都有哪些引用类型?

    202.说一下 jvm 有哪些垃圾回收算法?

    203.说一下 jvm 有哪些垃圾回收器?

    204.详细介绍一下 CMS 垃圾回收器?

    205.新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?

    206.简述分代垃圾回收器是怎么工作的?

    207.说一下 jvm 调优的工具?

    208.常用的 jvm 调优的参数都有哪些?

    本文题目转载自https://mp.weixin.qq.com/s/fxHN3t8w04mI9QVJQkM8bA,答案为博主自己整理

  • 相关阅读:
    vector、list、deque三者比较
    python多线程
    爬虫入门之线程进程协程抓取方法(八)
    爬虫之绘图matplotlib与词云(七)
    python字符串反转 高阶函数 @property与sorted(八)
    爬虫入门之Requests模块学习(四)
    爬虫入门之handler与opener(三)
    mongodb/python3.6/mysql的安装
    nginx配置+uwsgi+负载均衡配置
    [JLOI2016] 成绩比较
  • 原文地址:https://www.cnblogs.com/hwtnet/p/12100362.html
Copyright © 2011-2022 走看看