阿裡內部面試總結

来源:http://www.cnblogs.com/RunForLove/archive/2016/07/12/5010724.html
-Advertisement-
Play Games

目錄: 1.StringBuffer和StringBuilder有什麼區別?假設有一個方法,方法內部需要定義一個對象,可能是StringBuffer或StringBuilder,接下來會多次append操作,方法結束時,返回這個對象的toString()結果,並且這個線程會被多線程併發訪問,請選擇這 ...


目錄:

  1. StringBuffer和StringBuilder有什麼區別?假設有一個方法,方法內部需要定義一個對象,可能是StringBuffer或StringBuilder,接下來會多次append操作,方法結束時,返回這個對象的toString()結果,並且這個線程會被多線程併發訪問,請選擇這個對象是被定義成StringBuffer或者StringBuilder?為什麼?
  2. synchronized有什麼用?如何使用?(偽代碼,把所有使用方式都分別列出來)
  3. ReentranLock類有什麼作用?它常用的方法有哪幾個?分別有什麼特點?
  4. 集群環境下多機器間進行同步操作有什麼可選的解決方案?(最好用偽代碼寫出關鍵部分)
  5. 列出樂觀鎖的設計要點和使用方法?
  6. 何為冪等性控制?舉一個例子說明你之前如何實現冪等性控制?(或在項目IDCM中如何實現冪等性控制?)
  7. spring實現aop用到的關鍵技術是什麼?
  8. HashMap和ConcurrentHashMap有什麼區別和特點?
  9. java.util.concurrent package下,你用過哪些類?分別有什麼用途和特點?
  10. 如果一張表數據量較大,影響了查詢性能,可以有哪些優化方案?建立索引有什麼原則?
  11. 說一說資料庫事務隔離級別的理解?(項目IDCM中是如何使用的?)
  12. Spring中註解@Component @Repository @Service @Controller的區別?(項目IDCM中context:component-scan註解掃描是如何配置的?)
  13.  線程池如何實現?實現線程池的常用的幾個類是怎麼樣的?如何用線程池創建一個單線程?
  14. 原子操作類AtomicInteger等等這些類的API的瞭解。

 

 

 

1.StringBuffer和StringBuilder有什麼區別?假設有一個方法,方法內部需要定義一個對象,可能是StringBuffer或StringBuilder,接下來會多次append操作,方法結束時,返回這個對象的toString()結果,並且這個線程會被多線程併發訪問,請選擇這個對象是被定義成StringBuffer或者StringBuilder?為什麼?

  答:StringBuffer是線程安全的;StringBuilder是線程不安全的。

1.先來看String StringBuffer StringBuilder定義。final修飾的類不能被繼承,即不能擁有子類。 
    public final class StringBuffer 
    public final class StringBuilder 
    public final class String 

2.關於appdend方法的源碼如下: 
    public synchronized StringBuffer append(String str) {
             toStringCache = null; 
             super.append(str); 
             return this;
    } 

    public StringBuilder append(String str) { 
        super.append(str); 
        return this; 
    } 
3.對於經常變動的字元串才會考慮使用StringBuilder和StringBuffer,使用StringBuilder效率比StringBuffer高,StringBuffer可以保證線程安全,而StringBuilder不能。        

2.synchronized有什麼用?如何使用?(偽代碼,把所有使用方式都分別列出來)

  答:synchronized是Java語言的關鍵字,同時也是一個可重入鎖。當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執行該段代碼。synchronized用於修飾方法和代碼塊。

package basic;

public final class TestSynchronized {

    public static void main(String[] args) {
        new Thread("線程A") {

            @Override
            public void run() {
                try {
                    print("線程A ...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
        new Thread("線程B") {

            @Override
            public void run() {
                try {
                    print("線程B ...");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

    public static synchronized void print(String str) throws InterruptedException {
        System.out.println("當前線程:" + Thread.currentThread().getName() + "執行開始");
        for (int i = 0; i < 10; i++) {
            System.out.println(str);
            Thread.sleep(2000);
        }
        System.out.println("當前線程:" + Thread.currentThread().getName() + "執行完畢");
    }
} 
// 代碼執行結果: 
//當前線程:線程A執行開始 
//線程A ... 
//線程A ... 
//線程A ... 
//線程A ... 
//線程A ... 
//線程A ... 
//線程A ... 
//線程A ... 
//線程A ... 
//線程A ... 
//當前線程:線程A執行完畢
//當前線程:線程B執行開始 
//線程B ... 
//線程B ... 
//線程B ... 
//線程B ... 
//線程B ... 
//線程B ... 
//線程B ... 
//線程B ... 
//線程B ... 
//線程B ... 
//當前線程:線程B執行完畢

  synchronized在修飾方法的同時,還可以修飾代碼塊,示例代碼如下:

package basic;

public class SynchronizedExample {

    public static void main(String[] args) {
        new Thread("線程A") {

            @Override
            public void run() {
                print("線程A");
            }
        }.start();
        new Thread("線程B") {

            @Override
            public void run() {
                print("線程B");
            }
        }.start();
    }

    public static void print(String str) {
        System.out.println("線程: " + Thread.currentThread().getName() + "開始執行");
        synchronized (SynchronizedExample.class) {
            for (int i = 0; i < 10; i++) {
                System.out.println(Thread.currentThread().getName() + "列印了信息:" + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
            }
        }
        System.out.println("線程: " + Thread.currentThread().getName() + "執行結束");
    }
}
// 代碼執行結果:
// 線程: 線程A開始執行
// 線程A列印了信息:0
// 線程: 線程B開始執行
// 線程A列印了信息:1
// 線程A列印了信息:2
// 線程A列印了信息:3
// 線程A列印了信息:4
// 線程A列印了信息:5
// 線程A列印了信息:6
// 線程A列印了信息:7
// 線程A列印了信息:8
// 線程A列印了信息:9
// 線程: 線程A執行結束
// 線程B列印了信息:0
// 線程B列印了信息:1
// 線程B列印了信息:2
// 線程B列印了信息:3
// 線程B列印了信息:4
// 線程B列印了信息:5
// 線程B列印了信息:6
// 線程B列印了信息:7
// 線程B列印了信息:8
// 線程B列印了信息:9
// 線程: 線程B執行結束

  接下來詳細說明synchronized在修飾方法的時候的細節。synchronized是對類的當前實例進行加鎖,防止其他線程同時訪問該類的該實例的所有synchronized塊,註意這裡是“類的當前實例”,類的兩個不同實例就沒有這種約束了。那麼static synchronized恰好就是要控制類的所有實例的訪問了,static synchronized是限制線程同時訪問jvm中該類的所有實例同時訪問對應的代碼快。實際上,在類中某方法或某代碼塊中有synchronized,那麼在生成一個該類實例後,該類也就有一個監視快,放置線程併發訪問改實例synchronized保護快,而static synchronized則是所有該類的實例公用一個監視快了,也就是兩個的區別了,也就是synchronized相當於this.synchronized,而static synchronized相當於Something.synchronized。

package basic;

public class SynchronizedExample {

    public static void main(String[] args) {
        final MySynchronized mySynchronized = new MySynchronized();
        new Thread("線程A") {

            @Override
            public void run() {
                mySynchronized.print("線程A");
            }
        }.start();
        new Thread("線程B") {

            @Override
            public void run() {
                mySynchronized.print("線程B");
            }
        }.start();
    }
}

class MySynchronized {

    public synchronized void print(String str) {
        System.out.println("線程: " + Thread.currentThread().getName() + "開始執行");
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "列印了信息:" + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
        }
        System.out.println("線程: " + Thread.currentThread().getName() + "執行結束");
    }
} 
// 代碼運行結果: 
//線程: 線程A開始執行 
//線程A列印了信息:0 
//線程A列印了信息:1 
//線程A列印了信息:2 
//線程A列印了信息:3 
//線程A列印了信息:4 
//線程A列印了信息:5 
//線程A列印了信息:6 
//線程A列印了信息:7
//線程A列印了信息:8 
//線程A列印了信息:9 
//線程: 線程A執行結束 
//線程: 線程B開始執行 
//線程B列印了信息:0 
//線程B列印了信息:1 
//線程B列印了信息:2 
//線程B列印了信息:3 
//線程B列印了信息:4 
//線程B列印了信息:5
//線程B列印了信息:6 
//線程B列印了信息:7 
//線程B列印了信息:8 
//線程B列印了信息:9 
//線程: 線程B執行結束 

package basic;

public class SynchronizedExample {

    public static void main(String[] args) {
        final MySynchronized mySynchronized_first = new MySynchronized();
        final MySynchronized mySynchronized_second = new MySynchronized();
        new Thread("線程A") {

            @Override
            public void run() {
                mySynchronized_first.print("線程A");
            }
        }.start();
        new Thread("線程B") {

            @Override
            public void run() {
                mySynchronized_second.print("線程B");
            }
        }.start();
    }
}

class MySynchronized {

    public synchronized void print(String str) {
        System.out.println("線程: " + Thread.currentThread().getName() + "開始執行");
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "列印了信息:" + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
        }
        System.out.println("線程: " + Thread.currentThread().getName() + "執行結束");
    }
}
//代碼運行結果: 
//線程: 線程A開始執行 
//線程A列印了信息:0 
//線程: 線程B開始執行 
//線程B列印了信息:0 
//線程A列印了信息:1 
//線程B列印了信息:1 
//線程A列印了信息:2 
//線程B列印了信息:2 
//線程A列印了信息:3
//線程B列印了信息:3 
//線程A列印了信息:4 
//線程B列印了信息:4 
//線程A列印了信息:5 
//線程B列印了信息:5 
//線程A列印了信息:6 
//線程B列印了信息:6 
//線程A列印了信息:7 
//線程B列印了信息:7 
//線程A列印了信息:8
//線程B列印了信息:8 
//線程A列印了信息:9 
//線程B列印了信息:9 
//線程: 線程A執行結束 
//線程: 線程B執行結束 

package basic;

public class SynchronizedExample {

    public static void main(String[] args) {
        final MySynchronized mySynchronized_first = new MySynchronized();
        final MySynchronized mySynchronized_second = new MySynchronized();
        new Thread("線程A") {

            @Override
            public void run() {
                mySynchronized_first.print("線程A");
            }
        }.start();
        new Thread("線程B") {

            @Override
            public void run() {
                mySynchronized_second.print("線程B");
            }
        }.start();
    }
}

class MySynchronized {

    public static synchronized void print(String str) {
        System.out.println("線程: " + Thread.currentThread().getName() + "開始執行");
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "列印了信息:" + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
        }
        System.out.println("線程: " + Thread.currentThread().getName() + "執行結束");
    }
}
//代碼運行結果: 
//線程: 線程A開始執行 
//線程A列印了信息:0
//線程A列印了信息:1 
//線程A列印了信息:2 
//線程A列印了信息:3 
//線程A列印了信息:4 
//線程A列印了信息:5 
//線程A列印了信息:6 
//線程A列印了信息:7
//線程A列印了信息:8 
//線程A列印了信息:9 
//線程: 線程A執行結束 
//線程: 線程B開始執行 
//線程B列印了信息:0 
//線程B列印了信息:1 
//線程B列印了信息:2 
//線程B列印了信息:3 
//線程B列印了信息:4 
//線程B列印了信息:5
//線程B列印了信息:6 
//線程B列印了信息:7 
//線程B列印了信息:8 
//線程B列印了信息:9 
//線程: 線程B執行結束

  上述代碼完整的展示了static synchronized和synchronized的用法。synchronized針對同一個實例不能訪問,針對不同的實例可以同時訪問。static synchronized針對所有的實例均不能同時訪問。synchronized本來就是修飾方法的,後來引申出synchronized修飾代碼塊,只是為了可以更精確的控制衝突限制的訪問區域,使得表現更加高效率。synchronized方法只能鎖定現階段的對象,而synchronized區塊可以鎖定指定的對象,指定的對象直接跟在synchronized()括弧之後。此外,synchronized關鍵字是不能繼承的,也就是說,基類的方法synchronized f(){} 在繼承類中並不自動是synchronized f(){},而是變成了f(){}。繼承類需要你顯式的指定它的某個方法為synchronized方法。還有synchronized不能被繼承,繼承時子類的覆蓋方法必須顯示定義成synchronized

  除了方法前用synchronized關鍵字,synchronized關鍵字還可以用於方法中的某個區塊中,表示只對這個區塊的資源實行互斥訪問。用法是: synchronized(object){/*區塊*/},它的作用域是object對象。當一個線程執行時,將object對象鎖住,另一個線程就不能執行對應的塊。synchronized方法實際上等同於用一個synchronized塊包住方法中的所有語句,然後在synchronized塊的括弧中傳入this關鍵字。當然,如果是靜態方法,需要鎖定的則是class對象。可能一個方法中只有幾行代碼會涉及到線程同步問題,所以synchronized塊比synchronized方法更加細粒度地控制了多個線程的訪問,只有synchronized塊中的內容不能同時被多個線程所訪問,方法中的其他語句仍然可以同時被多個線程所訪問(包括synchronized塊之前的和之後的)。

package basic;

public class TestSynchronizedObject {

    public static void main(String[] args) {
        final MyObject myObject_first = new MyObject();
        final MyObject myObject_seconde = new MyObject();
        new Thread("線程A") {

            @Override
            public void run() {
                myObject_first.print("線程A");
            }
        }.start();
        new Thread("線程B") {

            @Override
            public void run() { /* * 同一個實例,實現了互斥訪問 */
                myObject_first.print("線程B"); /* * 不同的實例,並不能夠實現互斥訪問 */
                myObject_seconde.print("線程B");
            }
        }.start();
    }
}

class MyObject {

    /**
     * * synchronized(this)的用法相當於synchronized直接修飾方法<br/>
     * * 只針對一個實例的時候有效,針對多個實例的時候無效
     */
    public void print(String str) {
        System.out.println("線程" + Thread.currentThread().getName() + "開始執行");
        synchronized (this) {
            for (int i = 0; i < 10; i++) {
                System.out.println(str + " ." + i + ". ");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
            }
        }
        System.out.println("線程" + Thread.currentThread().getName() + "執行結束");
    }
}




package basic;

public class TestSynchronizedObject {

    public static void main(String[] args) {
        final MyObject myObject_first = new MyObject();
        final MyObject myObject_seconde = new MyObject();
        new Thread("線程A") {

            @Override
            public void run() {
                myObject_first.print("線程A");
            }
        }.start();
        new Thread("線程B") {

            @Override
            public void run() {
                myObject_seconde.print("線程B");
            }
        }.start();
    }
}

class MyObject {

    /**
     * * synchronized(MyObject.class)的用法相當於static synchronized修飾方法<br/>
     * * 在針對多個實例的情況下,互斥有效,但是synchronized括弧後面要指定正確的對象信息
     */
    public void print(String str) {
        System.out.println("線程" + Thread.currentThread().getName() + "開始執行");
        /*
         * 1、synchronized(MyObjcet.class)可以正確的實現互斥效果 ,因為調用的是MyObject的對象。
         */
        synchronized (MyObject.class) {
            for (int i = 0; i < 10; i++) {
                System.out.println(str + " ." + i + ". ");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
            }
        }
        System.out.println("線程" + Thread.currentThread().getName() + "執行結束");
    }
}

  總結:synchronized方法是一種粗粒度的併發控制,在某一時刻,只能有一個線程執行該synchronized方法。synchronized塊則是一種細粒度的鬢髮控制,只會將塊中的代碼同步,位於方法內,synchronized塊之外的代碼是可以被多個線程同時訪問到的。關於synchronized修飾代碼塊的詳細細節可以參考附錄[1]和附錄[2]

3.ReentrantLock類有什麼作用?它常用的方法有哪幾個?分別有什麼特點?(讀法:Re-entrantLock)

  上面的的synchronized和ReentranLock是最經典的可重入鎖,在面試中經常有問到兩種鎖的對比。先介紹ReentranLock的使用和代碼示例,接著再分析ReentranLock和synchronized的具體區別。

4.集群環境下多機器間進行同步操作有什麼可選的解決方案?(最好用偽代碼寫出關鍵部分)

  reids

5.列出樂觀鎖的設計要點和使用方法?

6.何為冪等性控制?舉一個例子說明你之前如何實現冪等性控制?(或在項目IDCM中如何實現冪等性控制?)

7.spring實現aop用到的關鍵技術是什麼?

  當然是動態代理(這個網易面試面過的)。引申一下JDK中java提供的動態代理的應用,靜態代理和動態代理的關鍵區別。公共的介面subject,然後有委托類RealSubject和代理類ProxySubject。正所謂靜態代理只是在編譯階段就確定了代理類和委托來之間的關係。而動態代理則是,在運行時,才能確定具體的代理類和委托類之間的關係,因此寫此部分代碼要結合JDK的反射機制來實現。(代理介面)。

  代碼是死的,進程才是活的。所以說,運行時確定的委托類和代理類之間的關係,是根據運行時來決定的。

8.HashMap和ConcurrentHashMap有什麼區別和特點?

9.java.util.concurrent package下,你用過哪些類?分別有什麼用途和特點?

10.如果一張表數據量較大,影響了查詢性能,可以有哪些優化方案?建立索引有什麼原則?

11.說一說資料庫事務隔離級別的理解?(項目IDCM中是如何使用的?)

12.Spring中註解@Component @Repository @Service @Controller的區別?(項目IDCM中context:component-scan註解掃描是如何配置的?)

13.線程池如何實現?實現線程池的常用的幾個類是怎麼樣的?如何用線程池創建一個單線程?

14.原子操作類AtomicInteger等等這些類的API的瞭解?

 

 

附錄:

[1] https://segmentfault.com/q/1010000005945389?_ea=960340 

[2] https://segmentfault.com/q/1010000005944096?_ea=959633

[3] 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • UML關係:繼承(泛化)、實現、依賴、關聯、聚合、組合的聯繫與區別 ...
  • 描述 風景迷人的小城Y市,擁有n個美麗的景點。由於慕名而來的游客越來越多,Y市特意安排了一輛觀光公交車,為游客提供更便捷的交通服務。觀光公交車在第0分鐘出現在1號景點,隨後依次前往2、3、4……n號景點。從第i號景點開到第i+1號景點需要Di分鐘。任意時刻,公交車只能往前開,或在景點處等待。 設共有 ...
  • 1.打開pip的文檔官網 https://pip.pypa.io/en/stable/ ,進入installation。在installation里,我們需要的是get-pip.py這個腳本。 選中後下載,我把它另存到C盤。 2.打開cmd命令行,打開C盤根目錄並運行get-pip.py腳本。當然, ...
  • 游戲服務端架構 介紹 端游、手游服務端常用的架構是什麼樣的? http://www.zhihu.com/question/29779732 根據知乎問答文章整理而成。 作者:韋易笑 謝邀,手游頁游和端游的服務端本質上沒區別,區別的是游戲類型。 類型1:卡牌、跑酷等弱交互服務端 卡牌跑酷類因為交互弱,... ...
  • JNA 調用 dll 庫時,保錯: 我環境是 64 位 win7. java.lang.UnsatisfiedLinkError: %1 不是有效的 Win32 應用程式。 解決方法, 刪掉了系統中的 64 位的 JDK,就沒有再報該錯誤了。 ...
  • Java.util.zip 提供用於讀寫標準 ZIP 和 GZIP 文件格式的類。 還包括使用 DEFLATE 壓縮演算法(用於 ZIP 和 GZIP 文件格式)對數據進行壓縮和解壓縮的類。 依賴 Jdk 編寫該工具類,不依賴任何第三方 jar,隨用隨取,實現功能大體如下: 1.目錄級別遞歸壓縮與解壓 ...
  • c++ auto_ptr智能指針 該類型在頭文件memory中,在程式的開通通過 #include<memory> 導入,接下來講解該智能指針的作用和使用。 使用方法: auto_ptr<type> ptr(new type()); 這是該指針的定義形式,其中 type 是指針指向的類型,ptr 是 ...
  • 前文Selenium2入門(一)說到Selenium是Web 應用程式測試框架,那麼如果對一個簡單的web應用需求:打開瀏覽器,登錄百度首頁,輸入“歐洲杯”關鍵詞,點擊搜索按鈕 這一系列操作,能否用Selenium進行執行呢?可以,下麵介紹的WebDriver就是可以完成這項任務的方法之一: Web ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...