一般的域名可以做彩票网站吗常州seo排名收费
文章目录
-
目录
文章目录
提问问题
问题1
问题2
问题3
问题4
问题5
问题6
问题7
问题8
问题9
问题10
问题11
问题12
问题13
问题14
问题15
问题16
问题17
问题18
写在最后
提问问题
JVM类加载机制?
nginx怎么做到负载均衡?
HashMap的红⿊树和扩容机制?
怎么⽤前缀树过滤敏感词?
简单介绍一下JVM垃圾回收机制?
线程安全介绍?
IO如何多路复⽤?
讲⼀下抽象类和接口的区别?
讲⼀下static和final的作⽤?什么时候会不能⽤static?
string可以被继承吗?
synchonized 和 locked的区别?synchonized底层实现原理?
多线程创建的⽅式?
线程池怎么⽤?核⼼参数?整个执⾏的过程(包括消息队列)?
InnoDB和Mysam搜索引擎的区别以及索引的区别?
Innodb索引介绍下?Innodb的锁介绍下?
redis三⼤问题介绍⼀下?
项⽬⾥Redis当中数据不⼀致性怎么解决的?
Kafka如果有三个分区,四个消费者会怎么样?
问题1
Java类加载机制主要分为以下几个步骤:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)和使用(Using)。
类加载器按照一定的层次结构组织,遵循双亲委派模型(Parent Delegation Model),即先委托父类加载器去加载类,父类加载器加载不了时,再由子类加载器尝试加载。
问题2
nginx通过配置模块实现负载均衡,主要有轮询(Round Robin)、最少连接(Least Connections)、IP哈希(IP Hash)等算法。它会根据这些策略将客户端请求分发到后端服务器上
问题3
HashMap在Java 8中引入了红黑树,当链表长度超过一定阈值(默认8)时,链表会转换成红黑树以提高查找效率。
当HashMap中的元素数量达到负载因子与容量的乘积时,会进行扩容,默认将容量翻倍,并重新计算每个元素的位置。
问题4
前缀树(Trie Tree),也称字典树,是一种用于快速检索字符串集合的数据结构。
使用前缀树过滤敏感词,主要通过高效地对文本进行匹配和过滤,以检测并移除敏感词;按照以下步骤进行:
构建前缀树:首先,你需要将敏感词库转换成前缀树。每个敏感词都是树的一个节点,节点之间的连接表示字符之间的关系。例如,对于敏感词"abc",你需要创建一个从根节点开始,依次添加'a'、'b'、'c'的路径。
插入数据:遍历敏感词库,将所有的敏感词按照上述方式插入前缀树中。在插入过程中,如果某个节点已经存在,则无需重复创建,只需更新该节点即可。
文本匹配:当需要检查某个文本是否含有敏感词时,将文本分解成单个字符,然后从前缀树的根节点开始遍历。如果在某一节点处发现文本的剩余部分与树中的路径完全匹配,则说明文本中含有一个敏感词。
处理匹配结果:如果找到匹配,可以根据需求对敏感词进行处理,比如替换为星号(*)、删除或者标记出来。
优化性能:为了提高匹配效率,可以对前缀树进行优化,比如使用压缩技术减少节点占用空间,或者采用Trie树的变种如字典树(Radix Tree)来减少内存消耗。
问题5
JVM垃圾回收机制是指Java虚拟机中用于管理内存的一系列自动化技术,其目的是回收那些不再被程序使用的内存资源,以便这些资源可以被重新分配给新的对象实例,来确保JVM运行时环境的稳定性和高效性。
垃圾回收机制主要分为以下几个方面:
垃圾回收器:JVM提供了多种垃圾回收器,每种都有其特点和适用场景。常见的垃圾回收器包括Serial GC、Parallel GC、Concurrent Mark Sweep (CMS) GC、Garbage-First (G1) GC等。
垃圾收集策略:垃圾回收策略决定了何时以及如何执行垃圾回收。主要的策略包括分代收集(Generational Collection)和标记-清除(Mark-Sweep)、标记-压缩(Mark-Compact)、复制(Copying)算法等。
分代收集:基于对象存活周期的不同,JVM将堆内存划分为新生代(Young Generation)、老年代(Old Generation)和永久代/元空间(PermGen/Metaspace)。大多数对象首先在新生代分配,经过一定次数的垃圾回收后,存活下来的对象会被移动到老年代。
内存管理:JVM还包含其他几个重要的内存区域,如方法区(用于存储类信息、静态变量等)、程序计数器(当前线程所执行的字节码的行号指示器)和虚拟机栈(每个方法执行的地方,用于存放局部变量表、操作数栈、动态链接等信息)。
性能监控和调优:通过JVM提供的工具如jconsole、jvisualvm、jmap、jstat等,可以监控垃圾回收的性能,并根据应用的特点进行调优,以达到最佳的内存使用效率。
问题6
线程安全是指当多个线程访问某个类的实例时,该类仍然能表现出正确的行为。
实现线程安全的方式有同步代码块、不可变对象、线程局部变量等。
问题7
IO多路复用是指通过单个线程监听多个文件描述符,当某个文件描述符就绪时,能够通知对应的处理程序进行处理。
在Java中,可以使用Selector和它的注册通道(Channel)来实现非阻塞IO的多路复用。
问题8
抽象类可以有构造方法、成员变量、成员函数(其中可以包含抽象方法),而接口只能声明常量和抽象方法。
抽象类可以实现多个接口,但接口不能实现类。
问题9
static用于定义类级别的成员变量或方法,它们不依赖于类的实例,而是属于类本身。final用于定义不可更改的变量或方法,一旦被赋值或实现后就不能被改变。static
适用于那些与对象实例无关,需要在类级别上共享的成员,而final
适用于需要确保不变性的。
不能使用
static
的情况:
- 静态不能用于实例变量和非静态方法,因为它们需要依赖于具体的对象实例来存在。
- 静态不能用于构造器,因为构造器的目的是创建对象实例,而静态方法和变量不依赖于任何特定的实例。
- 静态不能用于初始化块以外的代码块,因为静态代码块是用于初始化静态成员的特殊代码块。
- 静态不能用于实例初始化器(instance initializer block),因为实例初始化器是在创建对象实例时执行的,而静态成员与对象实例无关。
问题10
在Java中,String类是final的,因此不能被子类继承。
问题11
synchronized是Java内置的同步关键字,用于实现方法或代码块的互斥访问。
ReentrantLock是java.util.concurrent.locks包下的一个类,提供了比synchronized更强大的功能,如尝试非阻塞获取锁、可中断锁获取等。
synchronized
提供了基本的同步功能,使用起来比较简单,但是功能较少。ReentrantLock
提供了更多的控制和灵活性,但是需要程序员自己管理锁的获取和释放。
synchronized
的底层实现原理:
- 每个对象都有一个内置锁(monitor lock)关联。
- 当一个线程想要进入同步方法或同步代码块时,它必须先获得这个对象的内置锁。
- 如果锁已经被另一个线程持有,当前线程将被阻塞,直到锁被释放。
- 锁的释放是自动的,当同步方法或同步代码块执行完毕后,锁会被释放,其他线程可以竞争这个锁。
- JVM利用操作系统的互斥锁(Mutex Lock)来实现内置锁。
问题12
可以通过Thread类的构造方法创建线程,或者实现Runnable接口,并将实例传递给Thread类的构造方法。还可以使用Callable接口和FutureTask类创建有返回值的线程。
问题13
在Java中使用线程池,一般会通过java.util.concurrent
包中的ExecutorService
接口来实现。ExecutorService
提供了一组执行异步任务的方法,而线程池则实现了这个接口,用于管理一组工作线程,以提高资源的利用率和响应速度。
核心参数:
corePoolSize
:核心线程数,即线程池在没有任务执行时也会保持的最小线程数。maximumPoolSize
:最大线程数,线程池允许的最大线程数。keepAliveTime
:空闲线程存活时间,当线程池中的线程数超过corePoolSize
时,多余的线程在等待新任务执行前可以存活的最长时间。unit
:keepAliveTime
的时间单位,如秒、分钟等。workQueue
:任务队列,用于存储待执行的任务,常用的有LinkedBlockingQueue
、SynchronousQueue
等。threadFactory
:线程工厂,用于创建新线程。handler
:拒绝策略,当任务队列满了且线程数达到最大线程数时,如何处理新提交的任务。
执行过程:
- 当向线程池提交一个任务时,线程池会首先判断核心线程数是否已达到,如果没有,则创建一个新的工作线程来执行任务。
- 如果核心线程数已经达到,任务将被放入消息队列中。
- 如果消息队列已满,并且线程数小于最大线程数,线程池会创建新的工作线程来处理任务。
- 如果线程数达到最大线程数,并且消息队列也已满,线程池将根据拒绝策略来处理新提交的任务。常见的拒绝策略有
AbortPolicy
(抛出异常)、CallerRunsPolicy
(由调用者自己运行)、DiscardPolicy
(丢弃任务)、DiscardOldestPolicy
(丢弃队列最老的任务)。- 当线程执行完任务后,它会回到空闲状态。如果此时线程池中的活跃线程数大于
corePoolSize
,并且有线程空闲时间超过keepAliveTime
,那么空闲线程将被终止。- 线程池会不断重复上述过程,以处理不断提交的任务。
使用线程池的一个典型例子如下:
import java.util.concurrent.*;public class ThreadPoolExample {public static void main(String[] args) {// 创建固定大小的线程池ExecutorService executorService = Executors.newFixedThreadPool(5);// 提交任务到线程池for (int i = 0; i < 10; i++) {Runnable task = new Runnable() {public void run() {System.out.println("执行任务: " + Thread.currentThread().getName());}};executorService.submit(task);}// 关闭线程池executorService.shutdown();}
}
在使用线程池时,应当合理配置核心参数,避免创建过多线程导致资源浪费,或者创建过少线程导致任务处理不及时。同时,要注意正确关闭线程池,释放系统资源。
问题14
InnoDB支持事务处理、行级锁定和外键约束,而MyISAM不支持。
索引方面,InnoDB使用聚簇索引,数据和索引在一起存储,而MyISAM使用非聚簇索引,索引文件和数据文件分离。
问题15
InnoDB的索引是基于B+树的,主键索引是聚集索引,其他索引是辅助索引。辅助索引中的数据指针指向聚集索引的记录。
InnoDB支持行级锁和表级锁,行级锁有共享锁(S锁)、排他锁(X锁)、意向锁等。它还支持乐观并发控制和悲观并发控制,以减少锁争用。
Innodb支持两种类型的锁:
共享锁(Share Locks,又名读锁):
- 允许多个事务读取同一个数据行,但不允许写入操作。
- 共享锁之间是兼容的,即多个事务可以同时持有同一数据行的共享锁进行读取。
排他锁(Exclusive Locks,又名写锁):
- 只允许单个事务对某数据行进行写操作,期间不允许其他事务读取或写入该数据行。
- 排他锁之间是不兼容的,即如果一个事务对数据行加了排他锁,其他事务必须等待该事务释放锁才能访问该数据行。
Innodb还支持以下高级锁机制:
意向锁(Intention Locks):
- 用于表示事务在某个资源上的锁的意向,比如意向共享锁(IS)或意向排他锁(IX)。
- 在请求更细粒度的锁之前,事务会先设置一个意向锁,这样其他事务就能知道这个事务打算在子资源上加什么样的锁。
行级锁(Row-level Locking):
- 锁定的粒度非常细,只锁定一行数据。
- 行级锁可以大大减少锁冲突,提高并发性能。
乐观并发控制(Optimistic Concurrency Control,OCC):
- 在更新数据前不加锁,而是在事务提交时检查是否有其他事务修改过相同的数据。
- 适用于冲突较少的环境,可以减少锁的开销。
悲观并发控制(Pessimistic Concurrency Control):
- 在读取数据时就加锁,直到事务结束才释放锁。
- 适用于冲突较多的环境,可以保证数据的一致性,但可能会降低并发性能。
问题16
Redis面临的三大问题通常指的是持久化、复制和高可用性。
持久化是指将内存中的数据保存到磁盘,复制是指主从数据同步,高可用性涉及到故障转移和集群部署。
问题17
在项目中,可以通过以下方式解决Redis数据不一致性:
- 使用Raft或Redis Sentinel实现高可用性和自动故障转移。
- 使用Redis Cluster进行分布式部署,实现数据分片和冗余。
- 在应用层实现一致性协议,比如二阶段提交。
- 使用事务和Lua脚本来保证操作的原子性。
问题18
Kafka的分区和消费者之间是一对一的关系,即一个分区只能由一个消费者消费。如果有三个分区和四个消费者,那么第四个消费者将无法获得分区,除非调整消费者组的分配策略或者增加分区数量。
写在最后
PS:以上是网络上收集的一些常见的问题以及自己对答案搜索整理;一次整理基本上就是面试一次的题量,适合对自己的知识的查缺补漏
面试一般根据岗位要求或者简历上写的来进行扩展提问,也有些是直接问公司常用到的相关方面的技术问题,无论怎么准备都祝大家能拿到心怡的offer!