阿里媽媽技術聯盟Java後端研發五輪技術面總結

2019年03月12日內推簡歷投遞
2019年04月19日面完HR面
2019年04月30日收到錄取意向書
部門:阿里集團-阿里媽媽事業羣-阿里媽媽事業部-聯盟業務

阿里一面(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.接口隔離原則:一個類對另外一個類的依賴性應當是建立在最小的接口上
五、你剛纔說設計模式,你知道哪些設計模式?能不能做一個總結性的介紹?
單例、簡單工廠、工廠方法、抽象工廠、觀察者、命令、裝飾器、迭代器、策略、模板方法、適配器等。
六、設計模式在你的項目中有哪些應用?
在遊戲項目中,用過工廠模式、單例模式、裝飾器模式
在Spring Cloud中,Feign這個組件是用動態代理的方式實現的
在Spring中,創建bean的時候用了單例模式,AOP用了動態代理模式,ApplicationContext用了工廠模式。
在Java中,Iterator用了迭代器模式,String常量池和Integer.valueOf等緩存策略,用了享元模式,IO相關類(InputStream、OutputStream)用了裝飾器模式,StringBuffer、StringBuilder用了建造者模式。
七、你覺得設計模式是爲了做什麼的?
八、對Hibernate和Mybatis做個比較。
九、你Spring、Spring Boot、Spring MVC、Spring Cloud這些東西都用過,那給我來一個總結性的介紹吧。然後又覺得說的太多了,改口說對比一下Spring Boot和Spring的區別吧。
整體來看,Spring MVC和Spring Boot都屬於Spring,Spring MVC 是基於Spring的一個 MVC 框架,而Spring Boot 是基於Spring的一套快速開發整合包。
有關Spring和Spring Boot的對比
1.Spring需要做很多配置,定義bean就包括三種方式(xml、註解、Java代碼),而Spring Boot儘可能自動做一些配置。
2.Spring Boot內置Tomcat、Jetty等容器,就不需要去部署了,Spring則需要。
3.Spring Boot提供pom文件簡化配置,當我們引入核心依賴時,會自動引入其他依賴。
十、1T文件128G內存求TOP10頻率熱詞。
十一、說說你對面向對象、面向過程等的理解,你覺得他對於開發人員來說有什麼意義。

阿里五面(44min)(側重技術廣度和深度)
你知道哪些數據庫?對比一下
講了Redis、Memcache、MongoDB、Mysql
追問:你們用的Redis的集羣,怎麼做的?
我:Redis的集羣有三種方式實現,我用的是官網的那種,不需要插件,直接配置的。
追問:說了一些我聽不懂的話
我:不知道
你知道Elastic Search之類的數據庫嗎?
講了一下大數據實驗時候用過,原理不知道
你知道RabbitMQ、Kafka、RocketMQ、ActiveMQ嗎?
沒有對比過
你爲什麼選擇RabbitMQ?
就看着挑了一個
你對機器學習算法有了解嗎?
我講到決策樹,按照信息增益選擇特徵作爲節點進行分裂。
信息增益和熵是一個東西嗎?
不知道
你知道有哪些迴歸器?
決策樹、隨機森林、Xgboost、樸素貝葉斯等,具體原理不瞭解,只是應用,調參。
你覺得你有什麼亮點?
我覺得我對Mysql的InnoDB比較熟悉
你講一下Mysql的InnoDB的原理吧
講了索引、鎖、redo log、undo log、插入緩衝
你對操作系統底層的鎖是怎麼實現有了解嗎?
我知道的是操作系統是通過信號量、PV操作來實現的,臨界區巴拉巴拉。
我不知道這算不算底層。
還有別的嗎?你知道一個sql語句的在存儲引擎層面的解析過程嗎?
我不知道。
之前數據結構都沒怎麼問,你對數據結構和算法哪些比較熟悉?
鏈表、二叉樹、圖(深搜廣搜最短路)、字符串的KMP等算法書上有的都知道吧
你平時二叉樹哪些寫的多?
普通的二叉樹、查找二叉樹、平衡二叉樹、B樹、B+樹、前綴樹、紅黑樹,紅黑樹沒有實現過,其他的都有實現或者看過代碼。
講一下AVL、B樹、B+樹
AVL是高度平衡,巴拉巴拉
B樹的分裂巴拉巴拉
B+樹葉子節點之間有鏈表
還有別的嗎
還有一個項目之前沒聊過的可以聊聊,巴拉巴拉
好的,就到這裏把,你還有什麼問題嗎

HR面(27min)
講下你的項目,不用描述技術細節
聊下你的職業規劃?
你有哪些愛好?
最近看的電影是什麼?
你覺得你的優點和缺點是什麼?
有其他Offer嗎?
你的話應該沒什麼問題,過幾天可能會發Offer

下面那道多線程題的一個題解,細節還可以改進。

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;
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章