大厂真实面试之面试题(一)

文章目录

      • 1.TCP和UDP的区别,为什么UDP快
      • 2.TCP三次握手和四次挥手的原因
      • 3.Java集合类用的有哪些,说一下各自特点
      • 4.hashmap的底层数据结构
      • 5.hashmap的扩容,put,rehash过程
      • 6.这个链表会一直扩大吗,为什么?红黑树好在哪?红黑树特点(JDK1.8)
      • 7.并发的话你知道哪些锁?
      • 8.那你说下synchronized锁升级过程?每个锁都适用于什么场合?
      • 9.synchronized和lock都是用于什么场合?
      • 10.volatile的原理是什么,实现了什么,怎么实现的?
      • 11.公平锁什么样,非公平的什么样?
      • 12.线程池的参数有哪些?线程销毁是怎么销毁的?
      • 13.线程池的工作原理说一下
      • 14.GC收集算法有哪些?
      • 15.说下CMS工作原理,流程,并发标记的是什么?
      • 16.事务ACID
      • 17.设计模式会吗?你说说工厂,原理、优点、实现代表
      • 18.类加载的过程是什么样的
      • 19.双亲委派好处是什么,类加载器你知道的有什么
      • 20.手写快排

问题的答案都是我个人理解和纯手工编写,如果有写得不好的地方或者写错的地方,还请大佬们多多指出。我先谢过了。

1.TCP和UDP的区别,为什么UDP快

区别

  • TCP是全双工的,面向报文的,传输数据之前先要通过三次握手建立连接,数据传输完毕后需要通过四次挥手断开连接,所以是可靠的
  • TCP对系统资源要求较大,因为头部开销大。
  • UDP是半双工的,面向字节流,传输数据不需要建立连接,所以传输不可靠。

原因

  • TCP传输之前需要建立连接,传输结束后需要断开连接。这个过程需要时间。而UDP传输数据不需要建立连接,所以速度比较快。

2.TCP三次握手和四次挥手的原因

  • TCP三次握手:因为TCP是可靠传输,传输数据之前,客户端和服务端需要建立连接,以保证数据的可靠性。第一次握手,客户端请求服务端。第二次握手,服务端响应客户端。第三次握手,客户端告诉服务端,要开始传输数据了。如果只有两次握手的话,在客户端请求给服务端的过程,如果出现延迟等原因,服务端一段时间没有收到。客户端会在次发出新的一轮请求,但是这时候原来的响应又到了。就会造成数据的丢失和异常。因为网络始终是不可靠的,所以三次握手已经够了。
  • 四次挥手:因为TCP是全双工的,所以第一次挥手,客户端告诉服务端我的数据已经传输完毕了。我要关闭数据发送的通道了。但是,还可以继续接受数据。第二次挥手,服务端响应客户端,回复收到,并等待数据全部接收完毕后关闭服务端的接受数据通道。第三次挥手,服务端数据传输结束,告诉客户端。第四次挥手,客户端数据接收完毕,关闭数据接收通道。

3.Java集合类用的有哪些,说一下各自特点

Java集合类主要有Collection和Map两个顶级接口

  • Collection接口下面有List和Set接口:
    • List接口下面主要有两个实现:ArrayList和LinkedList。
    • Set接扣下面主要有两个实现:HashSet和TreeSet。
  • Map接口下主要有两个实现:HashMap、TreeMap。

特点这儿就省略啦…

4.hashmap的底层数据结构

  • JDK1.7 数组+链表
  • JDK1.8 数组+链表+红黑树

5.hashmap的扩容,put,rehash过程

  • put过程:先计算key的Hash值。判断是否存在当前的key,如果存在,则直接更新value即可(这儿可能会导致数据覆盖问题)。如果不存在,则添加新的key-value。再添加的过程中要判断当前数组所用容量是否超过了阈值(负载因子(默认0.75)*数组容量(默认16))。如果未超过直接添加新的key-value,如果超过,需要扩容。在扩容的过程中,需要重新计算Hash值(rehash)。(JDK1.8号采用原来索引位置+扩容的大小来判断扩容后的key的位置)

6.这个链表会一直扩大吗,为什么?红黑树好在哪?红黑树特点(JDK1.8)

  • 不会,当链表长度超过8,数组长度未到达64时,数组会进行扩容。如果数组长度超过64,并且链表长度超过8 ,链表会转为红黑树。
  • 红黑树的查询效率高,进行查找的时候可以降低时间复杂度。

红黑树特点

  • 每个节点是黑色或者红色。
  • 根节点是黑色。
  • 每个叶子节点(NIL)是黑色。(这里叶子节点,是指为空(NIL或NULL)的叶子节点)
  • 如果一个节点是红色的,则它的子节点必须是黑色的。
  • 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。(这里指到叶子节点的路径)

  • 关于HashMap的更多面试相关知识,可以看我之前的这篇博客:HashMap的前世今生

7.并发的话你知道哪些锁?

  • Synchronized:JVM层面的锁,公平锁,jdk1.6对它做了很大的优化。用于方法,类,代码块。
  • Lock:Java层面的API,实现了synchronised的所有功能,但比Synchronized更好。默认非公平锁,可以改变参数设置为公平锁。它可以手动加锁和解锁。并且更直观。
  • CAS(乐观锁)、Volatile、读写锁等。

8.那你说下synchronized锁升级过程?每个锁都适用于什么场合?

  • 当不存在锁竞争时,synchronized处于无锁状态。当同步线程只有一个线程时,加偏向锁,每次线程访问的时候,判断当前线程是否是原来加偏向锁的线程,如果是直接执行;如果不是,偏向锁升级为轻量级锁(也就是自旋锁),线程不断去重试获取资源。当自旋一段时间时,还无法获取到锁时,转为重量级锁,未获取到锁的线程挂起,等待当前获取到锁的线程执行完毕之后唤醒。

9.synchronized和lock都是用于什么场合?

  • Synchronized可以用于类,方法,代码块。
  • Lock只能用于代码块。

10.volatile的原理是什么,实现了什么,怎么实现的?

原理

  • 观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令。lock前缀指令实际上相当于一个内存屏障(也称内存栅栏),内存屏障会提供3个功能:
    • 它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成;
    • 它会强制将对缓存的修改操作立即写入主存;
    • 如果是写操作,它会导致其他CPU中对应的缓存行无效。

实现了什么

  • volatile实现了线程之间的可见性,禁止指令重排,不保证原子性。

怎么实现的?

  • Java多个线程共享一个变量时,会将主内存中的变量拷贝到线程的工作内存,操作工作内存中的变量。但是由于线程之间不具有可见性,所以当一个线程对变量更改之后,其他线程可能还不知道,所以其他线程继续在原来的变量上面进行更改,就会导致最终的数据出错。当变量用volatile修饰之后,当一个线程对变量进行修改之后,修改之后的变量会实时更新回到主内存中,并且通知其他线程。其他线程立马更新自己工作内存中的变量。

11.公平锁什么样,非公平的什么样?

  • 公平锁中,如果有另一个线程持有锁或者有其他线程在等待队列中等待这个锁,那么新发出的请求的线程将被放入到队列中。
  • 非公平锁中,只有当锁被某个线程持有时,新发出请求的线程才会被放入队列中(此时和公平锁是一样的)。当前的锁状态没有被占用时,当前线程可以直接占用,而不需要判断当前队列中是否有等待线程。

12.线程池的参数有哪些?线程销毁是怎么销毁的?

  • corePoolSize:核心线程数
  • maxinumPoolSize:最大线程数
  • keepAliveTime:线程不执行任务时,保持存活的时间

销毁

  • 设置标志位,使线程正常退出
  • stop() 不推荐使用
  • Interrupt()中断线程

13.线程池的工作原理说一下

  • 当有一个任务发来请求时,线程池会首先判断正在使用的核心线程数是否已经达到最大。如果没有,分配一个线程执行任务。如果已经达到最大,则判断工作队列是否已满,未满添加任务到工作队列。已满的话,判断最大线程数是否已经达到最大,如果没有,则创建一个线程执行任务,执行完即销毁线程。如果当前最大线程已经达到最大,则执行拒绝策略。

14.GC收集算法有哪些?

  • 标记-清除、标记-复制、标记-整理、分代收集

15.说下CMS工作原理,流程,并发标记的是什么?

16.事务ACID

  • 原子性:一个事务是一个不可分割的工作单位,要不全部执行,要不全部不执行。
  • 一致性:事务执行前和后,必须都保持一致性或完整性。
  • 隔离性:一个事务在执行的过程中,不受其他事务的影响。
  • 持久性:当一个事提交后,对数据库的改变是永久性的,不会被回滚。

17.设计模式会吗?你说说工厂,原理、优点、实现代表

18.类加载的过程是什么样的

  • 加载、连接(验证、准备、解析)、初始化

19.双亲委派好处是什么,类加载器你知道的有什么

  • 双亲委派机制能保证多加载器加载某个类时,最终都是由一个加载器加载,确保最终加载结果相同。

类加载器

  • 根类加载器(Bootstrap ClassLoader)
  • 扩展类加载器(Extension ClassLoader)
  • App类加载器
  • 自定义类加载器

20.手写快排

class Solution {
    public int[] sortArray(int[] nums) {
        quickSort(nums,0,nums.length-1);
        return nums;
    }

    private void quickSort(int[] nums,int left,int right){
        int l = left;
        int r = right;
        int mid = left + (right-left)/2;
        int priovt = nums[mid];
        while(l<r){
            while(nums[l]<priovt){
                l++;
            }
            while(nums[r]>priovt){
                r--;
            }
            if(l>=r){
                break;
            }
            swap(nums,l,r);
            if(nums[l]==priovt){
                r--;
            }
            if(nums[r]==priovt){
                l++;
            }
        }
        if(l==r){
            l++;
            r--;
        }
        if(left<r){
            quickSort(nums,left,r);
        }
        if(right>l){
            quickSort(nums,l,right);
        }
    }

    private static void swap(int[] nums,int index1,int index2){
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }
}

有些问题的答案我还没有写,或者说是不完整。主要是因为我还不太掌握相关知识点,等我掌握差不多了,我会以我自己的理解把它陆续完善的。

你知道的越多,你不知道的越多。
有道无术,术尚可求,有术无道,止于术。
如有其它问题,欢迎大家留言,我们一起讨论,一起学习,一起进步

你可能感兴趣的:(java基础)