哈喽~,大家好,我是千羽。
今年2023年的互联网行业的竞争依然激烈。在这个充满挑战的环境中,面试成为了实现职业发展的重要一步。
近期有幸获得了一份来自中国科学院大学的ACM选手在阿里暑期实习面试的面经。
这位同学拥有丰富的算法竞赛经验,深厚的技术功底和卓越的学术背景。尽管经验丰富、回答出色,令人遗憾的是,他在初面时未能成功晋级。
static
关键字主要用于定义静态变量和静态方法。这些静态成员在类加载时被加载,并且随着类的加载而初始化。类的加载过程一般发生在以下几种情况下:
Class.forName()
方法动态加载类时,也会触发类的加载和初始化过程。这种方式可以在运行时动态加载类,这在一些特定场景下很有用。java.util.concurrent.atomic
包中,用于支持在多线程环境下进行原子操作。在并发编程中,当多个线程同时访问共享变量时,可能会引发竞态条件(race conditions),导致数据不一致或出现错误。原子类通过提供特定操作的原子性保证,帮助避免了这种情况。常见的原子类包括 AtomicInteger
、AtomicLong
、AtomicBoolean
等,它们提供了一些原子性操作,比如原子性的递增、递减、设置等。java.lang
包中。在 Java 中,基本数据类型(比如 int
、long
、boolean
等)是非对象类型,但有时候需要将其转换成对象才能操作或者传递给某些方法。这时就可以使用包装类。例如,Integer
是 int
的包装类,Long
是 long
的包装类,Boolean
是 boolean
的包装类。这些包装类提供了一些方法来操作对应的基本数据类型,同时也允许 null
值。例如,原子类的用法如下所示:
AtomicInteger atomicInt = new AtomicInteger(0);
atomicInt.incrementAndGet(); // 原子性递增操作
而包装类的用法则是将基本数据类型封装为对象,例如:
Integer intObj = Integer.valueOf(10); // 将int类型10封装为Integer对象
int value = intObj.intValue(); // 获取Integer对象的int值
JVM的垃圾回收主要涉及新生代和老年代两个部分,它们的垃圾回收过程和算法有所不同。
新生代到老年代过程:
垃圾回收算法:
常用线程池参数:
使用线程池:
创建线程池: 使用 Executors
类的工厂方法创建线程池,根据需要指定参数。例如:
ExecutorService executor = Executors.newFixedThreadPool(corePoolSize);
提交任务: 使用线程池的 submit()
或 execute()
方法提交任务。例如:
executor.execute(new RunnableTask());
关闭线程池: 使用 shutdown()
或 shutdownNow()
方法关闭线程池,释放资源。
运行原理:
corePoolSize
和 maximumPoolSize
。如果并发量很大,可以增加最大线程数以处理更多请求。corePoolSize
和 maximumPoolSize
以应对长时间的请求处理。ArrayBlockingQueue
): 可以控制任务的最大排队数量,避免无限制的任务积压。但如果队列满了,会触发线程池的饱和策略。LinkedBlockingQueue
): 不限制队列大小,但会导致内存占用增加。当任务量很大时,可能导致内存耗尽。SynchronousQueue
,它不会保存任务,而是直接将任务提交给线程池的最大线程数处理。如果可以接受一定程度的失误,可以采用调整 keepAliveTime
和 allowCoreThreadTimeOut
的方式,让空闲线程在一定时间内被回收,以节省资源。
监控系统资源使用情况:
top
可以实时查看系统的 CPU、内存、进程等使用情况。按 Shift + M
可以按照内存占用排序显示进程。查看进程和资源占用情况:
ps aux
可以显示所有进程的详细信息。pidstat -u -p <PID>
可以显示特定进程的 CPU 使用情况。监控内存使用情况:
free -m
显示内存使用情况(以兆字节为单位)。vmstat 1
每秒刷新一次信息。查看系统日志:
/var/log/messages
、/var/log/syslog
)中的错误、警告信息,查看系统可能出现的异常情况。针对性的调试工具:
strace -p <PID>
跟踪特定进程的系统调用。lsof -p <PID>
显示特定进程打开的文件列表。在 Java 中,Synchronized 锁在运行过程中存在四种状态,它们包括无锁状态、偏向锁、轻量级锁和重量级锁。Syn锁升级即是指锁从低级状态升级到高级状态的过程。
Syn锁升级的过程:
查看系统中锁的阻塞状态:
分布式锁的实现方式:
分布式锁的缺点:
缓存击穿解决方案:
降低一致性,增强可用性的方案:
RabbitMQ提供了三种Confirm机制:
RabbitMQ的Confirm机制通过channel.confirmSelect()
开启,然后针对每条发送的消息,通过channel.waitForConfirms()
、channel.waitForConfirmsOrDie()
等方法等待Broker的确认。
ThreadLocal使用了一个特殊的ThreadLocalMap
来存储数据。这个ThreadLocalMap
是Thread
类中的一个成员变量,它以ThreadLocal
对象为键,以线程的私有变量副本为值。每个线程都可以根据ThreadLocal
对象获取自己线程的独立副本,这样不同线程间的变量副本互不干扰。
何时使用ThreadLocal?
注意事项:
ThreadLocal
的remove()
方法来手动清理。隐马尔可夫模型(Hidden Markov Model,HMM)是一种基于概率的统计模型,用于建模观测序列和隐藏的状态序列之间的关系。HMM广泛应用于语音识别、自然语言处理、生物信息学等领域。
隐马尔可夫模型原理:
工作原理举例:
在语音识别中,假设有一个隐藏状态序列(声音状态:浊音、清音等)和对应的观测序列(声音信号),HMM可以通过观测到的声音信号来推断最可能的声音状态序列。模型会根据训练数据学习每个声音状态产生不同声音信号的概率,以及声音状态之间的转移概率,然后利用这些概率来预测最可能的声音状态序列。
调参方法:
修改模型本身的方法:
nn.Module
类并实现forward
函数,你可以创建自定义层并将其添加到模型中。