网易Java后端面经(一面)

这是网易的Java一面,问的都很基础。


1.session过期怎么处理?

session过期通常指用户在一段时间内没有进行任何操作而导致session失效。针对这种情况,可以采取以下措施:
1.  前端提示用户session即将过期,提醒其重新登录或者刷新页面维持session;
2.  后端在程序中加入判断,如果session过期,返回错误信息或者让用户重新登录;
3.  增加自动刷新session的机制,例如通过定时器在session即将过期时自动续期。

 2.redis过期时间怎么设置,redis怎么续期?

考的基本命令:

Redis过期时间可以使用命令`EXPIRE  key  seconds`来设置,其中`key`为需要设置过期时间的键名,`seconds`为过期时间,单位为秒。
例如:设置`mykey`键10秒后过期,命令为`EXPIRE  mykey  10`。

Redis续期可以使用命令`EXPIREAT  key  timestamp`,其中`key`为需要续期的键名,`timestamp`为续期时间戳,单位为秒。
例如:将`mykey`键的过期时间延长到10秒后,命令为`EXPIREAT  mykey  1626914136`,其中`1626914136`为10秒后的时间戳。

3.rabbitmq可以多个消费者订阅一个消费者吗?说出实现步骤。

可以,步骤如下: 

1. 创建一个 RabbitMQ 消息队列。

2. 创建多个消费者,并分别从队列中读取消息。

扫描二维码关注公众号,回复: 15297188 查看本文章

3. 通过设置消息队列的 exchange type,将多个消费者绑定到同一个 exchange 上,使得它们能够从同一个消息队列中接收消息。

4. 当消息发布到 exchange 上时,它会被分发到多个消费者中的某一个进行处理。

5. 消费者在处理完消息之后需要向队列确认已经处理完成,以便 RabbitMQ 可以删除该消息。

4. rabbitmq遇到重复下单怎么处理?

如果RabbitMQ遇到重复下单,可以按照以下步骤处理:

1. 在生产者端对下单请求进行幂等性检查,即判断是否已经存在相同的订单请求,如果存在,则直接忽略该请求,不向RabbitMQ发送信息。

2. 在消费者端接收到订单请求时,对订单的状态进行判断,如果订单已经存在,则不再进行处理,直接将订单状态返回给生产者端,告知订单已经存在;如果订单不存在,则进行订单创建、订单状态更新等业务处理,并将订单状态返回给生产者端,告知订单已经成功创建。

3. 如果您的系统中需要保证强一致性,可以使用分布式锁来保证同一时间只有一个消费者进行订单创建和更新操作,以避免多个消费者同时处理同一个订单请求。

 5.redis数据类型,zest实现原理?

Redis支持多种数据类型,包括字符串(string)、哈希(hash)、列表(list)、集合(set)、有序集合(zset)。

zset数据类型,也称作有序集合,是Redis中的一个特殊类型,它在集合基础上增加了一个权重。即每个元素都有一个权重值(score),根据这个权重值进行排序。有序集合使用时需要注意以下几点:

1.有序集合内的元素必须是唯一的。
2.元素存储顺序是按照score从小到大排序的。
3.元素可以根据score进行范围查找。

在Redis中,zset数据类型的底层实现是跳表(skiplist)。跳表是一种基于链表的数据结构,其查询和插入时间复杂度都是O(logn),效率较高。跳表内的每个节点都包含一个score和value,score用于插入和查找时的元素比较和排序,value则作为元素的值。

当用户向zset中添加元素时,Redis会根据元素的score大小将元素插入到跳表中的合适位置。如果具有相同的score,则比较value的大小,如果还相同,再比较value的存储地址。

当用户执行查询操作时,Redis会根据score的范围进行跳表的遍历查询,找到符合查询条件的元素。在常规的链表查询中,遍历的时间复杂度是O(n),而在跳表查询中,由于跳表中的节点不是按顺序排列的,因此其查询时间复杂度可以达到O(logn)。

6.redis淘汰策略

 Redis的淘汰策略可以选择以下几种:

1. Noeviction(不淘汰策略):表示当内存满了之后,Redis的写操作会直接返回内存溢出的错误信息。这种策略适用于不愿意丢失数据,而又能承受短暂的服务中断的场景。

2. Volatile-lru(最近最少使用策略):表示淘汰最近最少使用的那些key,其中Volatile表示只对设置过期时间的key淘汰,不设置过期时间的key不淘汰,适用于缓存场景。

3. Volatile-ttl(过期时间策略):表示淘汰即将过期的那些key,其中Volatile表示只对设置过期时间的key淘汰,不设置过期时间的key不淘汰,适用于缓存场景。

4. Volatile-random(随机淘汰策略):表示随机删除key,但仅限于过期key,适用于无需准确控制淘汰的场景。

5. Allkeys-lru(最近最少使用策略):表示淘汰最近最少使用的那些key,不考虑是否设置过期时间,适用于缓存场景。

6. Allkeys-random(随机淘汰策略):表示随机删除key,不考虑是否设置过期时间,适用于无需准确控制淘汰的场景。

不同的场景选择不同的淘汰策略可以提高Redis的性能和稳定性。

7.MySQL存储引擎

 MySQL存储引擎是基于MySQL数据库系统的一种模块化式架构,它可以提供不同的数据存储和读写支持。

MySQL存储引擎是MySQL交付的时候就内置的,包括MyISAM、InnoDB、MEMORY等多个存储引擎类型,且各个存储引擎有各自独特的特性和优缺点。

比如MyISAM是MySQL最常使用的存储引擎,适合于处理非交互性的查询和读操作,但不适合于高并发的写操作。而InnoDB存储引擎则适合于高并发的读写操作,但不适合于处理查询操作。MEMORY存储引擎可以缓存数据到内存中,可以加快访问速度,但是如果断电或者重启服务器,数据就会丢失。

8.事务隔离级别 

事务隔离级别是数据库系统的一个特性,用于控制多个并发事务之间的可见性和影响范围。常见的四个隔离级别分别是:

1. 读未提交(Read Uncommitted):允许一个事务读取未提交的数据,可能会导致“脏读”问题。

2. 读已提交(Read Committed):要求一个事务只能读取已提交的数据,但是由于读取期间其他事务可能会修改数据,因此可能会导致“不可重复读”问题。

3. 可重复读(Repeatable Read):要求一个事务在执行过程中多次读取相同的数据时,得到的结果应该是一致的。因此,在一个事务内,读取的数据不能被其他事务修改,只有当前事务提交后其他事务才能修改。

4. 串行化(Serializable):要求所有事务依次执行,按顺序访问数据库。这种隔离级别能够避免“幻读”问题,但会降低数据库性能。

 9.jvm中堆和栈还有方法区作用

在Java虚拟机中,堆、栈和方法区是用来管理内存的三个区域,每个区域都有不同的作用。

1. 堆

堆是Java虚拟机中一块存储空间,用于存储Java对象。堆内存是在JVM启动时自动分配的,用于存储所有的Java对象和数组。当一个对象被创建时,它在堆上分配一块内存,而 Java虚拟机负责回收不再使用的内存。堆的特点是动态分配内存,它可以根据需要扩展或收缩大小。

2. 栈

栈是Java虚拟机中的另一个存储区域,用于存储局部变量和方法调用的执行环境。每当一个方法被调用时,Java虚拟机会分配一块新的栈帧,用来存储该方法的局部变量和返回值。当方法执行完毕时,栈帧被弹出,被腾出的内存可以被其他方法重用。栈的特点是内存分配速度快,但它的大小是固定的,不支持动态扩展。

3. 方法区

方法区也是Java虚拟机的一种存储区域,用于存储类信息、常量、静态变量、编译器编译后的代码等。方法区被所有线程共享,一般情况下不会被回收,它的大小也是固定的。方法区的特点是存储内容较为稳定,但占用内存比较大,需要重点管理。

 10.创建线程的方式

创建线程的方式有两种:

1. 继承Thread类,并重写run()方法。创建自定义的线程类对象,并调用start()方法启动线程。

示例代码:

class MyThread extends Thread {
    public void run() {
        System.out.println("MyThread is running");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
}

2. 实现Runnable接口,并重写run()方法。创建Runnable接口实现类的对象,并以其为参数创建Thread对象。调用Thread对象的start()方法,启动线程。

示例代码:

class MyRunnable implements Runnable {
    public void run() {
        System.out.println("MyRunnable is running");
    }
}

public class Main {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}

11.线程池的队列满了怎么处理?

 当线程池的队列已经满了,处理方式通常有以下几种:

1. 抛出异常:当任务无法添加到线程池队列中时,可以抛出运行时异常,通知程序处理此异常。

2. 阻塞:当队列已满时,新提交的任务可以阻塞,等待队列中的任务执行完成后再添加进队列中。这种方式适用于任务数不是很多,且任务执行时间较短的情况。

3. 拒绝:当队列已满时,可以直接拒绝当前提交的任务。这种方式可以有效地防止由于任务过多导致线程池崩溃,并保证后续的任务能够继续执行。可以根据业务需求选择不同的拒绝策略,比如直接抛出异常,或者将任务添加到其他队列等待执行。

4. 扩容:当线程池队列已满时,可以通过增加队列容量或者扩大线程池的线程数来提高任务处理的效率,从而避免队列满的情况。

12.spring中been的生命周期

 在Spring中,Bean生命周期可以分为以下8个阶段:

1. 装载配置文件:Spring容器在启动时装载Bean配置文件,并解析成相应的Bean定义(BeanDefinition)。

2. 实例化Bean:Spring容器根据Bean定义,使用Java反射机制实例化Bean。

3. 设置Bean属性:Spring容器使用JavaBean的setter方法或者反射机制为Bean设置属性值。

4. BeanPostProcessor的前置处理:如果Bean实现了BeanPostProcessor接口,Spring容器会在Bean实例化和属性设置之后自动调用它的postProcessBeforeInitialization方法。

5. 初始化Bean:如果Bean实现了InitializingBean接口,Spring容器会在Bean属性设置之后自动调用它的afterPropertiesSet方法,或者使用<bean>元素的init-method属性指定的初始化方法。

6. BeanPostProcessor的后置处理:如果Bean实现了BeanPostProcessor接口,Spring容器会在Bean初始化之后自动调用它的postProcessAfterInitialization方法。

7. 使用Bean:此时Bean已经被完全装配好,可以供其他对象调用或注入到其他对象中。

8. 销毁Bean:如果Bean实现了DisposableBean接口,Spring容器会在容器关闭时自动调用它的destroy方法,或者使用<bean>元素的destroy-method属性指定的销毁方法。

需要注意的是,上述生命周期中的前4步发生在容器启动阶段或者第一次获取Bean实例之前,后4步发生在容器关闭阶段或者Bean实例被销毁之前。

 13.力扣:找不重复子串的最长的字串3. 无重复字符的最长子串 - 力扣(LeetCode)

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        vector<int>f(128, 0);
        int i, j, ans = 0;
        for(i = 0, j = 0; i < s.size(); i ++ ) {
            f[s[i]] ++ ;
            while(f[s[i]] > 1) {
                f[s[j ++ ]] -- ;
            }
            ans = max(ans, i - j + 1);
        }
        return ans;
    }
};

猜你喜欢

转载自blog.csdn.net/m0_62600503/article/details/131107299