GitHub 6.6k Star 的Java工程師成神之路 ,不來了解一下嗎?java
GitHub 6.6k Star 的Java工程師成神之路 ,真的不來了解一下嗎?git
GitHub 6.6k Star 的Java工程師成神之路 ,真的肯定不來了解一下嗎?github
這是一個知乎上面很火的問題(www.zhihu.com/question/50… ),下面是我關於這個問題的回答,截止今天,這個答案收穫了500+贊和70+評論。面試
這個問題只是開個場,熱個身而已啊。redis
StringBuffer,StringBuilder區別是啥?算法
什麼是線程安全?sql
如何保證線程安全?數據庫
什麼是鎖?死鎖?編程
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的鎖優化是怎麼回事?(鎖粗化?鎖消除?自旋鎖?偏向鎖?輕量級鎖?)
知道JMM嗎?(原子性?可見性?有序性?)
Java內存模型(Java Memory Model ,JMM)是一種符合內存模型規範的,屏蔽了各類硬件和操做系統的訪問差別的,保證了Java程序在各類平臺下對內存的訪問都能保證效果一致的機制及規範。
Java併發包瞭解嗎?
java.util.concurrent包(J.U.C)中包含的是java併發編程中有用的一些工具類,包括幾個部分:
一、locks部分:包含在java.util.concurrent.locks包中,提供顯式鎖(互斥鎖和速寫鎖)相關功能;
二、atomic部分:包含在java.util.concurrent.atomic包中,提供原子變量類相關的功能,是構建非阻塞算法的基礎;
三、executor部分:散落在java.util.concurrent包中,提供線程池相關的功能;
四、collections部分:散落在java.util.concurrent包中,提供併發容器相關功能;
五、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 。
什麼是CopyOnWrite?
Copy-On-Write簡稱COW,是一種用於程序設計中的優化策略。其基本思路是,從一開始你們都在共享同一個內容,當某我的想要修改這個內容的時候,纔會真正把內容Copy出去造成一個新的內容而後再改,這是一種延時懶惰策略。
CopyOnWrite容器即寫時複製的容器。通俗的理解是當咱們往一個容器添加元素的時候,不直接往當前容器添加,而是先將當前容器進行Copy,複製出一個新的容器,而後新的容器裏添加元素,添加完元素以後,再將原容器的引用指向新的容器。
那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都知道,那樂觀鎖必定知道了?
樂觀鎖( Optimistic Locking ) 相對悲觀鎖而言,樂觀鎖假設認爲數據通常狀況下不會形成衝突,因此在數據進行提交更新的時候,纔會正式對數據的衝突與否進行檢測,若是發現衝突了,則讓返回用戶錯誤的信息,讓用戶決定如何去作。
相對於悲觀鎖,在對數據庫進行處理的時候,樂觀鎖並不會使用數據庫提供的鎖機制。通常的實現樂觀鎖的方式就是記錄數據版本。
實現數據版本有兩種方式,第一種是使用版本號,第二種是使用時間戳。
樂觀鎖悲觀鎖區別是什麼?
同上
數據庫如何實現悲觀鎖和樂觀鎖?
數據庫鎖有了解麼?行級鎖?表級鎖?共享鎖?排他鎖?gap鎖?next-key lock?
數據庫鎖和隔離級別有什麼關係?
不少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的葉子節點存儲了主鍵的值的是非主鍵索引。由於主鍵索引樹的葉子節點直接就是咱們要查詢的整行數據了。而非主鍵索引的葉子節點是主鍵的值,查到主鍵的值之後,還須要再經過主鍵的值再進行一次查詢,這個過程叫作回表。
分佈式鎖有了解嗎?
目前比較經常使用的有如下幾種方案:
基於數據庫實現分佈式鎖 基於緩存(redis,memcached,tair)實現分佈式鎖 基於Zookeeper實現分佈式鎖
Redis怎麼實現分佈式鎖?
多個進程執行如下Redis命令:
SETNX lock.foo
若是 SETNX 返回1,說明該進程得到鎖,SETNX將鍵 lock.foo 的值設置爲鎖的超時時間(當前時間 + 鎖的有效時間)。 若是 SETNX 返回0,說明其餘進程已經得到了鎖,進程不能進入臨界區。進程能夠在一個循環中不斷地嘗試 SETNX 操做,以得到鎖。
爲何要用Redis?
分佈式緩存,提高性能
Redis和memcache區別是什麼?
一、存儲方式:Memcache把數據所有存在內存之中,斷電後會掛掉,數據不能超 過內存大小。Redis支持數據的持久化,能夠將內存中的數據保存在磁盤中,重啓時能夠再次加載進行使用。(RDB快照和AOF日誌兩 種持久化方式)。
二、Redis支持數據的備份,及master-slave模式的數據備份。
三、數據支持類型:Redis在數據支持上要比Memcache多得多。
四、使用底層模型不一樣:新版本的Redis直接本身構建了VM機制,由於通常的系統調用系統函數的話,會浪費必定的時間去移動和請求。
Zookeeper怎麼實現分佈式鎖?
基於zookeeper臨時有序節點能夠實現的分佈式鎖。
大體思想即爲:每一個客戶端對某個方法加鎖時,在zookeeper上的與該方法對應的指定節點的目錄下,生成一個惟一的瞬時有序節點。 判斷是否獲取鎖的方式很簡單,只須要判斷有序節點中序號最小的一個。 當釋放鎖的時候,只需將這個瞬時節點刪除便可。同時,其能夠避免服務宕機致使的鎖沒法釋放,而產生的死鎖問題。
什麼是Zookeeper?
Zookeeper是一個開放源碼的分佈式服務協調組件,是Google Chubby的開源實現。是一個高性能的分佈式數據一致性解決方案。他將那些複雜的、容易出錯的分佈式一致性服務封裝起來,構成一個高效可靠的原語集,並提供一系列簡單易用的接口給用戶使用。
什麼是CAP?
CAP理論:一個分佈式系統最多隻能同時知足一致性(Consistency)、可用性(Availability)和分區容錯性(Partition tolerance)這三項中的兩項。
什麼是BASE?和CAP什麼區別?
BASE理論是對CAP理論的延伸,核心思想是即便沒法作到強一致性(Strong Consistency,CAP的一致性就是強一致性),但應用能夠採用適合的方式達到最終一致性(Eventual Consitency)。
BASE是指基本可用(Basically Available)、軟狀態( Soft State)、最終一致性( Eventual Consistency)。
CAP怎麼推導?如何取捨?
對於涉及到錢財這樣不能有一絲讓步的場景,C必須保證。網絡發生故障寧肯中止服務,這是保證CP,捨棄A。好比前幾年支付寶光纜被挖斷的事件,在網絡出現故障的時候,支付寶就在可用性和數據一致性之間選擇了數據一致性,用戶感覺到的是支付寶系統長時間宕機,可是其實背後是無數的工程師在恢復數據,保證數數據的一致性。
對於其餘場景,比較廣泛的作法是選擇可用性和分區容錯性,捨棄強一致性,退而求其次使用最終一致性來保證數據的安全。
分佈式系統怎麼保證數據一致性?
分佈式事務
啥是分佈式事務?分佈式事務方案?
分佈式事務是指會涉及到操做多個數據庫的事務。其實就是將對同一庫事務的概念擴大到了對多個庫的事務。目的是爲了保證分佈式系統中的數據一致性。分佈式事務處理的關鍵是必須有一種方法能夠知道事務在任何地方所作的全部動做,提交或回滾事務的決定必須產生統一的結果(所有提交或所有回滾)
那麼,最後了,來手寫一個線程安全的單例吧?
不用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算法,總要先拋出一個比較簡單的問題,而後根據面試者回答的狀況,逐漸的展開和深刻。
另外 ,以上問題的"推倒"過程,其實就是一個完整的知識體系,不少人在個人公衆號後臺以及微信好友問我到底什麼是知識體系,如何構建本身的知識體系。
這個問題並無什麼標準答案,一樣一個知識點,不斷的展開,把多個知識點互相鏈接,這就是一個知識體系。每一個人的知識體系都不相同。可是構建過程都是同樣的,那就是圖論中的"深度優先搜索"和"廣度優先搜索",就看哪一種比較適合你了。