7.10飞书一面面经

问题描述

协程和线程的区别?

协程是用于实现轻量级并发编程的一种机制。与线程相比,协程提供了更细粒度的并发控制,可以用来执行多任务并发处理,但它们的开销比线程要小得多。在Java中,协程通常指的是在单个线程内可以挂起和恢复执行的代码块。

Java协程的概念在Java 19中通过Project Loom正式引入,以解决传统线程模型中的一些问题,例如线程资源消耗大、上下文切换开销大等。以下是关于Java协程的一些关键点:
轻量级:协程是用户态线程,它们比操作系统线程(内核态线程)更轻量,创建和销毁的开销更小。
非阻塞:协程可以在等待某些操作(如I/O)完成时释放CPU,让出执行权给其他协程,从而提高资源利用率。
协作式多任务:协程通过显式的挂起(suspend)和恢复(resume)操作来实现多任务并发,这与线程的抢占式调度不同。
更好的资源利用:由于协程的轻量性,可以在单个线程内创建大量协程,从而提高并发处理的效率。

实现机制:
Java 19引入了VirtualThread作为协程的一种实现,它是一种可以在任何线程上运行的轻量级线程。VirtualThread由Java运行时管理和调度。

import java.lang.Thread;

public class VirtualThreadExample {
    public static void main(String[] args) {
        // 创建并启动一个虚拟线程
        Thread.startVirtualThread(() -> {
            // 这是在虚拟线程中执行的代码
            System.out.println("VirtualThread starts working...");
            
            // 执行一些简单的任务,例如计数
            for (int i = 0; i < 5; i++) {
                System.out.println("Count: " + i);
                
                // 模拟耗时操作,让出CPU时间片
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("VirtualThread was interrupted.");
                    return;
                }
            }
            
            System.out.println("VirtualThread finished its work.");
        });
        
        // 主线程可以继续执行其他任务或等待虚拟线程完成
        System.out.println("Main thread continues execution...");
        
        // 在这个简单的例子中,我们选择让主线程等待,以确保虚拟线程有机会执行
        try {
            Thread.sleep(6000); // 等待足够的时间以确保虚拟线程可以完成
        } catch (InterruptedException e) {
            System.out.println("Main thread was interrupted.");
        }
        
        System.out.println("Main thread is done.");
    }
}

Redis为什么快?

这个问题我遇到过,但是没有好好总结,导致答得很乱。
答:Redis基于内存操作: 传统的磁盘文件操作相比减少了IO,提高了操作的速度。

Redis高效的数据结构:Redis专门设计了STRING、LIST、HASH等⾼效的数据结构,依赖各种数据结构提升了读写的效率。

Redis是单线程模型,单线程操作省去了上下⽂切换带来的开销和CPU的消耗,同时不存在资源竞争,避免了死锁现象的发生。

Redis采用I/O多路复⽤,同时监听多个Socket,根据Socket上的事件来选择对应的事件处理器进⾏处理。

介绍一下Mysql的索引?

这里我第一时间不知道从哪里入手,面试官引导我从数据结构说。

B+树的⾮叶⼦节点不存放实际的记录数据,仅存放索引,所以数据量相同的情况下,相⽐存储即存索引⼜存记录的 B 树,B+树的⾮叶⼦节点可以存放更多的索引,因此 B+ 树可以⽐ B 树更「矮胖」,查询底层节点的磁盘 I/O次数会更少。
B+ 树有⼤量的冗余节点(所有⾮叶⼦节点都是冗余索引),这些冗余索引让 B+ 树在插⼊、删除的效率都更⾼,⽐如删除根节点的时候,不会像 B 树那样会发⽣复杂的树的变化;
B+ 树叶⼦节点之间⽤链表连接了起来,有利于范围查询,⽽ B 树要实现范围查询,因此只能通过树的遍历来完成范围查询,这会涉及多个节点的磁盘 I/O 操作,范围查询效率不如 B+ 树。

说一下Redis集群。

这个我说只是了解,没有答。

在Redis中提供的集群方案总共有三种:主从复制、哨兵模式、Redis分片集群
主从复制:单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,可以搭建主从集群,实现读写分离。一般都是一主多从,主节点负责写数据,从节点负责读数据,主节点写入数据之后,需要把数据同步到从节点中。

哨兵模式建立在主从复制模式上,通过引入了哨兵来监控与自动处理故障。哨兵模式可以实现主从集群的自动故障恢复,里面就包含了对主从服务的监控、自动故障恢复、通知;如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主;同时Sentinel也充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端,所以一般项目都会采用哨兵的模式来保证redis的高并发高可用。

哨兵模式解决了主从复制不能自动故障转移,达不到高可用的问题,但还是存在难以在线扩容,Redis容量受限于单机配置的问题。

分片集群模式实现了Redis的分布式存储,即每台节点存储不同的内容,来解决在线扩容的问题。

算法:

峰值元素是指其值严格大于左右相邻值的元素。
给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞ 。
你必须实现时间复杂度为 O(log n) 的算法来解决此问题。

public class Solution {
    public int findPeakElement(int[] nums) {
        int left = 0, right = nums.length - 1;
        
        while (left < right) {
            int mid = left + (right - left) / 2;
            
            // 比较中间元素与其右侧邻居
            if (nums[mid] > nums[mid + 1]) {
                // 峰值在左侧或者就在 mid 位置
                right = mid;
            } else {
                // 峰值在右侧
                left = mid + 1;
            }
        }
        
        // left 和 right 会相遇在峰值位置
        return left;
    }
}
  • 38
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

miss writer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值