秋招面经一(蚂蚁、招银)

本想着一次性全部放上来,但是最后发现内容还是有点多,最后想想还是分为5块儿放上来吧~如果有需要的小伙伴可以自取哈!

另外,面试的问题较多,有些问题过于复杂,我就没有把答案写上来,大家可以针对性的搜索答案即可。

有些问题,在多次面试冲重复出现,我就简单的进行合并了,大家按顺序看即可。


实习

蚂蚁金服

一面(2020-4-24)

1、对一个操作数进行多线程操作,如何保证不会出现结果的混乱

可以使用synchronize关键字,对操作数进行加锁,或者使用volatile关键字,使得变量具有可见性。

2、多线程相互之间如何通信?

线程之间的通信可以使用管道pipe进行通信,在Java中对应的就是pipedWriter和pipedReader进行通信,类似于生产者-消费者模式。

  • 信号量:信号量是一个计数器,可以用来控制多个线程对共享资源的访问.,它不是用于交换大批数据,而用于多线程之间的同步.它常作为一种锁机制,防止某进程在访问资源时其它进程也访问该资源.因此,主要作为进程间以及同一个进程内不同线程之间的同步手段.
  • 锁机制:包括互斥锁、条件变量、读写锁
    • 互斥锁提供了以排他方式防止数据结构被并发修改的方法。
    • 读写锁允许多个线程同时读共享数据,而对写操作是互斥的。
    • 条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。
  • 信号量机制(Semaphore):包括无名线程信号量和命名线程信号量
  • 信号机制(Signal):类似进程间的信号处理

线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制。

3、卡夫卡如何保证可靠性:一旦一个挂了,如何保证另一个开始另一个恢复?

kafka的每个分区都有多个副本,如果一个broker宕机了,zookeeper会自动选择另一个副本作为主副本。在选择从副本的时候,使用ISR优先的原则来完成选举。

4、有没有考虑本地缓存对jvm的影响?

本地缓存会占用内存,会影响jvm的可使用内存的大小。

二面(2020-4-27)

1、项目中,分布式部署kafka时,如果保证一个消息不会被多个消费者进行消费?

同一个消费者组内使用的是点到点,避免重复消费;

不同的消费者组之间,是订阅发布者模式。

每个主题内的消费者组,同组中的所有消费者不能订阅相同的分区。

2、tcp4次挥手?

TCP的报文格式如下所示:

图片说明

3次握手过程如下:

  • 第一次握手:客户端发送给服务器建立连接的请求,然后自身进入syn-sent状态,此时有同步号标志位SYN=1,发送的序列长度seq=x,没有确认号。
  • 第二次握手:服务器接收到SYN=1,seq=x的数据报之后,可以了解到这个数据报是一个请求连接的数据报,然后服务器便向客户端进行响应,然后将自己的状态转换为SYN-RCVD。在响应给客户端的数据报中,依旧需要将同步位设置为SYN=1,ACK=1,并且设置对应的确认号ack=x+1,表示下一次客户端可以从x+1的位置开始传输数据,同时也将自己的数据报的长度写入数据报中,seq=y
  • 第三次握手:经过上面的两次握手之后,可以确保网络的通畅,并且建立了一个相对稳定的连接,彼此协商好了发送和接收的窗口大小等参数。此时客户端需要再次给服务器端,表示客户端已经接受到了服务器发送过来的确认连接信息,由于此时已经建立了连接,所以此次的数据包中不需要设置同步位SYN,根据第二次握手的数据报中的seq=y,可以告知服务器一个确认号ack=y+1。同时根据第二次握手的确认号ack=x+1,设置此次发送数据的起始位置为seq = x+1。

经过三次握手之后,客户端与服务器端的连接就建立好了,双方开始正常的发送数据。

为什么要有第三次握手?

假如没有第三次握手过程,仅有两次。可能会出现这么一种情况:客户端第一次发送请求,但是由于网络不通畅,很久还没有到达服务器端,此时客户端会以为数据报丢失,重新发送一个新的请求连接的数据报,然后服务器接收到第二次的连接请求后,就和客户端建立连接。

但是过了一段时间之后,客户端第一次发送的请求连接数据报到达了服务器端,服务器端会做出响应,给客户端发送一个确认报文,然后就以为与客户端建立了连接,开始等待客户端发送数据。

可是客户端已经与服务器端建立了连接,便不会响应服务端第二次发送过来的响应报文,那么服务器端就会以为建立了新的连接,一直等待客户端传送数据,使得服务器端处于浪费资源的状态。

四次挥手过程

  • 第一次挥手:客户端给服务器发送第一次挥手数据报,设置标志位FIN = 1 ,seq = u ,表示客户端请求释放连接。 然后客户端状态转换为FIN-WAIT1
  • 第二次挥手:服务器收到请求释放连接的请求后,做出响应,设置标志位ACK = 1 ,seq = v ,确认号根据第一次挥手请求的seq = u,此时设置为ack = u+1。此时关闭客户端到服务器端发送数据的通道,但是服务器依旧可以向客户端发送数据,此时服务器端的状态更改为CLOSE-WAIT客户端收到数据报之后,状态更改为FIN-WAIT2
  • 第三次挥手:当服务器端将最后的数据也发送完成之后,服务器向客户端发送一个释放连接的请求,标志位FIN=1 , ACK = 1,确认号依旧为ack = u+1 , seq设置为起始位置w。此时服务器状态转换为LAST-ACK
  • 第四次挥手:客户端收到数据报文后,给服务器端响应一个确认报文,此时的标志位ACK=1,seq = u+1 , ack = w+1。此时客户端也进入等待状态,等待一段时间之后,再关闭,改变状态为closed

为什么第四次挥手后,客户端不立即关闭?

假如第四次挥手的数据报在传输过程中丢失,那么服务器端将无法收到第四次挥手的报文,就会重新发送第三次挥手的报文给客户端,此时的客户端收到重新发送过来的挥手报文,会重新给服务器端发送第四次的挥手报文。

假如说客户端在发送完第四次挥手报文之后,立即关闭。那么上述情况发生之后,服务器端将无法收到关闭连接的确认请求,将会不断的向客户端发送第三次挥手请求,同时,客户端已经关闭,无法响应,那么服务器端将会一直处于LAST-ACK状态中,将永远无法释放此次的连接。

3、在客户端检测到服务器端进行了连接重置,一般是什么原因造成的?

4、数据库底层为什么要用B+树,B+树有什么优势?

B+树是把所有的数据都存储在叶子节点中,每个叶子节点都会有一个页表,对应着叶子节点中的每条数据的索引值。

B+树的优点是,高度低,每次在非叶子节点做判断的时候,就可以直接知道下一次要前往哪个子节点去。由于树的高度低,并且所有的数据都是存放在硬盘中,这样就会使得我们把数据从硬盘读取到内存中的次数较少,提高效率。

5、数据库如何保证事务的一致性的?

在数据库的底层,会有一个undo.log和一个redo.log,在宕机之后,会从这两个log文件中进行恢复操作。与此同时在innodb中还会有MVCC来保证并发性更改数据同步。

在mysql中使用wal的方式进行数据存储,所有的数据在写入之前,首先将命令写入到redo.log文件中。开机时,会检查磁盘中的文件与redo.log的文件中记录的数据是否一致。在使用undo.log文件的时候,使用的就是撤销操作,对每次的操作命令记录其对应的逆操作命令,比如:add命令,就对应着delete命令,在事务内部依次执行即可保证事务的原子性。

6、如何理解OS中的进程,java中的线程,还有一个协程?

  • 进程:进程是表示资源分配的基本单位,又是调度运行的基本单位。例如,用户运行自己的程序,系统就创建一个进程,并为它分配资源,包括各种表格、内存空间、磁盘空间、I/O设备等。然后,把该进程放人进程的就绪队列。进程调度程序选中它,为它分配CPU以及其它有关资源,该进程才真正运行。所以,进程是系统中的并发执行的单位。
  • 线程:线程是进程中执行运算的最小单位,亦即执行处理机调度的基本单位。如果把进程理解为在逻辑上操作系统所完成的任务,那么线程表示完成该任务的许多可能的子任务之一。例如,假设用户启动了一个窗口中的数据库应用程序,操作系统就将对数据库的调用表示为一个进程。假设用户要从数据库中产生一份工资单报表,并传到一个文件中,这是一个子任务;在产生工资单报表的过程中,用户又可以输人数据库查询请求,这又是一个子任务。这样,操作系统则把每一个请求――工资单报表和新输人的数据查询表示为数据库进程中的独立的线程。线程可以在处理器上独立调度执行,这样,在多处理器环境下就允许几个线程各自在单独处理器上进行。操作系统提供线程就是为了方便而有效地实现这种并发性。
  • 多线程调度:
    • 协同式(协程):线程的执行时间由线程本身来控制,只有当线程把自己的任务做完了,才会通知系统切换到另外的一个线程上去。
    • 抢占式:每个线程的使用时间由系统来分配,线程的切换不由线程本身来决定

7、java中如何结束线程的方式有哪些?

①使用标志位的方式使得整个线程运行完run方法

②使用interrupt()方法中断当前线程

③直接使用stop方法,但是这种方法目前已经被弃用,是一种安全的方法,类似于直接断电的方式

8、jvm中的垃圾回收算法有哪些?

标记复制,标记整理,标记清除

9、当客户端访问浏览器的时候,应该采取什么样的垃圾回收算法?

9、jvm的双亲委派机制?

具体的流程在下面的这种图中,当加载一个类的时候,首先是将其交给父类加载器进行加载,如果父类加载器无法加载,然后再依次向下进行传递。

在jvm规范中,只分为两类类加载器,第一类是系统类加载器:启动类加载器(由c编写)。第二类是用户类加载器:除了启动类加载器都属于这一类。

优势:

  • 防止重复加载同一个.class。通过委托去向上面问一问,加载过了,就不用再加载一遍。保证数据安全。
  • 保证核心.class不能被篡改。通过委托方式,不会去篡改核心.clas,即使篡改也不会去加载,即使加载也不会是同一个.class对象了。
  • 不同的加载器加载同一个.class也不是同一个Class对象。这样保证了Class执行安全。

图片说明

10、接口的保护限流机制如何实现? 比如规定一个接口1秒内只能进行5万次访问

在Redis中可以使用一个队列来实现限流操作。比如每来一次请求,查看队首的时间,如果队首时间与当前时间间隔超过1秒,则移除队首元素,把当前元素添加在尾部,如果间隔不到一秒,再判断队列中的请求个数,如果没有超过5万,则加入队列,否则阻塞等待,否则。

11、hashMap是线程不安全的,ConcurrentHashMap是线程安全的,如何保证的?

java中的免锁容器主要实现的原理是:对容器的修改可以与读取操作同时发生。

concurrentHashMap使用的是分段锁的技术,保证读取时可以有较高的速度,并在写的时候利用写时复制技术,保证整体的线程安全。

12、hashMap和treeMap的区别,分别适应什么情况下进行选择?

treeMap中的键值对是有序存储(此处的有序是指按照自然序进行排序)。

hashmap中是无序的。

13、hashMap中的hash算法如何避免键的冲突问题。

hash碰撞无论是什么算法都是无法完全避免的,只能使用好的hash算法来降低hash碰撞的次数。

当发生hash碰撞的时候,hashmap使用的是散列表(数组+链表)的方式来进行解决,在jdk1.8之后,还加入了红黑树来提升效率。

14、了解哪些互联网的大佬?

王坚(阿里云创始人),多隆,褚霸,吴翰清

15、平时学习的方式?

一面(来自朋友)

16、谈一下Arraylist和Linkedlist的区别?

ArrayList 底层实现就是数组,且ArrayList实现了RandomAccess,表示它能快速随机访问存储的元素,通过下标 index 访问,数组支持随机访问, 查询速度快, 增删元素慢;
LinkedList 底层实现是链表, LinkedList 没有实现 RandomAccess 接口,链表支持顺序访问, 查询速度慢, 增删元素快.

17、Arraylist和Linkedlist查询和增删操作的时间复杂度分别是多少?

Arraylist 根据下标查询,顺序存储知道首个元素的地址,其他的位置很快就能确定,时间复杂度为O(1);
Linkedlist 从首个元素开始查找,直到查找到第 i个位置,时间复杂度为O(n);

Arraylist插入指定位置元素,后面元素需要向后移动,时间复杂度为O(n);
Linkedlist插入指定位置元素,直接指针操作(设置前驱结点和后驱节点)时间复杂度为O(1);

Arraylist删除指定位置元素,后面元素需要向前移动,时间复杂度为O(n);
Linkedlist删除指定位置元素,直接指针操作(将前驱结点和后驱结点相连),时间复杂度O(1);

18、Arraylist底层实现是数组,容量不够怎么办?

容量不够,首先创建一个新的容量数组,再将原来数组复制到新的数组中去,释放旧数组。

19、Linklist查询时间复杂度O(n)有没有什么方法优化?

传进来的索引小于集合size/2就从头节点开始遍历查询,反之从尾节点反向遍历查询;

20、谈一下tcp协议和三次握手?

TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。数据传输时,应用程序向TCP层发送数据流,TCP就会将接受到的数据流切分成报文段(会根据当前网络环境来调整报文段的大小),然后经过下面的层层传递,最终传递给目标节点的TCP层。为了防止丢包,TCP协议会在数据包上标有序号,对方收到则发送ACK确认。未收到则重传。

这个步骤就是我们通常所说的TCP建立连接的三次握手。同时TCP会通过奇偶校验和的方式来校验数据传输过程中是否出现错误。

第一次握手:当客户端需要去建立连接时,客户端就会发送SYN包(seq=x)到服务器,然后客户端进入SYN_SEND的状态,代表已经发SYN包过去, 并且在等待服务器确认。此时ACK=0,SYN=1,这时候由于才第一次握手,所以没有ACK标志。
第二次握手:服务器收到SYN包,就会进行确认,由上面的标志位介绍我们可以知道SYN是表示同步序号,这时候会使得ack=x+1, 然后服务器也会像客户端发送一个SYN包(seq=y),这时候也就是服务器会发送SYN+ACK包,来表示服务器确认到了客户端的一次握手并且二次握手建立,此时服务器进入SYN_RECV状态。此时SYN=1,ACK=1,这时候由于是第二次握手,所以就会有一个服务器给客户端的确认标志。
第三次握手:客户端收到服务器的SYN+ACK包,然后就会像服务器发送确认包ACK(ack=k+1)和seq=x+1,等到这个包发送完毕之后,客户端和服务器就会进入ESTABLISHED状态,完成三次握手,而后就可以在服务端和客户端之间传输数据。此时SYN标志位已经不需要,因为当我们发送ACK标志位的时候代表三次握手成功,已经建立完连接了,接下来可以传送数据过去了。


提前批

招商银行

一面(2020-7-7)

二面(2020-714)

1、项目缓存中如何保证消息一直是最新的。

我们在发布或者修改一个帖子的时候,会使用kafka来监听,告诉elasticsearch进行写入操作,通过这种方式来保证我们elasticsearch可以进行实时的搜索。

2、kafka同一个消费者组如何保证不会重复消费。

kafka同时支持两种消息投递模式:

  • 对于消费者组内而言,所有消息会被均衡的投递给每一个消费者,即每条消息只会被一个消费者处理,相当于点对点模式
  • 对于不同的消费者组,消息会被广播给每一个消费者组,相当于发布、订阅模式

3、项目中的elasticsearch用什么做的索引

我们是将帖子的内容content和帖子的标题title作为索引。具体如下所示:

package com.nowcoder.community.entity;

import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;

import java.util.Date;

//@Document注解用于配置elasticSearch的内容,依次为:索引名称,类型,分片数量,副本数量
@Document(indexName = "discusspost", type = "_doc", shards = 6, replicas = 3)
public class DiscussPost {

    @Id
    private int id;

    @Field(type = FieldType.Integer)
    private int userId;

    //第二个analyzer,是存储拆分器,将存入的内容,尽可能查分成为多个词语
    //第三个属性searchAnalyzer,是搜索拆分器,智能的将搜索内容查分成具有较好语义的几个词语
    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
    private String title;

    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
    private String content;

    @Field(type = FieldType.Integer)
    private int type;

    @Field(type = FieldType.Integer)
    private int status;

    @Field(type = FieldType.Date)
    private Date createTime;

    @Field(type = FieldType.Integer)
    private int commentCount;

    @Field(type = FieldType.Double)
    private Double score;

    @Override
    public String toString() {
        return "DiscussPost{" +
                "id=" + id +
                ", userId='" + userId + '\'' +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", type=" + type +
                ", status=" + status +
                ", createTime=" + createTime +
                ", commentCount=" + commentCount +
                ", score=" + score +
                '}';
    }
}

3、线程池的几个参数,会一开始就创建核心线程数量么?

线程池一开始不会创建核心线程数量,而是没来一个任务,就创建一个线程。

这里需要注意一点,在线程池中的线程数量尚未达到核心线程数量之前,每次来一个任务,不管此时有没有空闲的可用线程,线程池都会新创建一个线程来给新任务使用。

线程池创建的7大参数我们直接找到源码,如下所示:

    /**
     * Creates a new {@code ThreadPoolExecutor} with the given initial
     * parameters.
     *
     * @param corePoolSize the number of threads to keep in the pool, even
     *        if they are idle, unless {@code allowCoreThreadTimeOut} is set
     * @param maximumPoolSize the maximum number of threads to allow in the
     *        pool
     * @param keepAliveTime when the number of threads is greater than
     *        the core, this is the maximum time that excess idle threads
     *        will wait for new tasks before terminating.
     * @param unit the time unit for the {@code keepAliveTime} argument
     * @param workQueue the queue to use for holding tasks before they are
     *        executed.  This queue will hold only the {@code Runnable}
     *        tasks submitted by the {@code execute} method.
     * @param threadFactory the factory to use when the executor
     *        creates a new thread
     * @param handler the handler to use when execution is blocked
     *        because the thread bounds and queue capacities are reached
     * @throws IllegalArgumentException if one of the following holds:<br>
     *         {@code corePoolSize < 0}<br>
     *         {@code keepAliveTime < 0}<br>
     *         {@code maximumPoolSize <= 0}<br>
     *         {@code maximumPoolSize < corePoolSize}
     * @throws NullPointerException if {@code workQueue}
     *         or {@code threadFactory} or {@code handler} is null
     */
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = (System.getSecurityManager() == null)
            ? null
            : AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

4、hashMap数据结构,不安全如何保证的。

(1)数组+链表+红黑树。

(2)安全问题有两个:

  • A、B线程都去put值的时候,发生hash碰撞,然后同时将对应的数组中的next指针指向自己,这样就会导致有一个线程的插入值被覆盖
  • 在对数组进行重新resize的时候,A、B线程都在进行transfer方法,在transfer方法之后只会有一个线程对结果生效,假如A、B线程都对resize之后的链表中插入了值,那么将会导致有一个线程插入的值失效。

(3)死锁问题

在1.8之前,在使用transfer的时候使用头插法,也就是链表的顺序会翻转,这样在A线程插入到一半时临时挂起,此时B线程同时也去更改,这样就会产生一种循环链表的问题。造成最后的死循环。

在jdk1.8之后,改用了尾插法,使得转移前后链表中的元素顺序不会发生改变,所以就解决了死锁问题。

5、concurrentHashMap的如何保证安全的

1.7版本:segment+hashEntrys

1.8版本:散列表+红黑树

首先使用分段锁+cas算法+volatile,实现整体的不加锁。在put方法的时候,首先检查是否已经初始化,如果没有初始化,则进行初始化工作,然后使用rehash对键的hash值进行再散列,然后使用(n-1)& hash值,获取元素所在table的位置。

get方法不加锁,直接获取,我们可以发现,Node节点是重写的,设置了volatile关键字修饰,致使它每次获取的都是最新设置的值。

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    volatile V val;
    volatile Node<K,V> next;

    Node(int hash, K key, V val) {
        this.hash = hash;
        this.key = key;
        this.val = val;
    }
    ....
}

一面(来自朋友)

1、网络传输层和应用层分别有哪些协议?以及之间的区别

网络传输层:TCP/UDP

应用层:http/dns/stmp/pop3

2、http有哪些方法

https://www.cnblogs.com/yinrw/p/10694474.html

  • get:GET方法用于使用给定的URI从给定服务器中检索信息,即从指定资源中请求数据。使用GET方法的请求应该只是检索数据,并且不应对数据产生其他影响。GET请求是可以缓存的,我们可以从浏览器历史记录中查找到GET请求,还可以把它收藏到书签中;且GET请求有长度限制,仅用于请求数据(不修改)。

    【注】因GET请求的不安全性,在处理敏感数据时,绝不可以使用GET请求。

    在GET请求的URL中发送查询字符串(名称/值对),需要这样写:
    /test/demo_form.php?name1=value1&name2=value2
  • post:POST方法用于将数据发送到服务器以创建或更新资源,它要求服务器确认请求中包含的内容作为由URI区分的Web资源的另一个下属。POST请求永远不会被缓存,且对数据长度没有限制;我们无法从浏览器历史记录中查找到POST请求。

  • head:HEAD方法与GET方法相同,但没有响应体,仅传输状态行和标题部分。这对于恢复相应头部编写的元数据非常有用,而无需传输整个内容。

  • put:PUT方法用于将数据发送到服务器以创建或更新资源,它可以用上传的内容替换目标资源中的所有当前内容。它会将包含的元素放在所提供的URI下,如果URI指示的是当前资源,则会被改变。如果URI未指示当前资源,则服务器可以使用该URI创建资源。

  • delete:DELETE方法用来删除指定的资源,它会删除URI给出的目标资源的所有当前内容。

  • connect:CONNECT方法用来建立到给定URI标识的服务器的隧道;它通过简单的TCP / IP隧道更改请求连接,通常实使用解码的HTTP代理来进行SSL编码的通信(HTTPS)。

  • options:OPTIONS方法用来描述了目标资源的通信选项,会返回服务器支持预定义URL的HTTP策略。

  • trace:TRACE方法用于沿着目标资源的路径执行消息环回测试;它回应收到的请求,以便客户可以看到中间服务器进行了哪些(假设任何)进度或增量。

3、Restful接口你知道吗?

按照请求的目的的不同,我们将每种功能的请求区分开,比如使用get请求做索引,put请求刷新,post请求做增加等等

4、Cookie和Session的区别?cookie和token有什么区别?

cookie存放在客户端,不安全,存量小,

session存放在服务器端,安全,存量大

token将用户信息进行加密作为令牌进行网络传输

5、MyBatis框架和面向对象的ORM的数据库插件的区别?

http://www.mybatis.cn/archives/764.html

ORM是Object和Relation之间的映射,包括Object->Relation和Relation->Object两方面。Hibernate是个完整的ORM框架,而MyBatis完成的是Relation->Object,也就是其所说的Data Mapper Framework。

JPA是ORM框架标准,主流的ORM框架都实现了这个标准。MyBatis没有实现JPA,它和ORM框架的设计思路不完全一样。MyBatis是拥抱SQL,而ORM则更靠近面向对象,不建议写SQL,实在要写,则推荐你用框架自带的类SQL代替。MyBatis是SQL映射框架而不是ORM框架,当然ORM和MyBatis都是持久层框架。

6、Redis为什么是单线程的?解释一下Redis的多路复用?多路复用存入格式为什么更好。

7、线程和进程的区别

进程属于系统中的概念,属于操作系统分配给每个执行程序的最小资源单位,一段执行代码运行起来之后叫做进程。进程中包括了系统的内存空间,寄存器等等信息。

线程属于进程中的最小执行单元,一个进程包括有多个线程,线程是除了进程中的内存空间,其他变量信息以外的东西。

8、Java多线程了解哪些类和关键字?解释一下具体

创建方式:Thread,Runnable,Callable

9、 Volatile是干嘛的?synchronized在哪些地方可以使用?

  • volatile的特性:

    • 可见性:每次使用数据前,从内存中读取到自己的工作空间中。

    • 禁止重排序:对使用volatile关键字的变量在操作的前后会加内存屏障,达到禁止指令重排序的效果

    • 不保证原子性:

      图片说明

  • synchronized

    • 可以在方法内部的代码块中:此时在字节码层面上会有一个monitor变量来记录当前代码块是否有线程在使用,如下反编译的部分代码

      3: monitorenter  //进入同步方法
      //..........省略其他  
      15: monitorexit   //退出同步方法
    • 修饰整个方法:在字节码层面上,在方法的头部增加了一个标志位ACC_SYNCHRONIZED,每当有线程进入的时候,会首先检查该标志位是否已经被访问

        public synchronized void syncTask();
          descriptor: ()V
          //方法标识ACC_PUBLIC代表public修饰,ACC_SYNCHRONIZED指明该方法为同步方法
          flags: ACC_PUBLIC, ACC_SYNCHRONIZED
          Code:
            stack=3, locals=1, args_size=1
               0: aload_0
               1: dup
               2: getfield      #2                  // Field i:I
               5: iconst_1
               6: iadd
               7: putfield      #2                  // Field i:I
              10: return
            LineNumberTable:
              line 12: 0
              line 13: 10

10、 Java有几类线程池?

总共4类,如下所示:

ExecutorService service = Executors.newFixedThreadPool(5);// 固定容量的线程池
ExecutorService service = Executors.newSingleThreadExecutor();// 容量为1的线程
ExecutorService service = Executors.newCachedThreadPool();//根据当前任务量自动调节池中线程数

ScheduledExecutorService service = Executors.newScheduledThreadPool(5);//定时任务的线程池

11、死锁的四个必要条件。

  • 资源互斥条件
  • 请求与保持条件
  • 不可抢占
  • 循环等待

12、String是线程安全的吗?ArrayList是线程安全的吗?

String 安全,被final修饰,当我们写如下代码的时候:

String a = "anc";
String b = "efg";
String c = a + b;

上面的代码将两个字符串相连时,底层是使用了StringBuilder类来进行转换。

ArrayList不安全,可以使用CopyOnWriteArrayList这个类是安全的。

13、线程同步的知识:多线程怎么协作?子线程如果想要返回数据给父线程(Java具体类return),对一个子线程中断会直接响应吗(在sleep和不在sleep时各有什么响应)

线程通信方式:

  • 锁机制
  • 信号量机制
  • 信号机制
  • volatile关键字
  • wait/notify

14、MySQL的引擎你了解哪些?

两种。myisam和innodb

15、Innodb的索引用的是什么?索引的数据结构是什么?B+树。B+树的特点?叶子节点之间还有什么特点?

16、A和B建立一个联合索引,什么规则?where A = *** and B like *** and C = ***这段联合索引哪些位置会用到索引?

只有A = *** 会使用到

17、四种隔离级别,分别解决了什么问题?幻读解决了什么问题,幻读用什么锁技术来解决?

隔离级别:

  • 读未提交:什么问题都没解决
  • 读已提交:解决脏读问题
  • 可重复读:解决不可重复读
  • 序列化:解决幻读

幻读使用的是间隙锁:gap lock + next key lock 解决

18、MySQL调优的所有手段?尽可能的说

19、拆分表一般怎么拆?有两种方法

20、索引建多了会带来什么问题?

因为每次都要更新索引,时间复杂度较大,占用内存较多。会额外的增加IOP频率

21、一张表有性别和年龄两个字段,要查询每个性别的平均年龄。这个SQL怎么写?涉及到SQL的一个关键字

22、Spring用过哪些设计模式?有哪些?

https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485303&idx=1&sn=9e4626a1e3f001f9b0d84a6fa0cff04a&chksm=cea248bcf9d5c1aaf48b67cc52bac74eb29d6037848d6cf213b0e5466f2d1fda970db700ba41&token=1667678311&lang=zh_CN#rd

单例模式,代理模式,工厂模式、模板方法模式、观察者

23、Java的HashSet底层是怎么实现的?

使用的是hashMap进行实现的

24、HashMap的key存的是什么?

HashCode的String值

25、写一个快排的代码。

全部评论

相关推荐

10-25 00:32
香梨想要offer:感觉考研以后好好学 后面能乱杀,目前这简历有点难
点赞 评论 收藏
分享
1 5 评论
分享
牛客网
牛客企业服务