阿里妈妈技术联盟Java后端研发四面总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kukubao207/article/details/89035468

昨天面完阿里的四面,持续了86分钟,算是对我这几个月学习成果的检验,暴露了很多很多的问题,心态有点崩了,我又买了两本书《大型网站技术架构》和《大型分布式网站架构》,四面对我来说比较困难,问了我如何搭建一个百亿级高并发高可用的网站,非常开放性的问题。但是我没有回答好,也问了一些听起来不难,回答起来很难受的问题。
我的每一次回答,都是基于自己的理解出发,发散性地想一条说一条,理解的深的就深入讲,但他会打断我,他说希望听到总结性的回答,我不知道是不是压力面。
数据库的优化我说我从下面几个方面做一个介绍:
1.数据库的底层优化,配置一些参数,像innodb_cache_size。
2.数据库的慢查询日志定位查的慢的sql,到索引优化。
3.分库分表的一些策略。
4.读写分离,主从同步的角度。
但是讲到一半被打断大脑一片空白,希望我先总结介绍,然后我在想我不是在总结吗,懵逼了。

可能这一次面试没有很好的发挥,或许最终会倒在这一面上,但是我意识到自己和顶尖优秀的那部分同学的差距。是平时的思考总结,平时的积累,我确实做了很多项目,但却没有停下去思考总结。项目本身用到的技术,他们之间的横向比较,每一种技术的特点,细节和坑点所在,这是需要慢慢积累的,才能做到在面试的时候脱口而出,给出一个类似于树形结构的思维导图。

下面给出一个阿里Java后端四面面经
2019年03月12日-2019年04月03日
阿里一面(60min)(基础面)
1、Netty、多线程相关
他:讲一下TCP粘包原理,怎么解决。
他:讲一下Reactor线程模型。
他:Netty的线程池和普通的线程池相比,性能提高的原因。
他:讲一下用户态和内核态的区别。
他:Java可以用到内核态吗。
他:你刚才说Netty是事件驱动的,如何怎么理解事件驱动。
他:讲一下Java线程池有哪些参数,原理。
他:讲一下Synchronize和Lock的区别。
追问:讲一下AQS。
追问:讲一下CAS。

2、JVM虚拟机
他:讲一下JVM虚拟机的几个内存区域。
他:讲一下内存分代。
他:一定是8:1吗?可以调整这两个区域的大小吗?
他:是什么参数?
他:你知道些什么参数?
他:讲一下MinorGC和FullGC。
他:讲一下垃圾收集器。
追问:你刚才说CMS是并发标记并发清除,那CMS在并发收集的时候需要Stop The World吗?
追问:为什么要等所有线程执行到SafePoint呢?
他:讲一下内存分配有哪些规则。
他:Java的类加载器有哪些。
追问:项目中有自己实现过类加载器吗。

3、 Java基础语法和集合框架源码理解
他:hashcode()和equal()?
他:HashMap的put,他是怎样一个过程?
他:HashMap的load factor了解吗?
他:Java的受检异常和非受检异常有什么区别?
他:你知道有哪些异常吗,说一下平时遇到过哪些异常?
他:如果try里面return了,finally会执行吗?
他:如果finally里面还有异常,会怎么样?
他:其实我刚刚这个问题有点迷惑性,你回答还会继续抛出异常就可以了。

4、数据库
他:left join和right join的区别。
他:InnoDB和MyIsam的区别,这里我提到了MVCC。
追问:说一下对InnoDB的MVCC的理解。
追问:Update的时候MVCC是怎样的过程。

5、Spring
他:@Autowired和@Resource的区别。
他:说说你对Spring Boot的理解。
他:讲一下Spring Cloud的组件。

6、设计模式
他:说说你知道的设计模式。
他:观察者模式如何实现。
7、你最近在看哪些书?
8、有其他Offer吗?
9、有什么问题吗?

阿里二面(30min)(代码面)
下午甩给我一个链接,让我2小时内实现这个题目(要求多线程实现)文末附上当时写的代码,大佬反馈说写的太长了,有更简便的实现方法。
题目:按文件大小排序,统计一个目录下按文件大小从高到底排序的TOP20个文件。
输入:一个目录,如/home/
输出:按文件大小排序的TOP20个文件
一、题是你做的吗。
二、讲下解题思路。
三、解题过程中有没有遇到什么问题。
四、平时用什么工具开发,有用过IDEA的哪些插件。
五、平时怎么进行单元测试,用哪些工具。
六、有没有处理线上问题的经验。
七、如果面对一个高并发的业务,要做哪些考虑呢。
八、做过几个Java后端项目。
九、上次面试学到了什么。
十、今天面试学到了什么。
十一、对你而言最有意义的一本书是什么。

阿里三面(70min)(项目面)
这一面主要聊了项目,所以持续时间比较久
一、聊一下项目,结构、规模、并发量、技术原理等角度。
二、你的项目的大小扩充一千倍,你觉得系统性能瓶颈在哪里,架构要怎么变化。
三、讲一下浏览器访问一个网站的全过程。
四、数据库的隔离性、锁、锁带来的问题。
五、给定两个文件,文件里面有每行一个数,求交集。(数据量10G,内存1G)

阿里四面(80min)(这一面侧重你平时的学习方式、思考习惯,夹杂基础)
一、要搭建一个高性能网站,你会采取哪些方式?
他:你讲了很多总结起来就是负载均衡和缓存,还有别的吗,能不能总结性地给出一些方案,不需要深入介绍。
二、要搭建一个高可用性网站,你会采用哪些方式?
三、你对操作系统、计算机网络这些都知道的吧?那我问你一个基础的啊,你讲一下操作系统有哪些内存分配算法。
PS:这里我讲了LRU、FIFO、时钟置换,但是讲的磕磕碰碰,很慢,我说前两天还刚手写过一个LRU并发插入和查找O(1)的数据结构,大佬不太满意,问我还有没有别的,常用的。我就想不起来了,他问我是不是没准备操作系统,我说是,其他公司也很少问到这个知识点,如果要用的话,我看一眼就能捡起来,他说但是我们招同学就是希望基础更为扎实的,我说操作系统一些概念的理解我还是到位的,他也没有继续问了。
四、设计模式有哪些原则?能不能做一个总结性的介绍?
PS:这个题我也是慢吞吞地答了5个设计原则,第6个真想不起来了,气氛就特别尴尬,给他的感觉是我的基础不扎实吧。他说远远不止6大设计原则,其实还有很多其他的。我说我没有背过,他说这不是背,而是理解记忆。
这里给自己做一个总结吧
1.单一职责原则:这个类尽量只负责一个功能,也就是说,引起该类发生变化的原因只有一个
2.开闭原则:面对扩展开放,面对修改关闭
3.迪米特法则(最小知识原则):
4.依赖倒置原则:
5.里式替换原则
6.接口隔离原则
五、你刚才说设计模式,你知道哪些设计模式?能不能做一个总结性的介绍?
六、设计模式在你的项目中有哪些应用?
七、你觉得设计模式是为了做什么的?
八、你对Hibernate和Mybatis这些东西有做过总结吗?
九、你Spring、Spring Boot、Spring MVC、Spring Cloud这些东西都用过,那给我来一个总结性的介绍吧。
十、1T文件128G内存求TOP10频率热词。
十一、说说你对面向对象、面向过程等的理解,你觉得他对于开发人员来说有什么意义。

下面那道多线程题的一个题解,很多细节还可以改进,但是两个小时只能做到这样了。

package tx;

import java.io.File;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.PriorityBlockingQueue;

public class Main {
    public static File[] filelist = new File[100000];   //存放文件
    public static int idx = 0;                          //统计总文件数量
    public static List<File> res = new ArrayList<>();   //存放结果
    public static int block = 10000;                    //拆分块的大小
    public static int k = 20;                           //找topK
    public static CountDownLatch latch;
    public static PriorityBlockingQueue<File> priorityBlockingQueue = new PriorityBlockingQueue<File>(k, new cmp());

    public static class cmp implements Comparator<File> {
        @Override
        public int compare(File f1, File f2) {
            if (f1.length() > f2.length())
                return -1;
            else if (f1.length() < f2.length())
                return 1;
            else
                return 0;
        }
    }

    public static void main(String[] args) {
        //1.递归搜索文件路径,找出所有文件并保存
        getFileList("/Users/wjq/Desktop");

        //2.拆分文件成为num块,开num个线程去处理
        int num = idx / block;
        latch = new CountDownLatch(num);
        for (int i = 0; i < num; i++) {
            int start = i * block, end = Math.min((i + 1) * block - 1, idx - 1);
            File[] tempF = new File[Math.min(block, end - start + 1)];
            for (int k = 0, j = start; j <= end; j++, k++)
                tempF[k] = filelist[j];
            Thread mythread = new MyThread(tempF, 0, block - 1);
            mythread.start();
        }
        System.out.println("所有线程已经完成工作");
        try {
            latch.await();
        } catch (Exception e) {
            e.printStackTrace();
        }

        //3.输出结果
        for (int i = 0; i < k; i++) {
            File curFile = priorityBlockingQueue.poll();
            System.out.println(curFile.getName() + " : " + curFile.length());
        }
    }

    public static void getFileList(String strPath) {
        File[] files = new File(strPath).listFiles();
        if (files == null)
            return;
        for (int i = 0; i < files.length; i++) {
            if (files[i].isDirectory())
                getFileList(files[i].getAbsolutePath());
            else
                filelist[idx++] = (files[i]);
        }
    }

    public static class MyThread extends Thread {
        private int lo;
        private int hi;
        private File[] file;

        public MyThread(File[] file, int lo, int hi) {
            this.file = file;
            this.lo = lo;
            this.hi = hi;
        }

        public void run() {
            try {
                while (lo < hi) {
                    int onePartition = partition(file, lo, hi);
                    if (onePartition == k) {
                        break;
                    } else if (onePartition > k) {
                        hi = onePartition - 1;
                    } else if (onePartition < k) {
                        lo = onePartition + 1;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                for (int i = 0; i < k; i++) {
                    priorityBlockingQueue.add(file[i]);
                }
                latch.countDown();
            }
        }

        public int partition(File[] nums, int start, int end) {
            int index = start;
            File endFile = nums[end];
            for (int i = start; i < end; i++) {
                if (nums[i].length() > nums[end].length()) {
                    //交换两个file的位置
                    File temp = nums[i];
                    nums[i] = nums[index];
                    nums[index] = temp;
                    index++;
                }
            }
            File temp = nums[index];
            nums[index] = endFile;
            nums[end] = temp;
            return index;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/kukubao207/article/details/89035468