百度2021面试

百度面试

  1. 自我介绍(比较短,一直不知道怎么自我介绍)

  2. 项目

  3. Redis为什么快(基于内存,IO多路复用,单线程,使用C语言并有很多优化)

    1. 纯内存操作,肯定快

    数据存储在内存中,读取的时候不需要进行磁盘的 IO

    2. 单线程,无锁竞争损耗

    单线程保证了系统没有线程的上下文切换

    使用单线程,可以避免不必要的上下文切换和竞争条件,没有多进程或多线程引起的切换和 CPU 的消耗,不必考虑各种锁的问题,没有锁释放或锁定操作,不会因死锁而降低性能;

    3. C 语言实现,更接近底层操作

    Redis 是用 C 语言开发完成的

    4. 多路 I/O 复用模型,非阻塞 IO

    采用多路 I/O 复用技术可以让单个线程高效的处理多个网络连接请求(尽量减少网络 IO 的时间消耗)

    非阻塞 IO 内部实现采用 epoll,采用了 epoll+自己实现的简单的事件框架。epoll 中的读、写、关闭、连接都转化成了事件,然后利用 epoll 的多路复用特性,绝不在 io 上浪费一点时间。

    5. 数据结构简单,底层又做了优化

    数据结构简单,对数据操作也简单,Redis 中的数据结构是专门进行设计的;

    6. 源码精湛、简短
    扩展:
    在 Redis 中,常用的 5 种数据结构和应用场景
    • String: 缓存、计数器、分布式锁等。
    • List: 链表、队列、微博关注人时间轴列表等。
    • Hash: 用户信息、Hash 表等。
    • Set: 去重、赞、踩、共同好友等。
    • Zset: 访问量排行榜、点击量排行榜等。
    多路 I/O 复用模型

    多路 I/O 复用模型是利用 select、poll、epoll 可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有 I/O 事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll 是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量的无用操作。

    这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。

    采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗),且 Redis 在内存中操作数据的速度非常快,也就是说内存内的操作不会成为影响 Redis 性能的瓶颈,主要由以上几点造就了 Redis 具有很高的吞吐量。

  4. Redis数据结构对于内存占用的优化(sdshdr5, sdshdr8, sdshdr16, sdshdr32, sdshdr64, 字符串越短,使用越少的内存存储额外信息;list 和 hash 元素少的时候使用 ziplist 编码)

    1. 利用zipList来替代大量的key-value

    2. 海量用户系统经常会碰到这样的需求,要求根据用户的某个唯一标识迅速查到该用户id

    3. 特点是数据量很大、千万或亿级别,key是比较长的字符串,如32位的md5或者uuid这种。

      如果不加以处理,直接以key-value形式进行存储,我们可以简单测试一下,往redis里插入1千万条数据,1550000000 - 1559999999,形式就是key(md5(1550000000))→ value(1550000000)这种。

      然后在Redis内用命令info memory看一下内存占用

      可以看到,这1千万条数据,占用了redis共计1.17G的内存。当数据量变成1个亿时,实测大约占用8个G。

      同样的一批数据,我们换一种存储方式,先来看结果:在我们利用zipList后,内存占用为123M,大约减少了85%的空间占用

      zipList最大的特点就是,它根本不是hash结构,而是一个比较长的字符串,将key-value都按顺序依次摆放到一个长长的字符串里来存储。如果要找某个key的话,就直接遍历整个长字符串就好了。

      所以很明显,zipList要比hashTable占用少的多的空间。但是会耗费更多的cpu来进行查询

      4.总结

    如果key的长短不一,譬如有些40位,有些10位,因为对齐问题,那么将产生巨大的内存碎片,占用空间情况更为严重。所以,保持key的长度统一(譬如统一采用int型,定长8个字节),也会对内存占用有帮助。

    string型的md5,占用了32个字节。而通过hash算法后,将32降到了8个字节的长整形,这显著降低了key的空间占用。

    zipList比hashTable明显减少了内存占用,它的存储非常紧凑,对查询效率影响也很小。所以应善于利用zipList,避免在hash结构里,存放超过512个field-value元素。

    如果value是字符串、对象等,应尽量采用byte[]来存储,同样可以大幅降低内存占用。譬如可以选用google的Snappy压缩算法,将字符串转为byte[],非常高效,压缩率也很高。

    为减少redis对字符串的预分配和扩容(每次翻倍),造成内存碎片,不应该使用append,setrange等。而是直接用set,替换原来的。

  5. Mysql 索引类型(聚簇索引和非聚簇索引,hash索引)

    1. 1.普通索引
      2.唯一索引
      3.主键索引
      4.组合索引
      5.全文索引
  6. 数据库读写分离的优缺点(写会加锁,降低数据库并发量,读写分离提高并发量;缺点是读服务器会存在延迟)

    1. 1.增加冗余(通信工程里的名字,对重要的部件多一种保护机制)

      2.增加了机器的处理能力

      3.对于读操作为主的应用,使用读写分离是最好的场景,因为可以确保写的服务器压力更小,而读又可以接受点时间上的延迟

      4.读写分离适用与读远大于写的场景,如果只有一台服务器,当select很多时,update和delete会被这些select访问中的数据堵塞,等待select结束,并发性能不高

  7. rabbitmq 介绍(说了topic,direct,fanout,header模式),重复消费问题(没答上来,说项目中没考虑到)

  8. springboot 最大的特点(自动配置),启动注解和配置文件(记不清了)

    1. @SpringBootApplication:用于标注该类为一个主程序类或者主配置类,我们点进去查看该注解
    2. application.properties:Spring Boot的配置文件
  9. JVM 内存模型和各自作用(程序计数器,JVM虚拟机栈,本地方法栈,堆,方法区),哪些是线程私有的(程序计数器,JVM虚拟机栈,本地方法栈)

  10. String 能被继承吗(不能,被final修饰),和StringBuilder,StringBuffer区别(这两个可变,StringBuffer线程安全)

  11. 重写重载区别(重载:方法名字相同,参数不同;重写发生在运行期,是子类对父类的允许访问的方法的实现过程进行重新编写),重写的修饰符和抛出异常大小(重写方法的修饰符更大,异常更小)

  12. 查看进程的指令(ps),查看cpu使用情况(top),改变文件权限(chmod

  13. TCP 可靠性(面向连接,数据包校验,重新排序,超时重发,流量控制)

算法题

  1. 判断一颗树是否为avl树(递归做)

    1. 如果左子树是AVL树,右子树是AVL树,他们的高度差小于等于1,那就是AVL树;否则不是.

      public class IsAVLTree {
      	public static boolean isAVL(TreeNode root) {
      		if (root==null) {
      			return true;
      		}
      		int diff=Math.abs(getHeigt(root.lchild)-getHeigt(root.rchild));
      		if (isAVL(root.lchild)&&isAVL(root.rchild)&&diff<=1) {
      			return true;
      		} else {
      			return false;
      		}
      	}
      	public static int getHeigt(TreeNode root) {
      		if (root==null) {
      			return 0;
      		}
      		return Math.max(getHeigt(root.lchild), getHeigt(root.rchild))+1;
      	}
      }
      
      class TreeNode{
      	int data;
      	TreeNode lchild;
      	TreeNode rchild;
      }
      
  2. 判断一个数是否回文(转换为字符数据,使用双指针法或者StringBuilder的reverse()方法)

    public static void main(String[] args) {
    int[] arr={1,2,3,4,5};
    printRandM(arr,3);//1 5 4
    System.out.println(isPalindrome(32456));//false
    System.out.println(isPalindrome(-12021));//true
    }

    //判断一个数是否是回文数
    public static boolean isPalindrome(int n){
        if(n==Integer.MIN_VALUE){
        //32位负数最小值,转不成正数,也明显不是回文数
            return false;
        }
        n=Math.abs(n);
        int help=1;
        while(n/help>=10){//防止help溢出
            help*=10;//使Help和n位数一样
        }
        while(n!=0){
            if((n/help)!=n%10){
                return false;//n的最高位不等于最低位,非回文
            }
            n=(n%help)/10;//n除去最高位和最低位
            help/=100;//使help变得跟n位数一样
        }
        return true;
    }
    

最后反问

总结:rabbitmq,springboot 只是使用,没有详细了解原理,相关问题没答上来

薄弱点:

  • Springboot还需要继续学习,了解原理
  • Rabbitmq常见问题的解决方案要熟悉,挺常问的
  • 自我介绍 一直很短,一分钟以内,想问下大家都是怎么自我介绍,要介绍的多细

第二天收到电话约二面

二面 8.12

  1. 接口和抽象类区别(接口是动作的抽象,抽象类是一种所属关系…)
  2. volatile作用(可见性,禁止指令重排),什么是可见性问题
  3. 常见容器(List,Set,Hashmap),Hashmap原理(数组 + 链表红黑树),resize() 过程,多线程会产生什么问题(循环链表),怎么产生循环链表(没答出来)
  4. 怎么解决HashMap多线程问题(加锁),说了ConcurrentHashMap的put过程
  5. 说说线程(CPU调度分派基本单位…)
  6. 进程如何同步(管道,命令管道,信号,信号量,共享内存,套接字),信号量怎么通信(P操作,V操作)
  7. 线程独有的对象(ThreadLocal,原理没说清)
  8. 类加载机制(双亲委派模型),有什么加载器,分别加载什么,怎么破坏双亲委派机制(重写loadClass方法),破坏双亲委派机制自己实现加载器加载java.lang.String可以吗(不可以,不懂怎么保证的)
  9. 标记-清理过程

代码:

  1. 单例模式
  2. 最长回文子串动态规划,中心扩散)
  3. 包含min函数的栈(栈 + 辅助栈)

最后反问环节

总的来说,面试官是个小姐姐,面试过程中会引导你,面试体验很棒

问题讨论:

  1. HashMap多线程下**循环链表**产生的原理,有大佬详细说一下嘛
  2. 破坏双亲委派机制后,怎么保证java.lang.String不能加载(java.lang.ClassLoaderd的preDefineClass 方***检查类名,发现以java作为一级包名,则抛出安全异常:禁止使用的包名)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值