天道不一定酬所有勤
但是,天道只酬勤

lol英雄联盟:國內Java面試總是問StringBuffer,StringBuilder區別是啥?檔次為什么這么低?

英雄联盟充值记录 www.frhrb.icu 這是一個知乎上面很火的問題(https://www.zhihu.com/question/50211894),下面是我關于這個問題的回答,截止今天,這個答案收獲了500+贊和70+評論。

原答案

這個問題只是開個場,熱個身而已啊。

StringBuffer,StringBuilder區別是啥?

什么是線程安全?

如何保證線程安全?

什么是鎖?死鎖?

synchronized的實現原理是什么?

有了synchronized,還要volatile干什么?

synchronized的鎖優化是怎么回事?(鎖粗化?鎖消除?自旋鎖?偏向鎖?輕量級鎖?)

知道JMM嗎?(原子性?可見性?有序性?)

Java并發包了解嗎?

那什么是fail-fast?什么是fail-safe?

什么是CopyOnWrite?

那AQS呢?那CAS呢?

CAS都知道,那樂觀鎖一定知道了?

樂觀鎖悲觀鎖區別是什么?

數據庫如何實現悲觀鎖和樂觀鎖?

數據庫鎖有了解么?行級鎖?表級鎖?共享鎖?排他鎖?gap鎖?next-key lock?

數據庫鎖和隔離級別有什么關系?

數據庫鎖和索引有什么關系?

什么是聚簇索引?非聚簇索引?最左前綴是什么?B+樹索引?聯合索引?回表?

分布式鎖有了解嗎?

Redis怎么實現分布式鎖?

為什么要用Redis?

Redis和memcache區別是什么?

Zookeeper怎么實現分布式鎖?

什么是Zookeeper?

什么是CAP?

什么是BASE?和CAP什么區別?

CAP怎么推導?如何取舍?

分布式系統怎么保證數據一致性?

啥是分布式事務?分布式事務方案?

那么,最后了,來手寫一個線程安全的單例吧?

不用synchronized和lock能實現線程安全的單例嗎?

這你都能答上?那好吧,你給我解釋下什么是Paxos算法吧?

卒~!

部分答案

針對以上的問題,我給一些答案,希望大家都能有所收獲。這些答案也都是從我的博客中歷史文章總結出來的。

部分問題簡單幾句可以說的清楚的,我就直接貼答案了,比較復雜的,我貼個傳送門。

但是,以下答案可能并不完整,比如一些比較類的,我可能只說重點或者和這個知識體系有關的關鍵點,所以希望讀者可以根據下面的問題,完善每一個問題的答案。

StringBuffer,StringBuilder區別是啥?

StringBuffer是線程安全的,而StringBuilder是非線程安全的。

什么是線程安全?

線程安全是編程中的術語,指某個函數、函數庫在并發環境中被調用時,能夠正確地處理多個線程之間的共享變量,使程序功能正確完成。即在多線程場景下,不發生有序性、原子性以及可見性問題。

如何保證線程安全?

Java中主要通過加鎖來實現線程安全。通常使用synchronized和Lock

什么是鎖?死鎖?

死鎖是指兩個或兩個以上的進程在執行過程中,由于競爭資源或者由于彼此通信而造成的一種阻塞的現象,若無外力作用,它們都將無法推進下去。此時稱系統處于死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程。

死鎖的發生必須具備以下四個必要條件:互斥條件、請求和保持條件、不剝奪條件、環路等待條件

死鎖的解決辦法就是破壞以上四種必備條件中的一個或者多個。

synchronized的實現原理是什么?

深入理解多線程(一)——Synchronized的實現原理 深入理解多線程(四)—— Moniter的實現原理 再有人問你synchronized是什么,就把這篇文章發給他

有了synchronized,還要volatile干什么?

volatile通常被比喻成”輕量級的synchronized“,volatile可以保證可見性和有序性,實現原理是通過內存屏障實現的。

volatile有一個重要的作用,是synchronized不具備的,那就是禁止指令重排序。這一特點在雙重校驗鎖實現單例的時候有用到,雖然使用了synchronized關鍵字,但是如果不用volatile修飾單例對象,就會存在問題。

深入理解Java中的volatile關鍵字 再有人問你synchronized是什么,就把這篇文章發給他。

synchronized的鎖優化是怎么回事?(鎖粗化?鎖消除?自旋鎖?偏向鎖?輕量級鎖?)

深入理解多線程(五)—— Java虛擬機的鎖優化技術

知道JMM嗎?(原子性?可見性?有序性?)

Java內存模型(Java Memory Model ,JMM)是一種符合內存模型規范的,屏蔽了各種硬件和操作系統的訪問差異的,保證了Java程序在各種平臺下對內存的訪問都能保證效果一致的機制及規范。

再有人問你Java內存模型是什么,就把這篇文章發給他。

Java并發包了解嗎?

java.util.concurrent包(J.U.C)中包含的是java并發編程中有用的一些工具類,包括幾個部分:

1、locks部分:包含在java.util.concurrent.locks包中,提供顯式鎖(互斥鎖和速寫鎖)相關功能;

2、atomic部分:包含在java.util.concurrent.atomic包中,提供原子變量類相關的功能,是構建非阻塞算法的基??;

3、executor部分:散落在java.util.concurrent包中,提供線程池相關的功能;

4、collections部分:散落在java.util.concurrent包中,提供并發容器相關功能;

5、tools部分:散落在java.util.concurrent包中,提供同步工具類,如信號量、閉鎖、柵欄等功能;

那什么是fail-fast?什么是fail-safe?

我們通常說的Java中的fail-fast機制,默認指的是Java集合的一種錯誤檢測機制。當多個線程對部分集合進行結構上的改變的操作時,有可能會產生fail-fast機制,這個時候就會拋出ConcurrentModificationException。

ConcurrentModificationException,當方法檢測到對象的并發修改,但不允許這種修改時就拋出該異常。

為了避免觸發fail-fast機制,導致異常,我們可以使用Java中提供的一些采用了fail-safe機制的集合類。

這樣的集合容器在遍歷時不是直接在集合內容上訪問的,而是先復制原有集合內容,在拷貝的集合上進行遍歷。

java.util.concurrent包下的容器都是fail-safe的,可以在多線程下并發使用,并發修改。同時也可以在foreach中進行add/remove 。

一不小心就踩坑的fail-fast是個什么鬼?

什么是CopyOnWrite?

Copy-On-Write簡稱COW,是一種用于程序設計中的優化策略。其基本思路是,從一開始大家都在共享同一個內容,當某個人想要修改這個內容的時候,才會真正把內容Copy出去形成一個新的內容然后再改,這是一種延時懶惰策略。

CopyOnWrite容器即寫時復制的容器。通俗的理解是當我們往一個容器添加元素的時候,不直接往當前容器添加,而是先將當前容器進行Copy,復制出一個新的容器,然后新的容器里添加元素,添加完元素之后,再將原容器的引用指向新的容器。

一不小心就踩坑的fail-fast是個什么鬼?

那AQS呢?那CAS呢?

AQS(AbstractQueuedSynchronizer),即隊列同步器。它是構建鎖或者其他同步組件的基礎框架(如ReentrantLock、ReentrantReadWriteLock、Semaphore等),JUC并發包的作者(Doug Lea)期望它能夠成為實現大部分同步需求的基礎。它是JUC并發包中的核心基礎組件。

CAS是項樂觀鎖技術,當多個線程嘗試使用CAS同時更新同一個變量時,只有其中一個線程能更新變量的值,而其它線程都失敗,失敗的線程并不會被掛起,而是被告知這次競爭中失敗,并可以再次嘗試。

CAS 操作包含三個操作數 —— 內存位置(V)、預期原值(A)和新值(B)。如果內存位置的值與預期原值相匹配,那么處理器會自動將該位置值更新為新值。否則,處理器不做任何操作。無論哪種情況,它都會在 CAS 指令之前返回該位置的值。(在 CAS 的一些特殊情況下將僅返回 CAS 是否成功,而不提取當前值。)CAS 有效地說明了“我認為位置 V 應該包含值 A;如果包含該值,則將 B 放到這個位置;否則,不要更改該位置,只告訴我這個位置現在的值即可?!閉餛涫島屠止鬯某逋患觳?數據更新的原理是一樣的。

樂觀鎖的一種實現方式——CAS

CAS都知道,那樂觀鎖一定知道了?

樂觀鎖( Optimistic Locking ) 相對悲觀鎖而言,樂觀鎖假設認為數據一般情況下不會造成沖突,所以在數據進行提交更新的時候,才會正式對數據的沖突與否進行檢測,如果發現沖突了,則讓返回用戶錯誤的信息,讓用戶決定如何去做。

相對于悲觀鎖,在對數據庫進行處理的時候,樂觀鎖并不會使用數據庫提供的鎖機制。一般的實現樂觀鎖的方式就是記錄數據版本。

實現數據版本有兩種方式,第一種是使用版本號,第二種是使用時間戳。

深入理解樂觀鎖與悲觀鎖

樂觀鎖悲觀鎖區別是什么?

同上

數據庫如何實現悲觀鎖和樂觀鎖?

深入理解樂觀鎖與悲觀鎖

數據庫鎖有了解么?行級鎖?表級鎖?共享鎖?排他鎖?gap鎖?next-key lock?

MySQL中的行級鎖,表級鎖,頁級鎖

MySQL中的共享鎖與排他鎖

數據庫鎖和隔離級別有什么關系?

很多DBMS定義了多個不同的“事務隔離等級”來控制鎖的程度和并發能力。

ANSI/ISO SQL定義的標準隔離級別有四種,從高到底依次為:可序列化(Serializable)、可重復讀(Repeatable reads)、提交讀(Read committed)、未提交讀(Read uncommitted)。

深入分析事務的隔離級別

數據庫鎖和索引有什么關系?

在MySQL中,行級鎖并不是直接鎖記錄,而是鎖索引。索引分為主鍵索引和非主鍵索引兩種,如果一條sql語句操作了主鍵索引,MySQL就會鎖定這條主鍵索引;如果一條語句操作了非主鍵索引,MySQL會先鎖定該非主鍵索引,再鎖定相關的主鍵索引。

什么是聚簇索引?非聚簇索引?最左前綴是什么?B+樹索引?聯合索引?回表?

主鍵索引的葉子節點存的是整行數據。在InnoDB中,主鍵索引也被稱為聚簇索引(clustered index)

非主鍵索引的葉子節點的內容是主鍵的值,在InnoDB中,非主鍵索引也被稱為非聚簇索引(secondary index)

當我們創建一個聯合索引的時候,如(key1,key2,key3),相當于創建了(key1)、(key1,key2)和(key1,key2,key3)三個索引,這就是最左匹配原則。

在 InnoDB 里,索引B+ Tree的葉子節點存儲了整行數據的是主鍵索引。而索引B+ Tree的葉子節點存儲了主鍵的值的是非主鍵索引。因為主鍵索引樹的葉子節點直接就是我們要查詢的整行數據了。而非主鍵索引的葉子節點是主鍵的值,查到主鍵的值以后,還需要再通過主鍵的值再進行一次查詢,這個過程叫做回表。

我以為我對Mysql索引很了解,直到我遇到了阿里的面試官

分布式鎖有了解嗎?

目前比較常用的有以下幾種方案:

基于數據庫實現分布式鎖 基于緩存(redis,memcached,tair)實現分布式鎖 基于Zookeeper實現分布式鎖

分布式鎖的幾種實現方式~

Redis怎么實現分布式鎖?

多個進程執行以下Redis命令:

SETNX lock.foo

如果 SETNX 返回1,說明該進程獲得鎖,SETNX將鍵 lock.foo 的值設置為鎖的超時時間(當前時間 + 鎖的有效時間)。 如果 SETNX 返回0,說明其他進程已經獲得了鎖,進程不能進入臨界區。進程可以在一個循環中不斷地嘗試 SETNX 操作,以獲得鎖。

為什么要用Redis?

分布式緩存,提升性能

Redis和memcache區別是什么?

1、存儲方式:Memcache把數據全部存在內存之中,斷電后會掛掉,數據不能超 過內存大小。Redis支持數據的持久化,可以將內存中的數據保存在磁盤中,重啟時可以再次加載進行使用。(RDB快照和AOF日志兩 種持久化方式)。? ? ? ? ?

2、Redis支持數據的備份,及master-slave模式的數據備份。? ? ? ? ?

3、數據支持類型:Redis在數據支持上要比Memcache多得多。? ? ? ? ?

4、使用底層模型不同:新版本的Redis直接自己構建了VM機制,因為一般的系統調用系統函數的話,會浪費一定的時間去移動和請求。? ? ? ? ?

Zookeeper怎么實現分布式鎖?

基于zookeeper臨時有序節點可以實現的分布式鎖。

大致思想即為:每個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節點的目錄下,生成一個唯一的瞬時有序節點。 判斷是否獲取鎖的方式很簡單,只需要判斷有序節點中序號最小的一個。 當釋放鎖的時候,只需將這個瞬時節點刪除即可。同時,其可以避免服務宕機導致的鎖無法釋放,而產生的死鎖問題。

分布式鎖的幾種實現方式~

什么是Zookeeper?

Zookeeper是一個開放源碼的分布式服務協調組件,是Google Chubby的開源實現。是一個高性能的分布式數據一致性解決方案。他將那些復雜的、容易出錯的分布式一致性服務封裝起來,構成一個高效可靠的原語集,并提供一系列簡單易用的接口給用戶使用。

Zookeeper介紹(二)——Zookeeper概述

什么是CAP?

CAP理論:一個分布式系統最多只能同時滿足一致性(Consistency)、可用性(Availability)和分區容錯性(Partition tolerance)這三項中的兩項。

分布式系統的CAP理論

什么是BASE?和CAP什么區別?

BASE理論是對CAP理論的延伸,核心思想是即使無法做到強一致性(Strong Consistency,CAP的一致性就是強一致性),但應用可以采用適合的方式達到最終一致性(Eventual Consitency)。

BASE是指基本可用(Basically Available)、軟狀態( Soft State)、最終一致性( Eventual Consistency)。

分布式系統的BASE理論

CAP怎么推導?如何取舍?

對于涉及到錢財這樣不能有一絲讓步的場景,C必須保證。網絡發生故障寧可停止服務,這是保證CP,舍棄A。比如前幾年支付寶光纜被挖斷的事件,在網絡出現故障的時候,支付寶就在可用性和數據一致性之間選擇了數據一致性,用戶感受到的是支付寶系統長時間宕機,但是其實背后是無數的工程師在恢復數據,保證數數據的一致性。

對于其他場景,比較普遍的做法是選擇可用性和分區容錯性,舍棄強一致性,退而求其次使用最終一致性來保證數據的安全。

分布式系統的CAP理論

分布式系統怎么保證數據一致性?

分布式事務

啥是分布式事務?分布式事務方案?

分布式事務是指會涉及到操作多個數據庫的事務。其實就是將對同一庫事務的概念擴大到了對多個庫的事務。目的是為了保證分布式系統中的數據一致性。分布式事務處理的關鍵是必須有一種方法可以知道事務在任何地方所做的所有動作,提交或回滾事務的決定必須產生統一的結果(全部提交或全部回滾)

關于分布式事務、兩階段提交協議、三階提交協議

分布式事務解決方案——柔性事務與服務模式

那么,最后了,來手寫一個線程安全的單例吧?

單例模式的七種寫法

為什么我墻裂建議大家使用枚舉來實現單例

不用synchronized和lock能實現線程安全的單例嗎?

借助CAS(AtomicReference)實現單例模式:

public class Singleton {
    private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>(); 

    private Singleton() {}

    public static Singleton getInstance() {
        for (;;) {
            Singleton singleton = INSTANCE.get();
            if (null != singleton) {
                return singleton;
            }

            singleton = new Singleton();
            if (INSTANCE.compareAndSet(null, singleton)) {
                return singleton;
            }
        }
    }
}

用CAS的好處在于不需要使用傳統的鎖機制來保證線程安全,CAS是一種基于忙等待的算法,依賴底層硬件的實現,相對于鎖它沒有線程切換和阻塞的額外消耗,可以支持較大的并行度。 CAS的一個重要缺點在于如果忙等待一直執行不成功(一直在死循環中),會對CPU造成較大的執行開銷。

不使用synchronized和lock,如何實現一個線程安全的單例?

不使用synchronized和lock,如何實現一個線程安全的單例?(二)

這你都能答上?那好吧,你給我解釋下什么是Paxos算法吧?

Paxos一種基于消息傳遞且具有高度容錯特性的一致性算法。Paxos算法號稱是最難理解的算法?。?!

總結

面試,其實是一個循序漸進的過程,面試官不可能上來就讓一個面試者手擼paxos算法,總要先拋出一個比較簡單的問題,然后根據面試者回答的情況,逐漸的展開和深入。

另外 ,以上問題的”推倒”過程,其實就是一個完整的知識體系,很多人在我的公眾號后臺以及微信好友問我到底什么是知識體系,如何構建自己的知識體系。

這個問題并沒有什么標準答案,同樣一個知識點,不斷的展開,把多個知識點互相連接,這就是一個知識體系。每個人的知識體系都不相同。但是構建過程都是一樣的,那就是圖論中的”深度優先搜索”和”廣度優先搜索”,就看哪種比較適合你了。

(全文完) 歡迎關注『Java之道』微信公眾號
贊(0)
如未加特殊說明,此網站文章均為原創,轉載必須注明出處。英雄联盟充值记录 » 國內Java面試總是問StringBuffer,StringBuilder區別是啥?檔次為什么這么低?
分享到: 更多 (0)

評論 搶沙發

  • 昵稱 (必填)
  • 郵箱 (必填)
  • 網址

HollisChuang's Blog

聯系我關于我