各大公司Java面试题收录含答案(整理版)

  本文分为17个模块,分别是:Java基础、容器、多线程、反射、对象拷贝、Java web、异常、网络、设计模式、算法、Spring/Spring MVC、Spring Boot/Spring Cloud、Hibernate、MyBatis、MySQL、Redis、JVM。

1. Java基础

1. JDK和JRE有什么区别?

答:

  JDK:Java Development Kit的简称,Java开发工具包,提供了Java的开发环境和运行环境。

  JRE:Java Runtime Environment的简称,Java运行环境,为Java的运行提供了所需环境。

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

答:

  对于基本类型和引用类型 == 的作用效果是不同的,如下所示:

  基本类型:比较的是值是否相同;

  引用类型:比较的是引用是否相同;

  ==对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而equals默认情况下是引用比较,只是很多类重写了equals方法,比如String、Integer等把它变成了值比较,所以一般情况下equals比较的是值是否相等。

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

答:

  ①普通类不能包含抽象方法,抽象类可以包含抽象方法。

  ②抽象类是不能被实例化的,就是不能用new调出构造方法创建对象,普通类可以直接实例化。

  ③如果一个类继承于抽象类,则该子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为abstract类。

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

答:

  不能,定义抽象类就是让其他类继承的,如果定义为final该类就不能被继承,这样彼此就会产生矛盾,所以final不能修饰抽象类。

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

答:

  实现:抽象类的子类使用extend来继承;接口必须使用implements来实现接口。

  构造函数:抽象类可以有构造函数;接口不能有。

  实现数量:类可以实现很多个接口;但只能继承一个抽象类。

  访问修饰符:接口中的方法默认使用public修饰;抽象类中的抽象方法可以使用Public和Protected修饰,如果抽象方法修饰符为Private,则报错:The abstract method 方法名 in type Test can only set a visibility modifier,one of public or protected。

6. 两个Integer的引用对象传给一个swap方法在方法内部交换引用,返回后,两个引用的值是否会发现变化?

答:

  线程对变量的所有操作(读取、赋值)都必须在工作内存中进行,而不能直接读写主内存中的变量。在swap方法内部交换引用,只会交换线程的工作内存中持有的方法参数,而工作内存中的方法参数是主内存中变量的副本,因此执行这样的swap方法不会改变主内存中变量的指向。

public class ExchangeInteger{

    public static void main(String[] args){
        int A = 2;
        int B = 3;
        swap(A,B);
        System.out.println("A:" + A +"\nB:" + B);
    }
    public static void swap(int A,int B){
        int C = A;
        B = C;
        A = B;
    }
}

结果为:
A:2
B:3

6. String属于基础的数据类型吗?Java中的几种基本数据类型是什么,各自占用多少字节?

答:

  String不属于基础类型,基础类型有8种:byte、short、int、long、float、double、char、boolean,而String属于对象。

  int    32bit / short 16bit 

  long 64bit / byte  8bit

  char 16bit / float  32bit

  double 64bit / boolean 1bit

7. String,StringBuffer,StringBuilder的区别是什么?String为什么是不可变的?

答:

  ①String是字符串常量,StringBuffer和StringBuilder都是字符串变量。后两者的字符内容可变,而前者创建后内容不可变。

  ②String不可变是因为在JDK中String类被声明为一个final类。

  ③StringBuffer是线程安全的,而StringBuilder是非线程安全的。

  ④执行速度:StringBuilder > StringBuffer > String

  注意:线程安全会带来额外的系统开销,所以StringBuilder的效率比StringBuffer高。所以单线程环境下推荐使用StringBuilder,多线程环境下推荐使用StringBuffer。

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

答:

  不一样,因为内存的分配方式不一样。String str = "i"的方式,Java虚拟机会将其分配到常量池中,如果常量池中有"i",就返回"i"的地址,如果没有就创建"i",然后返回"i"的地址;而String str = new String("i")则会被分到堆内存中新开辟一块空间。

9. sting s=new string("abc")分别在堆栈上新建了哪些对象?

答:

  栈:string s。

  堆:new String("abc")

  字符串池(方法区):"abc"

  JVM中存在着一个字符串池,使用引号 创建文本的方式的String对象都会放入字符串池,可以提高效率。

  String a = "abc";String b = "abc";//这两句在字符串池,只创建一个实例对象。

  String a = "ab" + "cd";//这一句在字符串池创建三个实例对象。

  new 方式新建String对象则不会放入字符串池,放入堆。

9. 如何将字符串反转?

答:

  使用StringBuilder或者stringBuffer的reverse()方法。

// StringBuffer reverse
StringBuffer stringBuffer = new StringBuffer();
stringBuffer. append("abcdefg");
System. out. println(stringBuffer. reverse()); // gfedcba
// StringBuilder reverse
StringBuilder stringBuilder = new StringBuilder();
stringBuilder. append("abcdefg");
System. out. println(stringBuilder. reverse()); // gfedcba

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

答:

  ①indexOf():返回指定字符的索引;

  ②charAt():返回指定索引处的字符;

  ③replace():字符串替换;

  ④trim():去除字符串两端空白;

  ⑤split():分割字符串,返回一个分割后的字符串数组;

  ⑥getBytes():返回字符串的byte类型数组;

  ⑦length():返回字符串长度;

  ⑧toLowerCase():将字符串转成小写字符;

  ⑨toUpperCase():将字符串转成大写字符;

  ⑩subString():截取字符串;

  ⑪equals():字符串比较;

11. final在Java中有什么作用?

答: 

  ①final修饰的类叫最终类,该类不能被继承。

  ②final修饰的方法不能被重写。

  ③final修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。

12. Java中IO流分为几种?

答:

  ①按功能来分:输入流(input)和输出流(output)。

  ②按类型来分:字节流和字符流。

  ③字节流和字符流的区别是:字节流按8为传输以字节为单位输入输出数据,字符流按16位传输以字符为单位输入输出数据。

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

答:

  ①BIO:Block IO同步阻塞IO,就是我们平常使用的传统IO,它的特点是模式简单使用方便,并发处理能力低。

  ②NIO:New IO同步非阻塞IO,就是传统IO的升级,客户端和服务器通过Channel(通道)通讯,实现了多路复用。

  ③AIO:Asynchronous IO是NIO的升级,也叫NIO2,实现了异步非堵塞IO,异步IO的操作基于事件和回调机制。

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

答:

  ①Files.exists():检测文件路径是否存在。

  ②Files.createFile():创建文件。

  ③Files.createDirectory():创建文件夹。

  ④Files.delete():删除一个文件或目录。

  ⑤Files.copy():复制文件。

  ⑥Files.move():移动文件。

  ⑦Files.size():查看文件个数。

  ⑧Files.read():读取文件。

  ⑨Files.write():写入文件。

15. 讲讲类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,当new的时候,他们的执行顺序。

答:

  类的实例化顺序:先静态再父子

  父类静态数据 -> 子类静态数据 -> 父类字段 -> 子类字段 -> 父类构造函数 -> 子类构造函数

16. Java8的ConcurrentHashMap为什么放弃了分段锁,有什么问题吗,如果你来设计,你如何设计。

答:

  jdk8放弃了分段锁而是用了Node锁,减低锁的粒度,提高性能,并使用CAS操作来确保Node的一些操作的原子性,取代了锁。

  但是ConcurrentHashMap的一些操作使用了synchronized锁,而不是ReentrantLock,虽然说jdk8的synchronized的性能进行了优化,但是我觉得还是使用ReentrantLock锁能更多的提高性能。

2. Java集合容器

1. Java容器都有哪些?

答:

  Java容器分为Collection和Map两大类,其下又有很多子类,如下所示:

    Collection
    List
    ArrayList
    LinkedList
    Vector
    Stack
    Set
    HashSet
    LinkedHashSet
    TreeSet
    Map
    HashMap
    LinkedHashMap
    TreeMap
    ConcurrentHashMap
    HashTable

2. Collection和Collections有什么区别?

答:

  Collection是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法,所有集合都是他的子类,比如List、Set等。

  Collections是一个包装类,包含了很多静态方法,不能被实例化,就像一个工具类,比如提供的排序方法:Collections.sort(list)。

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

答:

   List、Set、Map的区别主要体现在两个方面:元素是否有序、是否允许元素重复。   

4. Vector,ArrayList,LinkedList的区别是什么?

答:

  ①Vector、ArrayList都是以类似数组的形式存储在内存中,LinkedList则以链表的形式进行存储。

  ②List中的元素有序、允许有重复的元素,Set中的元素无序,不允许有重复元素。

  ③Vector线程安全,ArrayList、LinkedList线程不安全。

  ④LinkedList适合指定位置插入、删除操作,不适合查找,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找;ArrayList、Vector适合查找,在随机访问的时候效率要高,不适合指定位置的插入、删除操作,因为ArrayList增删操作要影响数组内的其他数据的下标。

  ⑤ArrayList在元素填满容器使会自动扩充容器大小的50%,而Vector则是100%,因此ArrayList更节省空间。

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

答:

  数组转List:使用Arrays.asList(array)进行转换。

  List转数组:使用List自带的toArray()方法。

6. HashTable,HashMap,TreeMap区别?

答:

  ①HashTable线程同步,HashMap非线程同步。

  ②HashTable和HashMap有几个主要不同:线程安全以及速度;HashMap速度比HashTable快。

  ③HashTable不允许<键,值>有空值,HashMap允许<键,值>有空值。

  ④HashTable使用Enumeration,HashMap使用Iterator。

  ⑤HashTable中hash数组的默认大小是11,增加方式的n*2+1,HashMap中hash数组的默认大小是16,之后每次扩充,容量变为原来的2倍。

  ⑥TreeMap能够把它保存的记录根据键排序,默认是按升序排序。

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

答:

  对于在Map中插入、删除、定位一个元素这类操作,HashMap是最好的操作,因为相对而言HashMap的插入会更快,但如果你要对一个key集合进行有序的遍历,那TreeMap是更好的选择。  

8. hashMap的底层实现原理?

答:

  ①hashMap基于hashing原理,我们通过put()和get()方法存储和获取对象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hash值,然后根据hash值找到bucket位置来存储value值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会存储在链表的下一个节点中。HashMap在每个链表节点中存储键值对对象。

  当两个不同的键对象的hashCode相同时,我们称之为hash冲突,HashMap的做法是用链表和红黑树存储相同hash值的value。当hash冲突的个数比较少时,使用链表否则使用红黑树。键对象的equals()方法用来找到键值对。

  ②HashMap的存储结构:数组+链表+红黑树(jdk1.8)

  

  HashMap是一种可以快速存储以及快速查找的键值容器,那么jdk是如何实现HashMap的快速存储和快速查找呢?

  从数组和链表以及二叉查找树这三种数据结构说起:

  1)数组:数组结构是连续的内存地址,数组的部分元素被连续存放在cpu缓存中,利用二分查找法,数组的时间复杂度位低到O(1),可见数组的查询效率是非常高的。但是由于数组的内存占用严重,空间复杂度很高,所以数组的增删操作效率将非常低下。

  2)链表:链表内存地址比较分散,空间复杂度较低,在插入和删除上效率较高。但是内存地址过于分散,导致查询效率大大降低。

  3)二叉树在查询效率上和排序后数组的二分查找效率完全相同,从根节点开始,到下面分支节点左边的永远比父节点的要小,右边的比父节点大。二叉树的元素过于分散,导致空间复杂度过大,在插入和删除上会非常低效。为了解决这个问题,jdk使用了红黑树这种数据结构,而红黑树在时间复杂度上可以做到O(log n)的高效率。

  综合以上三种数据结构的特点,HashMap有效的利用了各个数据结构的长处。

  实现快速存储

  快速存储是链表和红黑树以及无移动添加数组元素的优势。

  HashMap中数组的索引是通过hashCode的无符号右移16位后异或然后取余获得,公式如下

      index = [ (hashCode) ^ (HashCode >>> 16) ] / 数组的长度

  通过这样的计算可以保证数组索引的分散。但是分散并不代表不会出现相同的index,也就是索引冲突(hash冲突)。在遇到索引冲突的时候,HashMap会在该索引的位置生成一个单向链表,将元素放置到next。但是我们知道链表这种数据结构在存储方面高效,但是在查询上会非常低效。所以HashMap在链表元素大于8个的时候,会自动将链表转成红黑树,以达到查询高效,插入也高效的目的。当然,在红黑树中元素个数小于一定数量,也会变回原来的链表结构,jdk设置这个数量为6个。

  这样不管在外围"数组"上还是在"链表"上以及变成"红黑树"这种数据结构,HashMap都能做到快速存储。

  HashMap对数组的扩容触发条件是数组元素达到长度的0.75(75%),使用这样的触发条件jdk是从时间和空间角度上思考的,为了这个条件更加容易被触发,也要考虑到暂用过多内存浪费资源,75%非常理想化的触发条件。

  实现快速查找

  HashMap的外围数组这点毋庸置疑,查找效率绝对不会存在问题。索引冲突变成链表,元素数量仅仅只有8个的链表,查询效率不需要考虑。大于8个元素后变成的红黑树,二叉查找树的查询效率和数组相当,这点也不需要质疑。综合考虑在查询方面HashMap,也做到了快速查找的特性。

9. HashMap、HashTable和ConcurrentHashMap的区别,HashTable和ConcurrentHashMap是如何实现线程安全的?

答:

  ①因为多线程环境下,使用HashMap进行put操作会引起死循环,导致CPU利用率接近100%,所以在并发情况下不能使用HashMap。

  ②HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下,HashTable的效率非常低下。因为当一个线程访问HashTable的同步方法时,其他线程访问HashTable的同步方法时,可能会进入阻塞或者轮询状态。如线程1使用put进行添加元素,线程2不但不能使用put方法添加元素,并且也不能使用get方法来获取元素,所以竞争越激烈效率越低。

  总结:线程安全,效率和容器的大小成正比。容器数据量越大,效率越慢。

  ③由于HashTable效率低下,JDK1.5提出了ConcurrentHashMap替代HashTable。其实ConcurrentHashMap实现线程安全也是通过synchronized关键字来控制代码同步来实现的,不同于HashTable的是ConcurrentHashMap在线程同步上更加细分化,它不会像HashTable那样一把包揽的将所有数据都锁住。ConcurrentHashMap采用分段锁。底层数据结构实现原理和HashMap没什么两样,都是数组+链表+红黑树。

  总结:线程安全,效率相对于不如HashMap,但是和HashTable相比,效率得到很大的提升。

  综合考虑,如果使用线程安全容器,推荐使用ConcurrentHashMap。

 10. 用hashmap实现redis有什么问题

答:

  ①容量问题:HashMap是有最大容量的。

  ②时效问题:redis可以持久化,也可以定时时间;hashmap不可以持久化。

  ③线程并发问题:hashmap不是线程安全的,可能会出现死锁,死循环。

  ④可用ConcurrentHashMap。

11. 遍历hashmap的三种方式

答:

  ①通过HashMap.entrySet键值对集合,再通过迭代器Iterator遍历键值对集合得到key值和value值;

  ②通过HashMap.keySet()获得键的Set集合,遍历键的Set集合iterator()获取值;

  ③通过HashMap.values()得到“值”的集合iterator(),遍历“值”的集合;

12. hashmap如果只有一个写其他全读会出什么问题

答:

  会出现死锁,死循环等问题,因为hashmap不是线程安全的,建议使用ConcurrentHashMap。

13. concurrenhashmap求size是如何加锁的,如果刚求完一段后这段发生了变化该如何处理

答:

  Put等操作都是在单个Segment中进行的,但是ConcurrentHashMap有一些操作是在多个Segment中进行的,比如size操作,ConcurrentHashMap的size操作也采用了一种比较巧的方式,来尽量避免对所有的Segment都加锁。

  Segment中的有一个modCount变量,代表的是对Segment中元素的数量造成影响的操作的次数,这个值只增不减。

  size操作就是遍历了两次Segment,每次记录Segment的modCount值,然后将两次的modCount进行比较,如果相同,则表示期间没有发生过写入操作,就将原先遍历的结果返回,如果不相同,则把这个过程再重复做一次,如果再不相同,则就需要将所有的Segment都锁住,然后一个一个遍历了。

14. ConcurrentHashmap的锁是如何加的?是不是分段越多越好

答:

  ConcurrentHashMap是由Segment数组结构和HashEntry数组结构组成。Segment是一种可重入锁ReentrantLock,在ConcurrentHashMap里扮演锁的角色,HashEntry则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组,Segment的结构和HashMap类似,是一种数组和链表结构,一个Segment里包含一个HashEntry数组,每个HashEntry是一个链表结构的元素,每个Segment守护着一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁。

  

  Java7的segment数量推荐是hardware thread数。ConcurrentHashMap的segment分段数并不是越多越好,根据你并发的线程数量决定,太多会导致性能降低。

15. 有没顺序的Map实现类,如果有,他们是怎么保证有序的。顺序的Map实现类:LinkedHashMap,TreeMap。

答:

  LinkedHashMap是基于元素进入集合的顺序或者被访问的先后顺序排序,TreeMap则是基于元素的固有顺序(由Comparator或者Comparable确定)。

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

答:

  HashSet是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素,因此HashSet的实现比较简单,相关HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成,HashSet不允许重复的值。

16. Array和ArrayList有何区别?

答:

  ①Array可以存储基本数据类型和对象,ArrayList只能存储对象。

  ②Array是指固定大小的,而ArrayList大小是自动扩展的。

  ③Array内置方法没有ArrayList多,比如addAll,removeAll,iteration等方法只有ArrayList有。

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

答:

  相同点:都是返回第一个元素,并在队列中删除返回的对象。

  不同点:如果没有元素remove()会直接抛出NoSuchElementException异常,而poll()会返回null。

18. 迭代器Iterator是什么?

答:

  Iterator接口提供遍历任何Collection的接口。我们可以从一个Collection中使用迭代器方法来获取迭代器实例。迭代器取代了Java集合框架中的Enumeration,迭代器允许调用者在迭代过程中移除元素。

  Iterator的特点是更加安全,因为它可以确保,在当前遍历的集合元素被更改的时候,就会抛出ConcurrentModificationException异常。

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

答:

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

3. Java多线程

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

答:

  并行:多个处理器或多核处理器同时处理多个任务。

  并发:多个任务在同一个CPU核上,按细分的时间片轮流(交替)执行,从逻辑上来看那些任务是同时执行的。

2. 线程和进程的区别?

答:

  一个程序下至少有一个进程,一个进程下至少有一个线程,一个进程下也可以有多个线程来增加程序的执行速度。

3. 守护线程是什么?

答:

  守护线程是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。在Java中垃圾回收线程就是特殊的守护线程。

4. 多线程有几种实现方式?

答:

  有4种,分别是:

  ①继承Thread类;

  ②实现Runnable接口;

  ③实现Callable接口通过FutureTask包装器来创建Thread线程;

  ④通过线程池创建线程,使用线程池接口ExecutorService结合Callable、Future实现有返回结果的多线程。

5. 说一下Runnable和Callable有什么区别?

答:

  Runnable没有返回值,Callable可以拿到有返回值,Callable可以看作是Runnable的补充。

6. 线程有哪些状态?

答:

  线程的6种状态:

  ①初始(NEW):新创建了一个线程对象,但还没有调用start()方法;

  ②运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为"运行"。线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。

  ③阻塞(BLOCKED):表示线程阻塞于锁。

  ④等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。

  ⑤超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。

  ⑥终止(TERMINATED):表示该线程已经执行完毕。

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

答:

  类的不同:sleep()来自Thread,wait()来自Object。

  释放锁:sleep()不释放锁;wait()释放锁。

  用法不同:sleep()时间会自动恢复;wait可以使用notify()/notifyAll()直接唤醒。

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

答:

  notifyAll()会唤醒所有的线程,notify()之后唤醒一个线程。notifyAll()调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池被释放后再次参与竞争。而notify()只会唤醒一个线程,具体唤醒哪一个线程由虚拟机控制。

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

答:

  start()方法用于启动线程,run()方法用于执行线程的运行时代码。run()可以重复调用,而start()只能调用一次。

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

答:

  ①newSingleThreadExecutor():它的特点在于工作线程数目被限制为1,操作一个无界的工作队列,所以它保证了所有任务的都是被顺序执行,最多会有一个任务处于活动状态,并且不允许使用者改动线程池实例,因此可以避免其改变线程数目;

  ②newCachedThreadPool():它是一种用来处理大量短时间工作任务的线程池,具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置的时间超过60秒,则被终止并移出缓存;长时间闲置时,这种线程池,不会消耗什么资源。其内部使用SynchronousQueue作为工作队列;

  ③newFixedThreadPool(int nThreads):重用指定数目(nThreads)的线程,其背后使用的是无界的工作队列,任何时候最多有nThreads个工作线程是活动的。这意味着,如果任务数据超过了活动队列数目,将在工作队列中等待空闲线程出现;如果有工作线程退出,将会有新的工作线程被创建,以补足指定的数目nThreads;

  ④newSingleThreadScheduledExecutor():创建单线程池,返回ScheduledExecutorService,可以进行定时或周期性的工作调度;

  ⑤newScheduledThreadPool(int corePoolSize):和newSingleThreadScheduledExecutor()类似,创建的是个ScheduledExecutorService,可以进行定时或周期性的工作调度,区别在于单一工作线程还是多个工作线程;

  ⑥newWorkStrealingPool(int parallelism):这是一个经常被人忽略的线程池,Java8才加入这个创建方法,其内部会构建ForkJoinPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序;

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

答:

  ①RUNNING;

  ②SHUTDOWN;

  ③STOP;

  ④TIDYING;

  ⑤TERMINATED;

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

答:

  ①execute():只能执行Runnable类型的任务。

  ②submit():可以执行Runnable和Callable类型的任务。

  Callable类型的任务可以获取执行的返回值,而Runnable执行无返回值。

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

答:

  方法一:使用安全类,比如Java.util.concurrent下的类。

  方法二:使用自动锁synchronized。

  方法三:使用手动锁Lock。

14. 什么是死锁?

答:

  

2. volatile关键字的作用?

答:

  volatile字段值在所有的线程和CPU缓存中必须保持同步。简单讲,你读取的volatile关键字修饰的变量看到的随时是自己的最新值,而无关乎哪个线程写入的,线程1中对变量v的最新修改,对线程2是可见的。volatile字段本身保证了可见性,所有线程都能看到共享内存的最新状态。

 

 

 

4. 反射

 

4. JVM

5. 网络编程

6. 算法

1. 二分查找算法

答:

  

总结

【参考资料】

https://blog.csdn.net/youanyyou/article/details/82142014

https://blog.csdn.net/zhanglei082319/article/details/87872156

 https://juejin.im/post/5b97486cf265da0ac669347f#heading-0

https://www.cnblogs.com/kkdn/p/9039601.html

https://www.cnblogs.com/xyfer1018/p/10434827.html

http://blog.sina.com.cn/s/blog_73b4b91f0102xlkm.html

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值