应聘 Java!看看 JavaSE 面试题?(下)

87 阅读5分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

1. HashMap和Hashtable的区别

  • 相同点:

    • 都实现了Map接口
  • 不同点:

    • HashMap是非线程安全的,Hashtable是线程安全的
    • HashMap允许空键值(null=null),而Hashtable键和值都不能为null
    • 单线程情况下,HashMap的效率要高于Hashtable

2. 什么是线程死锁?

  • 线程死锁是指两个或两个以上线程同时被阻塞,它们互相持有对方所需要的资源,都在等待某个资源被释放,但这些线程只有获取到想要的资源才会释放已占有的资源,这就导致了无限期地阻塞。

    比如说,张三和李四各有一个鼠标和键盘,张三想借用李四的键盘,而李四也想借用张三的鼠标,看似挺好的,但张三和李四都有一个要求,必须对方的借给自己才能将自己的东西借出去。所以,李四就说:你先将鼠标借我,我再把键盘借你;而张三也说:你先将键盘借我,我再把鼠标借你……

3. sleep()和wait()方法的区别?

  • 相同点:

    • 都可以暂停线程的执行
  • 不同点:

    • sleep()方法没有释放锁,而wait()方法会释放锁
    • sleep()方法通常被用于暂停执行,wait()方法通常被用于线程间交互/通信
    • sleep()方法可以设置暂停执行时间,时间到了线程会自动苏醒;而wait()分为无参和有参两种,无参的方法被调用后则需要其它线程调用同一对象上的notify()或者notifyAll()方法才能苏醒,有参的方法超时后线程会自动苏醒

4. 现在有线程 T1、T2 和 T3。你如何确保 T2 线程在 T1 之后执行,并且 T3 线程在 T2 之后执行?

  • 可以使用Thread类的join方法实现

public final void join() throws InterruptedException 等待该线程终止。

5. 线程有哪些基本状态,并描述每种状态?

状态名称说明
初始状态(NEW)表示线程被创建了,但没有调用start()方法,由Java虚拟机为其分配内存并初始化成员变量值
运行状态(RUNNABLE)可以细分为就绪状态(READY)和运行状态(RUNNING)两种状态。 就绪状态:当线程调用start()方法后,线程就处于就绪状态,进入了线程队列排队,但此时线程并未开始执行,仅仅是获得了运行的资格,而运行的时期取决于CPU调度器的调度。 运行状态:表示线程对象被CPU调度器调度了,可以执行线程体。
阻塞状态(BLOCKED)表示正在运行的线程遇到某种特殊情况,比如同步、等待I/O操作完成等。进入阻塞状态的线程让出CPU资源,并暂停自己的执行。
等待状态(WAITING)进入该状态表示当前线程需要等待其它线程做出一些特定动作(比如调用notify、notifyAll方法),才能够重新进入RUNNABLE状态
超时等待状态(TIME_WAITING)与等待状态不同,处于该状态的线程达到设定的时间后可以自行返回
终止状态(TERMINATED)表示当前线程已经执行完毕

img

6. 如何避免线程死锁?

产生死锁有四个条件,分别是互斥条件、请求与保持条件、不剥夺条件、循环等待条件,若要避免死锁,只需要考虑破坏四个条件中的一个即可。

  • 破坏互斥条件:该条件无法被破坏,因为使用锁本来就是为了让线程互斥的,比如临界资源需要互斥访问。
  • 破坏请求与保持条件:让线程一次性申请所有资源。
  • 破坏不剥夺条件:占用部分资源的线程在申请其它资源时,若申请不到,则主动释放自身占用的资源
  • 破坏循环等待条件:申请资源时按顺序进行申请,释放资源时按相反顺序进行释放。

产生死锁的四个条件:

互斥条件:该资源任意时刻都只由一个线程占用

请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放。

不剥夺条件:线程占用的资源在未使用完之前不能被其它线程强行剥夺,只有在自己使用完之后自行释放。

循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。

7. HashMap 和 ConcurrentHashMap 的区别?

  • HashMap是非线程安全的,而ConcurrentHashMap是线程安全的
  • ConcurrentHashMap采用了锁分段技术,将整个Hash进行分段(segment),即将大的数组划分为多个片段,每个片段都有锁的存在。当要在某个片段上插入元素时,需要先获取segment锁。
  • ConcurrentHashMap使锁的粒度更精细一些,并发性能更好。

8. ArrayList的扩容机制?

ArrayList的初始容量为10,当容量不足时,会先创建一个容量为原容量的1.5倍的新数组,然后将旧数组的元素复制到新数组,并将指针指向新数组。

9. 深拷贝和浅拷贝是什么?

  • 深拷贝:对基本数据类型进行值传递,对引用数据类型创建一个新对象,并复制其内容,此为深拷贝。
  • 浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递,此为浅拷贝。