【刷面試題】阿里畢玄:來測試下你的Java編程能力 - 題解 01-15


原文鏈接 開發者社區> 面試一點通> 正文

阿里畢玄:來測試下你的Java編程能力

1.基於BIO實現的Server端,當建立了100個連接時,會有多少個線程?如果基於NIO,又會是多少個線程? 為什么?

  1. BIO:默認,同步阻塞IO流, 每個獲取的連接都需要創建一個新的處理線程,故需要100個處理線程,服務端還需要一個1個Accept線程來接受連接請求;所以當連接建立后,將這個連接的IO讀寫放到一個專門的處理線程,所以當建立100個連接時,通常會產生1個Accept線程 + 100個處理線程

  2. NIO: 同步非阻塞IO流, NIO通過事件來觸發。
    a.NIO有Selector,通過while循環檢查或系統調用通知,檢查多個channel的狀態是否可讀寫,所以可以用1個線程管理多個channel。NIO在處理IO的讀寫時,當從網卡緩沖區讀或寫入緩沖區,這個過程是串行的,所以用太多線程處理IO事件其實也沒什么意義,連接事件由於通常處理比較快,用1個線程去處理就可以。
    b.IO事件呢,通常會采用cpu core數+1或cpu core數 * 2,這個的原因是IO線程通常除了從緩沖區讀寫外,還會做些比較輕量的例如解析協議頭等,這些是可以並發的,為什么不只用1個線程處理,是因為當並發的IO事件非常多時,1個線程的效率不足以發揮出多core的CPU的能力,從而導致這個地方成為瓶頸,這種在分布式cache類型的場景里會比較明顯,按照這個,也就更容易理解為什么在基於Netty等寫程序時,不要在IO線程里直接做過多動作,而應該把這些動作轉移到另外的線程池里去處理,就是為了能保持好IO事件能被高效處理。 從上面可以看出,對於大多數需要建立大量連接,但並發讀寫並不會同時的場景而言,NIO的優勢是非常明顯的。

2.通常來說基於NIO實現的Server端,會用多少個線程去處理IO事件,為什么?

  1. 問的是Server端會用多少個線程去處理IO事件
  2. 2*cpu核數 或 cpu核心數+1 左右 該答案參考自:http://www.sohu.com/a/298857998_494946

3. 一個典型的客戶端集群->LB->服務端集群這樣的結構中,如客戶端采用連接池,長連接的方式,這種設計你覺得可能會出現什么問題?如果客戶端采用的是單個長連接的方式呢?如果有問題,你覺得應該怎么解決?

LB 即LoadBlance(負載均衡,如nginx)
a. 如客戶端采用連接池,長連接的方式,長連接建立后一般不會斷開,也就是某個client會固定請求到某台server,隨着擴容縮容、服務器上下線,會負載不均衡。
b. 解決方案:比較根本的解決方法是在這樣的場景里把中間的LB去掉,換成類似通過服務注冊/發現的機制來解決。重啟負載高的機器.不用LB.

4.cglib和Java的動態代理相比,具體有什么不同?

  1. 說白了就是SpringAop的兩個實現模式,扔個連接(AOP-snailclimb)[https://snailclimb.gitee.io/javaguide/#/docs/system-design/framework/spring/Spring?id=aop]; 在Java中一般采用JDK動態代理模式,Spring AOP 同時支持 CGLIB、ASPECTJ、JDK動態代理
    a.cglib 通過字節碼操作生成代理, 能夠對類做代理
    b.JDK通過反射接口生成代理,所以被代理類必須有實現接口。

(不是很懂,先扔着) 5. 在基於Netty實現FrameDecoder時,下面兩種代碼的表現會有什么不同?

第一種的處理方式可以有效減少IO線程池和業務處理線程池的上下文切換,從而提高IO線程的處理效率。

6. 用Executors.newCachedThreadPool創建的線程池,在運行的過程中有可能產生的風險是?

阿里規范不建議這么做, Executors.newCachedThreadPool()會一直創建大量線程直到OOM.

7. new ThreadPoolExecutor(10,100,10,TimeUnit.MILLISECONDS,new LinkedBlockingQueue(10));一個這樣創建的線程池,當已經有10個任務在運行時,第11個任務提交到此線程池執行的時候會發生什么,為什么?

此題考查ThreadPoolExecutor的workQueue [工作、阻塞隊列]的簡單用法, 所以應該第11個任務會加進隊列中,而非開啟第11個線程來處理。

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
}

workQueue如下:
1) 同步阻塞隊列:core-》max-》超出max后直接拋異常 ,
2) 鏈表阻塞隊列:先core-》隊列-》max-》再拋異常,速度快點;
3)數組,有界;
4)延遲隊列:用於定時任務
5)優先級..

8. 實現一個自定義的ThreadFactory的作用通常是?

  1. 通常的作用是給線程取名字,便於以后查問題,查日志。
  2. 用法

public class ThreadFactoryMain implements ThreadFactory{
 
    private final String groupName;
    private AtomicInteger nextId = new AtomicInteger(1);
 
    public ThreadFactoryMain(String groupName) {
        this.groupName = "ThreadFactoryMain -" + groupName + "-worker-";
    }
 
    @Override
    public Thread newThread(@NotNull Runnable r) {
        String threadName = groupName + nextId.incrementAndGet(); // 名稱中添加一個自增的id
        Thread thread = new Thread(null,r,threadName,0);
        return thread;
    }
}
———————————————
原文鏈接:https://blog.csdn.net/z69183787/article/details/91126481

9. 除了用Object.wait和Object.notifyAll來實現線程間的交互外,你還會常用哪些來實現?

考查JUC包, 也就是Java並發控制的常見機制
java的JUC包里的不管是BlockingQueue的實現,還是各種類似CountDownLatch、CyclicBarrier,都可以用來實現線程的交互。

CountDownLatch: 倒計數門閂,https://www.cnblogs.com/zhazhaacmer/p/11365805.html
CyclicBarrier: 循環柵欄,維持最低的線程並發量
BlockingQueue: 阻塞隊列,常見三類使用方式,阻塞式、超時式、查詢完直接返回式對資源取拿
參考:https://blog.csdn.net/zhou920786312/article/details/100175698

10. 為什么ConcurrentHashMap可以在高並發的情況下比HashMap更為高效?

分段式鎖,以及巧妙的使用final、volatile,
參考:https://snailclimb.gitee.io/javaguide/#/docs/java/Multithread/並發容器總結?id=二-concurrenthashmap

11. AtomicInteger、AtomicBoolean這些類之所以在高並發時高效,共同的原因是?

CAS+volatile機制,例如AtomicInteger 類主要利用 CAS (compare and swap) + volatile 和 native 方法來保證原子操作,從而避免 synchronized 的高開銷,執行效率大為提升。
參考:https://snailclimb.gitee.io/javaguide/#/docs/java/Multithread/Atomic?id=1-atomic-原子類介紹

12. 請合理的使用Queue來實現一個高並發的生產/消費的場景,給些核心的代碼片段。

例如通常可能會借助LinkedBlockingQueue來實現簡單的生產/消費, 或者使用BlockingQueue阻塞隊列來對ftp線程池的線程進行管理,頻繁的存取和釋放.

13. 請實現讓10個任務同時並發啟動,給些代碼片段。

定時任務,QuartZ
或者使用JUC的CyclicBarrier: 循環柵欄,維持最低的線程並發量

14. 在Java程序運行階段,可以用什么命令行工具來查看當前Java程序的一些啟動參數值,例如Heap Size等。

ps -ef | grep java
jinfo -flags

15. 用什么命令行工具可以查看運行的Java程序的GC狀況,請具體寫出命令行格式。

jstat -gc pid 5000
jstat -gcutil [pid] [頻率,例如多少毫秒一次] [多少次]
  • 如果已經打開了gc log,可以直接查看gc日志。
  • gc log通常怎么打開,具體的命令行參數,一段gc log的解讀


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM