兄弟面试了百度,面试题分享一波

简介: 兄弟面试了百度,面试题分享一波

线程池的拒绝策略

当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize时,如果还有任务到来就会采取任务拒绝策略,通常有以下四种策略:

  1. ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常,这也是默认策略
  2. ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常
  3. ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务
  4. ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务

类锁、对象锁和方法锁

对象锁

加锁非静态方法,即是对象锁。synchronized修饰非静态方法、同步代码块的 synchronized (this)用法和 synchronized (非this对象)的用法锁的是对象,线程想要执行对应同步代码,需要获得对象锁。

类锁

加锁静态方法,即类锁。可以换个方向理解,静态方法其实就是类方法,所以加锁静态方法,即类锁。类锁的范围是整个实体类,即全局锁。

方法锁

通过在方法声明中加入synchronized关键字来声明synchronized方法synchronized方法控制对类成员变量的访问,每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属 线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此 后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为synchronized的成员函数中至多只有一个处于可执行状态,从而有效避免了类成员变量的访问冲突。

String、StringBuffer、StringBuilder

  1. 运行速度:StringBuilder > StringBuffer > String
  2. 长度
  • StringBuilderStringBuffer是字符串变量,长度可变
  • String创建后不可更改,底层用于存放字符的数组为final类型
  1. 线程安全
  • StringBuilder是线程不安全的
  • StringBuffer是线程安全的
  1. 使用场景
  • String适合少量字符串操作情况
  • StringBuffer适用于多线程在字符缓冲区进行大量操作情况
  • StringBuilder适用于在单线程在字符缓冲区进行大量操作的情况

为什么String不可变

String类的字符是保存在value数组中的,并且是被private final修饰的。

  • private修饰,表明外部的类是访问不到value的,同时子类也访问不 到,当然String类不可能有子类,因为类被final修饰了
  • final修饰,表明value的引用是不会被改变的,而value只会在String的构造函数中被初始化,而且并没有其他方法可以修改value数组中的值,保证了value的引用和值都不会发生变化

Hashmap的put操作流程

当我们put的时候,首先计算keyhash值,这里调用了hash方法,hash方法实际是让key.hashCode()key.hashCode()>>>16进行异或操作,高16bit0,一个数和0异或不变,所以hash函数大概的作用就是:高16bit不变,低16bit和高16bit做了一个异或,目的是减少碰撞。按照函数注释,因为bucket数组大小是2的幂,计算下标index = (table.length - 1) & hash,如果不做hash处理,相当于散列生效的只有几个低bit位,为了减少散列的碰撞,设计者综合考虑了速度、作用、质量之后,使用高16bit和低16bit异或来简单处理减少碰撞,而且JDK8中用了复杂度O(log n)的树结构来提升碰撞下的性能。

Arraylist和Linkedlist

ArrayList的实现是基于数组LinkedList的实现是基于双向链表

  • 对于随机访问,ArrayList优于LinkedList
  • 对于插入和删除操作,LinkedList优于ArrayList

LinkedListArrayList更占内存,因为LinkedList的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。

线程安全的List有哪些

SynchronizedListCopyOnWriteArrayList

SynchronizedList

Collections.synchronizedList(list);list包装成SynchronizedList。需要注意的是SynchronizedListadd等操作加了锁,但是iterator()方法没有加锁,如果使用迭代器遍历的时候需要在外面手动加锁。适用于当不需要使用iterator()并且对性能要求不高的场景。

CopyOnWriteArrayList

在写的时候加锁(ReentrantLock锁),读的时候不加锁,大大提升了读的速度。添加元素的时候,先加锁,再复制替换操作,再释放锁。适用于读多写少的场景。

Arraylist扩容

第一种情况

ArrayList的容量为0时,此时添加元素的话,需要扩容,三种构造方法创建的ArrayList在扩容时略有不同:

  1. 无参构造:创建ArrayList后容量为0,添加第一个元素后,容量变为10,此后若需要扩容,则正常扩容。
  2. 传容量构造:当参数为0时,创建ArrayList后容量为0,添加第一个元素后,容量为1,此时ArrayList是满的,下次添加元素时需正常扩容。
  3. 传列表构造:当列表为空时,创建ArrayList后容量为0,添加第一个元素后,容量为1,此时ArrayList是满的,下次添加元素时需正常扩容。
第二种情况

ArrayList的容量大于0,并且ArrayList是满的时,此时添加元素的话,进行正常扩容,每次扩容到原来的1.5倍。

SpringBoot常用注解

@Component: 会被spring容器识别,并转为bean。

@Repository: 对Dao实现类进行注解。

@Service: 对业务逻辑层进行注解。

@Controller: 表明这个类是Spring MVC里的Controller,将其声明为Spring的一个Bean,Dispatch Servlet会自动扫描注解了此注解的类,并将Web请求映射到注解了@RequestMapping的方法上。

@RequestMapping: 用来映射Web请求(访问路径和参数)、处理类和方法的。它可以注解在类和方法上。注解在方法上的@RequestMapping路径会继承注解在类上的路径。

@RequestBody: 可以将整个返回结果以某种格式返回,如json或xml格式。

@PathVariable: 用来接收路径参数,如/news/001,可接收001作为参数,此注解放置在参数前。

@RequestParam:用于获取传入参数的值。

@RestController:是一个组合注解,组合了@Controller@ResponseBody,意味着当只开发一个和页面交互数据的控制的时候,需要使用此注解。

Spring解决循环依赖

Spring通过三级缓存解决了循环依赖,其中一级缓存为单例池(singletonObjects),二级缓存为早期曝光对象(earlySingletonObjects),三级缓存为早期曝光对象工厂(singletonFactories)。

当A、B两个类发生循环引用时,在A完成实例化后,就使用实例化后的对象去创建一个对象工厂,并添加到三级缓存中,如果A被AOP代理,那么通过这个工厂获取到的就是A 代理后的对象,如果A没有被AOP代理,那么这个工厂获取到的就是A实例化的对象。当A进行属性注入时,会去创建B,同时B又依赖了A,所以创建B的同时又会去调用getBean(a)来获取需要的依赖,此时的getBean(a)会从缓存中获取,第一步,先获取到三级缓存中的工厂;第二步,调用对象工工厂的getObject方法来获取到对应的对象,得到这个对象后将其注入到B中。紧接着B会走完它的生命周期流程,包括初始化、后置处理器等。当B创建完后,会将B再注入到A中,此时A再完成它的整个生命周期。至此,循环依赖结束!

为什么要使用三级缓存呢?二级缓存能解决循环依赖吗?

如果要使用二级缓存解决循环依赖,意味着所有Bean在实例化后就要完成AOP代理,这样违背了Spring设计的原则,Spring在设计之初就是通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来在Bean生命周期的最后一步来完成AOP代理,而不是在实例化后就立马进行AOP代理。

Hystrix的隔离策略

Hystrix目前是有两种隔离策略,分别是线程池隔离信号量隔离

线程池隔离

他的隔离是通过线程池来做到的,隔离粒度是线程池。一个请求进来都经过一个线程池。

当前端发起请求过来到服务A或者B之后,服务A和服务B是通过线程池隔离的。服务A是否熔断,是否正常都和服务B无关。

他其实是一个异步编程,用线程池将后面的服务包裹了起来,至于服务内部tomcate的线程运行怎么样是无关的。他适合于绝大多数的场景,对于一些超时的场景都非常好用。但是既然是通过线程池来操作的,不可避免的就是线程之间的计算开销,以及线程上下文的切换,调度消耗。

信号量隔离

他的隔离是通过信号量来做到的。他其实是一个计数器。一个请求进来就会减少一个信号,一个请求完成就会增加一个信号。

信号量的调用是同步的,也就是说他会阻塞直到请求回来。所以他自身是不能实现超时的,因此这里的超时只能依靠协议的超时来做,否则是无法释放的(比如socket超时等等)。所以当此服务不对外部服务依赖同时自身没有大量的计算或者说经过这个服务的时间比较短,则非常适合信号量,比如说Spring cloudzuulgateway网关。

相关文章
|
6天前
|
存储 NoSQL Java
【面试宝藏】Redis 常见面试题解析
Redis 是内存数据结构存储系统,用作数据库、缓存和消息中间件,支持字符串、哈希、列表等数据类型。它的优点包括高性能、原子操作、持久化和复制。相比 Memcached,Redis 提供数据持久化、丰富数据结构和发布/订阅功能。Redis 采用单线程模型,但通过 I/O 多路复用处理高并发。常见的面试问题涉及持久化机制、过期键删除、回收策略、集群和客户端等。
27 4
|
6天前
|
存储 关系型数据库 MySQL
【面试宝藏】MySQL 面试题解析
MySQL面试题解析涵盖数据库范式、权限系统、Binlog格式、存储引擎对比、索引原理及优缺点、锁类型、事务隔离级别等。重点讨论了InnoDB与MyISAM的区别,如事务支持、外键和锁机制。此外,还提到了Unix时间戳与MySQL日期时间的转换,以及创建索引的策略。
21 4
|
1天前
|
XML JSON Java
Android面试题 之 网络通信基础面试题
序列化对比:Serializable码流大、性能低;XML人机可读但复杂;JSON轻量、兼容性好但空间消耗大;ProtoBuff高效紧凑。支持大量长连接涉及系统限制调整、缓冲区优化。select/poll/epoll是IO多路复用,epoll在高连接数下性能更优且支持边缘触发。水平触发持续通知数据,边缘触发仅通知新数据。直接内存减少一次拷贝,零拷贝技术如sendfile和MMAP提升效率。关注公众号"AntDream"了解更多技术细节。
7 1
|
6天前
|
存储 异构计算 内存技术
【硬件工程师面试宝典】常见面试题其一
- Setup时间:时钟前数据需稳定的最小时间。 - Hold时间:时钟后数据需保持稳定的时间。 - 竞争现象:不同路径信号汇合导致输出不稳定。 - 冒险现象:竞争引起的短暂错误状态。 - D触发器实现2倍分频电路。
20 5
|
6天前
【硬件工程师面试宝典】常见面试题其二
检查单片机上电不运行:电源电压、时钟信号、复位电路、程序烧录。三极管特性:输出特性曲线和转移特性曲线。频率响应指系统对不同频率信号的响应,稳定要求幅度和相位不变。改变响应曲线方法:调整反馈、使用滤波器、改变元件参数。差分运放相位补偿通过在反馈回路加电容,波特图显示补偿效果。基本放大电路类型有共射、共集、共基,差分结构用于抗干扰和提高共模抑制比。电阻电容串联,电容电压为低通滤波,电阻电压为高通滤波。选择电阻考虑阻值、功率、温度系数、精度和尺寸。CMOS电路传递低电平用N管。电流偏置电路通过R1、Q1产生稳定电流。施密特电路回差电压由R1、R2决定。LC振荡器的哈特莱、科尔皮兹、克拉
13 0
|
6天前
|
存储 缓存 NoSQL
【面试宝藏】Redis 常见面试题解析其二
Redis 高级面试题涵盖了哈希槽机制、集群的主从复制、数据丢失可能性、复制机制、最大节点数、数据库选择、连通性测试、事务操作、过期时间和内存优化等。Redis 使用哈希槽实现数据分布,主从复制保障高可用,异步复制可能导致写操作丢失。集群最大支持1000个节点,仅允许单数据库。可通过 `ping` 命令测试连接,使用 `EXPIRE` 设置过期时间,`MULTI/EXEC` 等进行事务处理。内存优化包括合理数据类型、设置过期时间及淘汰策略。Redis 可用作缓存、会话存储、排行榜等场景,使用 `SCAN` 查找特定前缀键,列表实现异步队列,分布式锁则通过 `SET` 命令和 Lua 脚本实现。
19 5
|
6天前
|
负载均衡 算法 Java
【面试宝藏】Go语言运行时机制面试题
探索Go语言运行时,了解goroutine的轻量级并发及GMP模型,包括G(协程)、M(线程)和P(处理器)。GMP调度涉及Work Stealing和Hand Off机制,实现负载均衡。文章还讨论了从协作到基于信号的抢占式调度,以及GC的三色标记算法和写屏障技术。理解这些概念有助于优化Go程序性能。
23 4
|
6天前
|
存储 安全 Java
【面试宝藏】Go基础面试题其一
Go语言(Golang)结合C的性能和Python的易用性,具有简单语法、高效并发、自动垃圾回收等优点。它支持基本和派生数据类型,通过包进行代码管理。类型转换需显式进行,如将整数转为浮点数。Goroutine是轻量级线程,通过channel进行并发同步。Go接口可嵌套,同步锁用于控制并发访问。Channel提供类型安全的通信,注意避免死锁。Go Convey用于测试,`new`和`make`分别用于值类型和引用类型的初始化。了解这些,有助于更好地掌握Go语言。
13 2
|
6天前
|
存储 缓存 算法
【面试宝藏】Go并发编程面试题
探索Go语言并发编程,涉及Mutex、RWMutex、Cond、WaitGroup和原子操作。Mutex有正常和饥饿模式,允许可选自旋优化。RWMutex支持多个读取者并发,写入者独占。Cond提供goroutine间的同步,WaitGroup等待任务完成。原子操作保证多线程环境中的数据完整性,sync.Pool优化对象复用。了解这些,能提升并发性能。
11 2
|
28天前
|
消息中间件 数据采集 Python
2024年Python最全使用python的pika链接rabbitMq断裂_pika,BTAJ面试有关散列(哈希)表的面试题详解
2024年Python最全使用python的pika链接rabbitMq断裂_pika,BTAJ面试有关散列(哈希)表的面试题详解
2024年Python最全使用python的pika链接rabbitMq断裂_pika,BTAJ面试有关散列(哈希)表的面试题详解