0
点赞
收藏
分享

微信扫一扫

2022金三银四面试总结-Java高级篇

心如止水_c736 2022-04-25 阅读 68

Java面试总结

1.你用过哪些集合类?

Collection

├List

│├LinkedList

│├ArrayList

│└Vector

│ └Stack

└Set

Map

├Hashtable

├HashMap

└WeakHashMap


线程安全

非线程安全

2.你说说 arraylist 和 linkedlist 的区别?

3.HashMap 底层是怎么实现的?还有什么处理哈希冲突的方法?

处理哈希冲突的方法:

1.开放定地址法-线性探测法

2.开放定地址法-平方探查法

3.链表解决-可以用红黑树提高查找效率

1、具有1-5工作经验的,面对目前流行的技术不知从何下手,

需要突破技术瓶颈的。2、在公司待久了,过得很安逸,

但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的。

3、如果没有工作经验,但基础非常扎实,对java工作机制,

常用设计思想,常用java开发框架掌握熟练的。

4、觉得自己很牛B,一般需求都能搞定。

但是所学的知识点没有系统化,很难在技术领域继续突破的。

5. 群号:高级架构群468897908 备注好信息!

6.阿里Java高级大牛直播讲解知识点,分享知识,

多年工作经验的梳理和总结,带着大家全面、

科学地建立自己的技术体系和技术认知!

1234567891011
方法一:static final int hash(Object key) { //jdk1.8 & jdk1.7int h;// h = key.hashCode() 为第一步 取hashCode值// h ^ (h >>> 16) 为第二步 高位参与运算return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}方法二:static int indexFor(int h, int length) { //jdk1.7的源码,jdk1.8没有这个方法,但是实现原理一样的return h & (length-1); //第三步 取模运算}

4.熟悉什么算法,还有说说他们的时间复杂度?

5.ArrayList和Vector的底层代码和他们的增长策略,它们是如何进行扩容的?

6.jvm 原理。程序运行区域划分

7.minor GC 与 Full GC,分别什么时候会触发? 。分别采用哪种垃圾回收算法?简单介绍算法

Minor GC ,Full GC 触发条件

  • Minor GC触发条件:当Eden区满时,触发Minor GC。
  • Full GC触发条件:
  • (1)调用System.gc时,系统建议执行Full GC,但是不必然执行
  • (2)老年代空间不足
  • (3)方法去空间不足
  • (4)通过Minor GC后进入老年代的平均大小大于老年代的可用内存
  • (5)由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小

8.HashMap 实现原理

9.java.util.concurrent 包下使用过哪些

12345
Semaphore semaphore = new Semaphore(1);//critical section semaphore.acquire();...semaphore.release();
1234
Lock lock = new ReentrantLock();lock.lock();//critical section lock.unlock();

10.concurrentMap 和 HashMap 区别

11.信号量是什么,怎么使用?volatile关键字是什么?


12.阻塞队列了解吗?怎么使用

以ArrayBlockingQueue为例,我们先来看看代码:

123456789101112
public void put(E e) throws InterruptedException {if (e == null) throw new NullPointerException();final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {while (count == items.length)notFull.await();enqueue(e);} finally {lock.unlock();}}

从put方法的实现可以看出,它先获取了锁,并且获取的是可中断锁,然后判断当前元素个数是否等于数组的长度,如果相等,则调用notFull.await()进行等待,当被其他线程唤醒时,通过enqueue(e)方法插入元素,最后解锁。

12345678910111213
/*** Inserts element at current put position, advances, and signals.* Call only when holding lock.*/private void enqueue(E x) {// assert lock.getHoldCount() == 1;// assert items[putIndex] == null;final Object[] items = this.items;items[putIndex] = x;if (++putIndex == items.length) putIndex = 0;count++;notEmpty.signal();}

插入成功后,通过notEmpty唤醒正在等待取元素的线程。

13.Java中的NIO,BIO,AIO分别是什么?

1.BIO,同步阻塞式IO,简单理解:一个连接一个线程.BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。

2.NIO,同步非阻塞IO,简单理解:一个请求一个线程.NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。

3.AIO,异步非阻塞IO,简单理解:一个有效请求一个线程.AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。

14.类加载机制是怎样的

从类被加载到虚拟机内存中开始,到卸御出内存为止,它的整个生命周期分为7个阶段,加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸御(Unloading)。其中验证、准备、解析三个部分统称为连接。

15.什么是幂等性

所谓幂等,简单地说,就是对接口的多次调用所产生的结果和调用一次是一致的。

那么我们为什么需要接口具有幂等性呢?设想一下以下情形:

  • 在App中下订单的时候,点击确认之后,没反应,就又点击了几次。在这种情况下,如果无法保证该接口的幂等性,那么将会出现重复下单问题。
  • 在接收消息的时候,消息推送重复。如果处理消息的接口无法保证幂等,那么重复消费消息产生的影响可能会非常大。

16.有哪些 JVM 调优经验

  • 内存参数

参数作用

-Xmx堆大小的最大值。当前主流虚拟机的堆都是可扩展的

-Xms堆大小的最小值。可以设置成和 -Xmx 一样的值

-Xmn新生代的大小。现代虚拟机都是“分代”的,因此堆空间由新生代和老年代组成。新生代增大,相应的老年代就减小。Sun官方推荐新生代占整个队的3/8

-Xss每个线程的堆栈大小。该值影响一台机器能够创建的线程数上限

-XX:MaxPermSize=永久代的最大值。永久代是 HotSpot 特有的,HotSpot 用永久代来实现方法区

-XX:PermSize=永久代的最小值。可以设置成和 -XX:MaxPermSize 一样的值

-XX:SurvivorRatio=Eden 和 Survivor 的比值。基于“复制”的垃圾收集器又会把新生代分为一个 Eden 和两个 Survivor,如果该参数为8,就表示 Eden占新生代的80%,而两个 Survivor 各占10%。默认值为
8-XX:PretenureSizeThreshold=直接晋升到老年代的对象大小。大于这个参数的对象将直接在老年代分配。默认值为0,表示不启用


-XX:HandlePromotionFailure=是否允许分配担保失败。在 JDK 6 Update 24 后该参数已经失效。

-XX:MaxTenuringThreshold=对象晋升到老年代的年龄。对象每经过一次 Minor GC 后年龄就加1,超过这个值时就进入老年代。默认值为15

-XX:MaxDirectMemorySize=直接内存的最大值。对于频繁使用 nio 的应用,应该显式设置该参数,默认值为0

  • GC参数

垃圾收集器参数备注Serial(新生代)-XX:+UseSerialGC虚拟机在 Client 模式下的默认值,打开此开关后,使用 Serial + Serial Old 的收集器组合。Serial 是一个单线程的收集器ParNew(新生代)-XX:+UseParNewGC强制使用 ParNew,打开此开关后,使用 ParNew + Serial Old 的收集器组合。ParNew 是一个多线程的收集器,也是 server 模式下首选的新生代收集器-XX:ParallelGCThreads=垃圾收集的线程数Parallel Scavenge(新生代)-XX:+UseParallelGC虚拟机在 Server 模式下的默认值,打开此开关后,使用 Parallel Scavenge + Serial Old 的收集器组合-XX:MaxGCPauseMillis=单位毫秒,收集器尽可能保证单次内存回收停顿的时间不超过这个值。-XX:GCTimeRatio=总的用于 gc 的时间占应用程序的百分比,该参数用于控制程序的吞吐量-XX:+UseAdaptiveSizePolicy设置了这个参数后,就不再需要指定新生代的大小(-Xmn)、 Eden 和 Survisor 的比例(-XX:SurvivorRatio)以及晋升老年代对象的年龄(
-XX:PretenureSizeThreshold)了,因为该收集器会根据当前系统的运行情况自动调整。当然前提是先设置好前两个参数。Serial Old(老年代)无Serial Old 是 Serial 的老年代版本,主要用于 Client 模式下的老生代收集,同时也是 CMS 在发生 Concurrent Mode Failure 时的后备方案Parallel Old(老年代)-XX:+UseParallelOldGC打开此开关后,使用 Parallel Scavenge + Parallel Old 的收集器组合。Parallel Old 是 Parallel Scavenge 的老年代版本,在注重吞吐量和 CPU 资源敏感的场合,可以优先考虑这个组合CMS(老年代)-XX:+UseConcMarkSweepGC打开此开关后,使用 ParNew + CMS 的收集器组合。-XX:CMSInitiatingOccupancyFraction=CMS 收集器在老年代空间被使用多少后触发垃圾收集-XX:+UseCMSCompactAtFullCollection在完成垃圾收集后是否要进行一次内存碎片整理-XX:CMSFullGCsBeforeCompaction=在进行若干次垃圾收集后才进行一次内存碎片整理

附图:可以配合使用的收集器组合

  • 其他参数

参数作用-verbose:class打印类加载过程-XX:+PrintGCDetails发生垃圾收集时打印 gc 日志,该参数会自动带上 -verbose:gc 和 -XX:+PrintGC-XX:+PrintGCDateStamps / -XX:+PrintGCTimeStamps打印 gc 的触发事件,可以和 -XX:+PrintGC 和 -XX:+PrintGCDetails 混用-Xloggc:gc 日志路径-XX:+
HeapDumpOnOutOfMemoryError出现 OOM 时 dump 出内存快照用于事后分析-XX:HeapDumpPath=堆转储快照的文件路径

17.分布式 CAP 了解吗?

18.Java中HashMap的key值要是为类对象则该类需要满足什么条件?

需要同时重写该类的hashCode()方法和它的equals()方法。

19.java 垃圾回收会出现不可回收的对象吗?怎么解决内存泄露问题?怎么定位问题源?

一般不会有不可回收的对象,因为现在的GC会回收不可达内存。

20.终止线程有几种方式?终止线程标记变量为什么是 valotile 类型?

在定义exit时,使用了一个Java关键字volatile,这个关键字的目的是使exit同步,也就是说在同一时刻只能由一个线程来修改exit的值

21.用过哪些并发的数据结构? cyclicBarrier 什么功能?信号量作用?数据库读写阻塞怎么解决

  • 主要有锁机制,然后基于CAS的concurrent包。
  • CyclicBarrier的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。
  • Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。很多年以来,我都觉得从字面上很难理解Semaphore所表达的含义,只能把它比作是控制流量的红绿灯,比如XX马路要限制流量,只允许同时有一百辆车在这条路上行使,其他的都必须在路口等待,所以前一百辆车会看到绿灯,可以开进这条马路,后面的车会看到红灯,不能驶入XX马路,但是如果前一百辆中有五辆车已经离开了XX马路,那么后面就允许有5辆车驶入马路,这个例子里说的车就是线程,驶入马路就表示线程在执行,离开马路就表示线程执行完成,看见红灯就表示线程被阻塞,不能执行。

22.关于抽象类和接口的关系

23.堆内存和栈内存的区别

24.关于Java文件的内部类的解释?匿名内部类是什么?如何访问在其外面定义的变量?

26.String、StringBuffer与StringBuilder之间区别

27.运行时异常与一般异常有何异同?常见异常

###28.error和exception有什么区别?

###29.Java异常处理机制

12
methodname throws Exception1,Exception2,..,ExceptionN{ }

30.java中有几种方法可以实现一个线程?


123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
class Thread1 extends Thread {private String name;public Thread1(String name) {this.name = name;}@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println(name + "运行--->>>" + i);}}public static void main(String[] args) {Thread1 mTh11=new Thread1("A");Thread1 mTh12=new Thread1("B");mTh1.start();mTh2.start();}}class Thread2 implements Runnable {private String name;private int count = 15;public Thread2() {}public Thread2(String name) {this.name = name;}public void run() {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + "运行 : " + count--);}}public static void main(String[] args) {Thread2 mTh2 = new Thread2();new Thread(mTh2, "C").start();new Thread(mTh2, "D").start();}}class MyCallableThread implements Callable<Integer>{public Integer call() throws Exception {int i = 0;for(;i<100;i++){System.out.println(Thread.currentThread().getName()+" "+i);}return i;}public static void main(String[] args) {MyCallableThread mct = new MyCallableThread();FutureTask<Integer> ft = new FutureTask<Integer>(mct);for(int i = 0;i < 100;i++){System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);if(i==20){new Thread(ft,"有返回值的线程").start();}}try{System.out.println("子线程的返回值:"+ft.get());} catch (InterruptedException e){e.printStackTrace();} catch (ExecutionException e){e.printStackTrace();}}}

31.Java中常用的类,包,接口。

32.java在处理线程同步时,常用方法有:

33.Spring IOC/AOP?

34.对JVM的垃圾回收的认识?

垃圾回收器的作用是查找和回收(清理)无用的对象。以便让JVM更有效的使用内存。

35.进程与线程的区别,及其通信方式

  • 进程间通信
123456
1.管道(Pipe)及有名管道(named pipe2.信号(Signal)3.消息队列(Message)4.共享内存5.信号量(semaphore)6.套接口(Socket)

36.JVM如何GC,新生代,老年代,持久代,都存储哪些东西?

JVM的GC算法有:引用计数器算法,根搜索方法

新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。

在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

持久代主要存放的是Java类的类信息

37.JVM分为哪些区,每一个区干嘛的?

问:Java运行时数据区域?

回答:包括程序计数器、JVM栈、本地方法栈、方法区、堆

问:方法区里存放什么?

本地方法栈:和jvm栈所发挥的作用类似,区别是jvm栈为jvm执行java方法(字节码)服务,而本地方法栈为jvm使用的native方法服务。

JVM栈:局部变量表、操作数栈、动态链接、方法出口。

方法区:用于存储已被虚拟机加载的类信息,常量、静态变量、即时编译器编译后的代码等。

堆:存放对象实例。

38.GC用的引用可达性分析算法中,哪些对象可作为GC Roots对象?

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象;
  • 方法区中类静态属性引用的对象;
  • 方法区中常量引用的对象;
  • 本地方法栈中JNI(即一般说的Native方法)引用的对象

39.用什么工具调试程序?jmap、jstack,JConsole,用过吗?

虚拟机性能监控与调优实战–博客

40.线程池用过吗?

线程池(Thread Pool)对于限制应用程序中同一时刻运行的线程数很有用。因为每启动一个新线程都会有相应的性能开销,每个线程都需要给栈分配一些内存等等。

我们可以把并发执行的任务传递给一个线程池,来替代为每个并发执行的任务都启动一个新的线程。只要池里有空闲的线程,任务就会分配给一个线程执行。在线程池的内部,任务被插入一个阻塞队列(Blocking Queue ),线程池里的线程会去取这个队列里的任务。当一个新任务插入队列时,一个空闲线程就会成功的从队列中取出任务并且执行它。

41.操作系统如何进行分页调度?–要考LRU

12345678910111213141516171819
//扩展一下LinkedHashMap这个类,让他实现LRU算法class LRULinkedHashMap<K,V> extends LinkedHashMap<K,V>{//定义缓存的容量private int capacity;private static final long serialVersionUID = 1L;//带参数的构造器LRULinkedHashMap(int capacity){//调用LinkedHashMap的构造器,传入以下参数super(16,0.75f,true);//传入指定的缓存最大容量this.capacity=capacity;}//实现LRU的关键方法,如果map里面的元素个数大于了缓存最大容量,则删除链表的顶端元素@Overridepublic boolean removeEldestEntry(Map.Entry<K, V> eldest){System.out.println(eldest.getKey() + "=" + eldest.getValue());return size()>capacity;}}

42.讲讲LinkedHashMap

LinkedHashMap是通过哈希表和链表实现的,它通过维护一个链表来保证对哈希表迭代时的有序性,而这个有序是指键值对插入的顺序。

LinkedHashMap 的大致实现如下图所示,当然链表和哈希表中相同的键值对都是指向同一个对象,这里把它们分开来画只是为了呈现出比较清晰的结构。

LinkedHashMap是Hash表和链表的实现,并且依靠着双向链表保证了迭代顺序是插入的顺序。

三个重点实现的函数

在HashMap中提到了下面的定义:

1234567
// Callbacks to allow LinkedHashMap post-actions//1.把当前节点e移至链表的尾部。因为使用的是双向链表,所以在尾部插入可以以O(1)的时间复杂度来完成。并且只有当accessOrder设置为true时,才会执行这个操作。在HashMap的putVal方法中,就调用了这个方法。void afterNodeAccess(Node<K,V> p) { }//2.afterNodeInsertion方法是在哈希表中插入了一个新节点时调用的,它会把链表的头节点删除掉,删除的方式是通过调用HashMap的removeNode方法。通过afterNodeInsertion方法和afterNodeAccess方法,是不是就可以简单的实现一个基于最近最少使用(LRU)的淘汰策略了?当然,我们还要重写removeEldestEntry方法,因为它默认返回的是false。void afterNodeInsertion(boolean evict) { }//3.这个方法是当HashMap删除一个键值对时调用的,它会把在HashMap中删除的那个键值对一并从链表中删除,保证了哈希表和链表的一致性。void afterNodeRemoval(Node<K,V> p) { }

LinkedHashMap继承于HashMap,因此也重新实现了这3个函数,顾名思义这三个函数的作用分别是:节点访问后、节点插入后、节点移除后做一些事情。

43.线程同步与阻塞的关系?同步一定阻塞吗?阻塞一定同步吗?,同步和异步有什么区别?

44.int与Integer的区别,分别什么场合使用

1234
1Integerint提供的封装类,而int是Java的基本数据类型2Integer默认值是null,而int默认值是03、声明为Integer的变量需要实例化,而声明为int的变量不需要实例化;4Integer是对象,用一个引用指向这个对象,而int是基本类型,直接存储数值。

int是基本数据类型,Integer是包装类,类似HashMap这样的结构必须使用包装类,因为包装类继承自Object,都需要实现HashCode,所以可以使用在HashMap这类数据结构中。

45.RPC的详细过程

  • 1)服务消费方(client)调用以本地调用方式调用服务;
  • 2)client stub接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
  • 3)client stub找到服务地址,并将消息发送到服务端;
  • 4)server stub收到消息后进行解码;
  • 5)server stub根据解码结果调用本地的服务;
  • 6)本地服务执行并将结果返回给server stub;
  • 7)server stub将返回结果打包成消息并发送至消费方;
  • 8)client stub接收到消息,并进行解码;
  • 9)服务消费方得到最终结果。
举报

相关推荐

0 条评论