Java高階知識體系總結(一)

Java高階知識體系總結

1.Java 基礎

Java類設計的原則就是內聚性,一致性和封裝性是Java設計的基本原則
1.1 Java基礎理論
Java基礎理論知識
1.2繼承的優缺點
優點
新的實現很容易,因爲大部分是繼承而來的,很容易修改和擴展已有的實現
缺點
1)打破了封裝,因爲基類向子類暴露了實現細節 。
2)白盒重用,因爲基類的內部細節通常對子類是可見的
3)當父類的實現改變時可能要相應的對子類做出改變 。
4)不能在運行時改變由父類繼承來的實現
由此可見,組合比繼承具有更大的靈活性和更穩定的結構,一般情況下應該優先考慮組合。

只有當下列條件滿足時才考慮使用繼承:

1)子類是一種特殊的類型,而不只是父類的一個角色
2)子類的實例不需要變成另一個類的對象
3)子類擴展,而不是覆蓋或者使父類的功能失效

2、Java內核

2.1堆棧

棧stack和堆heapJAVA在程序運行時,在內存中劃分5片空間進行數據的存儲。
分別是:1:寄存器。2:本地方法區。3:方法區。4:棧。5:堆

棧內存:基本數據類型、局部變量都是存放在棧內存中的,用完就消失。
堆內存:new創建的實例化對象及數組,是存放在堆內存中的,用完之後靠垃圾回收機制不定期自動消除。

1).函數中定義的基本類型變量,對象的引用變量都在函數的棧內存中分配。
2).棧內存特點,數數據一執行完畢,變量會立即釋放,節約內存空間。
3).棧內存中的數據,沒有默認初始化值,需要手動設置。

1).堆內存用來存放new創建的對象和數組。
2).堆內存中所有的實體都有內存地址值。
3).堆內存中的實體是用來封裝數據的,這些數據都有默認初始化值。
4).堆內存中的實體不再被指向時,JVM啓動垃圾回收機制,自動清除,這也是JAVA優於C++的表現之一
(C++中需要程序員手動清除)

3、Spring

3.1、簡介

什麼是spring,爲什麼要用spring?

1.Spring是一個分層的,一站式的輕量級開源框架
2.它致力於提供一種方法管理業務對象,使JavaEE的開發更方便快捷.
3.Spring不是僅僅專注於某一層的開發,而是貫穿應用於web層/業務層及持久層,
與struts2/SpringMVC/hibernate等框架進行無縫整合,
並對一些API(JDBC/JavaMail/遠程調用等)進行了封裝,降低了這些API的使用難度
4.繼承Junit4,方便程序測試,@runwith(SpringJunit…)
5.對支持聲明式事物管理@transational,只需通過配置就可以完成對事物的管理,無需動手編程
6.對AOP(Aspect Oriented Programming)編程的支持,Spring提供面向切面編程,方便實現對程序進行權限攔截/運行監控等功能
7.Spring 就是一個大工廠,可以將所有對象創建(IOC)和依賴關係維護(DI),交給Spring管理

3.2、IOC

IOC爲InversionOfControl,控制反轉是spring基於Java反射技術來實現的。IOC並不是spring或者面向對象的專用術語。
IOC 控制反轉,是指對象實例化權利由spring容器來管理
實現原理: 工廠+反射+xml配置文件
底層是通過BeanFactory的子接口ApplicationContext接口的實現類ClassPathXmlApplicaitonContex從配置文件applicationContext.xml文件
中讀取要創建的類名,再通過它的方法的getBean("…")反射的方式,創建出類,真正意義上達到解耦合的目的.
DI(dependency injection 依賴注入)
DI 依賴注入 在spring創建對象的過程中,對象所依賴的屬性通過配置注入對象中。
實現原理:在spring框架負責創建Bean對象時,動態將依賴對象注入到Bean組件。

IoC中最基本的Java技術就是“反射”編程。通俗的說反射就是根據給出的類名(字符串)來生成對象。這種編程方式可以讓對象在生成時才決定要生成哪一種對象。反射的應用是很廣泛的,像Hibernate、Spring中都是用“反射”做爲最基本的技術手段。
  在過去,反射編程方式相對於正常的對象生成方式要慢10幾倍,這也許也是當時爲什麼反射技術沒有普遍應用開來的原因。但經SUN改良優化後,反射方式生成對象和通常對象生成方式,速度已經相差不大了(但依然有一倍以上的差距)。
IoC最大的好處是什麼?因爲把對象生成放在了XML裏定義,所以當我們需要換一個實現子類將會變成很簡單(一般這樣的對象都是實現於某種接口的),只要修改XML就可以了,這樣我們甚至可以實現對象的熱插拔(有點像USB接口和SCSI硬盤了)。

3.3、AOP

面向切面編程,往往被定義爲促使軟件系統實現關注點的分離的技術。系統是由許多不同的組件所組成的,每一個組件各負責一塊特定功能。除了實現自身核心功能之外,這些組件還經常承擔着額外的職責。例如日誌、事務管理和安全這樣的核心服務經常融入到自身具有核心業務邏輯的組件中去。這些系統服務經常被稱爲橫切關注點,因爲它們會跨越系統的多個組件。
3.3.1一般用於日誌記錄,性能統計,安全控制,事務處理,異常處理等等。
3.3.2可以通過預編譯方式和運行期動態代理實現在不修改源代碼的情況下給程序動態統一添加功能的一種技術。AOP實際是GoF設計模式的延續,設計模式孜孜不倦追求的是調用者和被調用者之間的解耦,提高代碼的靈活性和可擴展性,AOP可以說也是這種目標的一種實現。

3.4 spring事務傳播特性

事務傳播行爲就是多個事務方法相互調用時,事務如何在這些方法間傳播。
spring支持7種事務傳播行爲:

propagation_requierd:如果當前沒有事務,就新建一個事務,如果已存在一個事務中,加入到這個事務中,這是最常見的選擇。
propagation_supports:支持當前事務,如果沒有當前事務,就以非事務方法執行。
propagation_mandatory:使用當前事務,如果沒有當前事務,就拋出異常。
propagation_required_new:新建事務,如果當前存在事務,把當前事務掛起。
propagation_not_supported:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
propagation_never:以非事務方式執行操作,如果當前事務存在則拋出異常。
propagation_nested:如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行與propagation_required類似的操作

Spring 默認的事務傳播行爲是 PROPAGATION_REQUIRED,它適合於絕大多數的情況。

4、Java線程

多線程能滿足程序員編寫高效率的程序來達到充分利用 CPU 的目的。
一條線程指的是進程中一個單一順序的控制流,一個進程中可以併發多個線程,每條線程並行執行不同的任務。
多線程是多任務的一種特別的形式,但多線程使用了更小的資源開銷。
Java 提供了三種創建線程的方法:
通過實現 Runnable 接口;
通過繼承 Thread 類本身;
通過 Callable 和 Future 創建線程。
有效利用多線程的關鍵是理解程序是併發執行而不是串行執行的。例如:程序中有兩個子系統需要併發執行,這時候就需要利用多線程編程。
通過對多線程的使用,可以編寫出非常高效的程序。不過請注意,如果你創建太多的線程,程序執行的效率實際上是降低了,而不是提升了。
請記住,上下文的切換開銷也很重要,如果你創建了太多的線程,CPU 花費在上下文的切換的時間將多於執行程序的時間!
同步是多線程中的重要概念。同步的使用可以保證在多線程運行的環境中,程序不會產生設計之外的錯誤結果。同步的實現方式有兩種,同步方法和同步塊,這兩種方式都要用到synchronized關鍵字。
eg:

/** * 用同步方法實現 * * @param money */
 public synchronized void save(int money) { 
 		account += money;
 } 
 /** * 用同步代碼塊實現 * * 
 @param money */ 
	 public void save0(int money) { synchronized (this) {
	 		 account += money;
   		}
    }

使用非依賴屬性實現同步

4.1鎖

Java中的鎖y有 偏向鎖、輕量級鎖、自旋鎖、重量級鎖
鎖從宏觀上分類,分爲悲觀鎖樂觀鎖
樂觀鎖:是一種樂觀思想,即認爲讀多寫少,遇到併發寫的可能性低,每次去拿數據的時候都認爲別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,採取在寫時先讀出當前版本號,然後加鎖操作(比較跟上一次的版本號,如果一樣則更新),如果失敗則要重複讀-比較-寫的操作。
java中的樂觀鎖基本都是通過CAS操作實現的,CAS是一種更新的原子操作,比較當前值跟傳入值是否一樣,一樣則更新,否則失敗。
悲觀鎖:是就是悲觀思想,即認爲寫多,遇到併發寫的可能性高,每次去拿數據的時候都認爲別人會修改,所以每次在讀寫數據的時候都會上鎖,這樣別人想讀寫這個數據就會block直到拿到鎖。java中的悲觀鎖就是Synchronized,AQS框架下的鎖則是先嚐試cas樂觀鎖去獲取鎖,獲取不到,纔會轉換爲悲觀鎖,如RetreenLock。

4.1.2、Java中的鎖

自旋鎖:自旋鎖原理非常簡單,如果持有鎖的線程能在很短時間內釋放鎖資源,那麼那些等待競爭鎖的線程就不需要做內核態和用戶態之間的切換進入阻塞掛起狀態,它們只需要等一等(自旋),等持有鎖的線程釋放鎖後即可立即獲取鎖,這樣就避免用戶線程和內核的切換的消耗。
但是線程自旋是需要消耗cup的,說白了就是讓cup在做無用功,如果一直獲取不到鎖,那線程也不能一直佔用cup自旋做無用功,所以需要設定一個自旋等待的最大時間。
如果持有鎖的線程執行的時間超過自旋等待的最大時間扔沒有釋放鎖,就會導致其它爭用鎖的線程在最大等待時間內還是獲取不到鎖,這時爭用線程會停止自旋進入阻塞狀態。
偏向鎖(Biased Locking)是Java6引入的一項多線程優化。
偏向鎖,顧名思義,它會偏向於第一個訪問鎖的線程,如果在運行過程中,同步鎖只有一個線程訪問,不存在多線程爭用的情況,則線程是不需要觸發同步的,這種情況下,就會給線程加一個偏向鎖。
如果在運行過程中,遇到了其他線程搶佔鎖,則持有偏向鎖的線程會被掛起,JVM會消除它身上的偏向鎖,將鎖恢復到標準的輕量級鎖。
輕量級鎖:輕量級鎖是由偏向所升級來的,偏向鎖運行在一個線程進入同步塊的情況下,當第二個線程加入鎖爭用的時候,偏向鎖就會升級爲輕量級鎖;
重量級鎖:synchronized會導致爭用不到鎖的線程進入阻塞狀態,所以說它是java語言中一個重量級的同步操縱,被稱爲重量級鎖,爲了緩解上述性能問題,JVM從1.5開始,引入了輕量鎖與偏向鎖,默認啓用了自旋鎖,他們都屬於樂觀鎖。

4.1.3、鎖優化

減少鎖的時間:不需要同步執行的代碼,能不放在同步快裏面執行就不要放在同步快內,可以讓鎖儘快釋放;
減少鎖的粒度:將物理上的一個鎖,拆成邏輯上的多個鎖,增加並行度,從而降低鎖競爭。它的思想也是用空間來換時間;
鎖粗化:大部分情況下我們是要讓鎖的粒度最小化,鎖的粗化則是要增大鎖的粒度;
在以下場景下需要粗化鎖的粒度:
假如有一個循環,循環內的操作需要加鎖,我們應該把鎖放到循環外面,否則每次進出循環,都進出一次臨界區,效率是非常差的;
使用讀寫鎖:ReentrantReadWriteLock 是一個讀寫鎖,讀操作加讀鎖,可以併發讀,寫操作使用寫鎖,只能單線程寫;
讀寫分離:CopyOnWriteArrayList 、CopyOnWriteArraySet
CopyOnWrite容器即寫時複製的容器。通俗的理解是當我們往一個容器添加元素的時候,不直接往當前容器添加,而是先將當前容器進行Copy,複製出一個新的容器,然後新的容器裏添加元素,添加完元素之後,再將原容器的引用指向新的容器。這樣做的好處是我們可以對CopyOnWrite容器進行併發的讀,而不需要加鎖,因爲當前容器不會添加任何元素。所以CopyOnWrite容器也是一種讀寫分離的思想,讀和寫不同的容器。
 CopyOnWrite併發容器用於讀多寫少的併發場景,因爲,讀的時候沒有鎖,但是對其進行更改的時候是會加鎖的,否則會導致多個線程同時複製出多個副本,各自修改各自的;
使用CAS:如果需要同步的操作執行速度非常快,並且線程競爭並不激烈,這時候使用cas效率會更高,因爲加鎖會導致線程的上下文切換,如果上下文切換的耗時比同步操作本身更耗時,且線程對資源的競爭不激烈,使用volatiled+cas操作會是非常高效的選擇;
消除緩存行的僞共享:除了我們在代碼中使用的同步鎖和jvm自己內置的同步鎖外,還有一種隱藏的鎖就是緩存行,它也被稱爲性能殺手。
在多核cup的處理器中,每個cup都有自己獨佔的一級緩存、二級緩存,甚至還有一個共享的三級緩存,爲了提高性能,cpu讀寫數據是以緩存行爲最小單元讀寫的;32位的cpu緩存行爲32字節,64位cup的緩存行爲64字節,這就導致了一些問題。

4.1.3、死鎖

死鎖是這樣一種情形:多個線程同時被阻塞,它們中的一個或者全部都在等待某個資源被釋放。由於線程被無限期地阻塞,因此程序不可能正常終止。
java 死鎖產生的四個必要條件:
1、互斥使用,即當資源被一個線程使用(佔有)時,別的線程不能使用
2、不可搶佔,資源請求者不能強制從資源佔有者手中奪取資源,資源只能由資源佔有者主動釋放。
3、請求和保持,即當資源請求者在請求其他的資源的同時保持對原有資源的佔有。
4、循環等待,即存在一個等待隊列:P1佔有P2的資源,P2佔有P3的資源,P3佔有P1的資源。這樣就形成了一個等待環路。
解決方式:對於無法成功獲取的情況,一般就是重複嘗試,或指定嘗試的次數,也可以馬上退出。

4.2、Threadlocal

ThreadLocal的作用是提供線程內的局部變量,這種變量在線程的生命週期內起作用,減少同一個線程內多個函數或者組件之間一些公共變量的傳遞的複雜度。
ThreadLocal在每個線程中對該變量會創建一個副本,即每個線程內部都會有一個該變量,且在線程內部任何地方都可以使用,線程之間互不影響,這樣一來就不存在線程安全問題,也不會嚴重影響程序執行性能。
但是要注意,雖然ThreadLocal能夠解決上面說的問題,但是由於在每個線程中都創建了副本,所以要考慮它對資源的消耗,比如內存的佔用會比不使用ThreadLocal要大。

1)實際的通過ThreadLocal創建的副本是存儲在每個線程自己的threadLocals中的;
2)爲何threadLocals的類型ThreadLocalMap的鍵值爲ThreadLocal對象,因爲每個線程中可有多個threadLocal變量;
3)在進行get之前,必須先set,否則會報空指針異常;

4.3、Java對象的引用

包括:強引用,軟引用,弱引用,虛引用
Java中提供這四種引用類型主要有兩個目的:

第一是 可以讓程序員通過代碼的方式決定某些對象的生命週期;
第二是 有利於JVM進行垃圾回收。

強引用:是指創建一個對象並把這個對象賦給一個引用變量。
軟引用:如果一個對象具有軟引用,內存空間足夠,垃圾回收器就不會回收它;
如果內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以被 程序使用。軟引用可用來實現內存敏感的高速緩存,比如網頁緩存、圖片緩存等。使用軟引用能防止內存泄露,增強程序的健壯性。
SoftReference的特點是它的一個實例保存對一個Java對象的軟引用, 該軟引用的存在不妨礙垃圾收集線程對該Java對象的回收。
弱引用:WeakReference弱引用也是用來描述非必需對象的,當JVM進行垃圾回收時,無論內存是否充足,都會回收被弱引用關聯的對象。在java中,用java.lang.ref.WeakReference類來表示。
虛引用:虛引用(PhantomReference) 虛引用和前面的軟引用、弱引用不同,它並不影響對象的生命週期。在java中用java.lang.ref.PhantomReference類表示。如果一個對象與虛引用關聯,則跟沒有引用與之關聯一樣,在任何時候都可能被垃圾回收器回收

要注意的是,虛引用必須和引用隊列關聯使用,當垃圾回收器準備回收一個對象時,如果發現它還有虛引用,就會把這個虛引用加入到與之 關聯的引用隊列中。程序可以通過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。如果程序發現某個虛引用已經被加入到引用隊列,那麼就可以在所引用的對象的內存被回收之前採取必要的行動。

4.4、ThreadPoolExecutor
ThreadPoolExecutor是線程池框架的一個核心類,通過對ThreadPoolExecutor,可以知道其對資源進行了複用,並非無限制的創建線程,可以有效的減少線程創建和切換的開銷。
在ThreadPoolExecutor的內部,主要由阻塞隊列BlockingQueue和抽象隊列同步器AbstractQueuedSynchronizer對其提供支持,BlockingQueue接口有多種數據結構的實現,如LinkedBlockingQueue、ArrayBlockingQueue等。

corePoolSize:設置線程池的核心線程數,當添加新任務時,如果線程池中的線程數小於corePoolSize,則不管當前是否有線程閒置,都會創建一個新的線程來執行任務。
maximunPoolSize:是線程池中允許的最大的線程數
workQueue:用於存放排隊的任務
keepAliveTime:是大於corePoolSize的線程閒置的超時時間
handler:用於在任務逸出、線程池關閉時的任務處理

線程池的線程增長策略爲,當前線程數小於corePoolSize時,新增線程,當線程數=corePoolSize且corePoolSize時,只有在workQueue不能存放新的任務時創建新線程,超出的線程在閒置keepAliveTime後銷燬。

5、JVM

5.1、volatile

直接與主內存交互,保證可見性。避免指令重排序。
可見性是指的是線程訪問變量是否是最新值。
局部變量不存在可見性問題,而共享內存就會有可見性問題。因爲本地線程在創建的時候,會從主存中讀取一個共享變量的副本,且修改也是修改副本,且並不是立即刷新到主存中去,那麼其他線程並不會馬上共享變量的修改。
因此,線程B修改共享變量後,線程A並不會馬上知曉,就會出現上述死循環的問題。

解決共享變量可見性問題,需要用volatile關鍵字修飾。
可見性理解爲:
1. 對volatile變量的寫會立即刷新到主存
2. 對volatile變量的讀會讀主存中的新值

volatile是一個類型修飾符(type specifier),就像大家更熟悉的const一樣,它是被設計用來修飾被不同線程訪問和修改的變量。volatile的作用是作爲指令關鍵字,確保本條指令不會因編譯器的優化而省略,且要求每次直接讀值。
volatile的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。
一般說來,volatile用在如下的幾個地方:
1、中斷服務程序中修改的供其它程序檢測的變量需要加volatile;
2、多任務環境下各任務間共享的標誌應該加volatile;
3、存儲器映射的硬件寄存器通常也要加volatile說明,因爲每次對它的讀寫都可能有不同意義;
另外,以上這幾種情況經常還要同時考慮數據的完整性(相互關聯的幾個標誌讀了一半被打斷了重寫),在1中可以通過關中斷來實現,2 中可以禁止任務調度,3中則只能依靠硬件的良好設計了。
volatile關鍵字就是提示JVM:對於這個成員變量不能保存它的私有拷貝,而應直接與共享成員變量交互。
使用建議:在兩個或者更多的線程訪問的成員變量上使用volatile。當要訪問的變量已在synchronized代碼塊中,或者爲常量時,不必使用。
由於使用volatile屏蔽掉了JVM中必要的代碼優化,所以在效率上比較低,因此一定在必要時才使用此關鍵字。

Java 語言包含兩種內在的同步機制:同步塊(或方法)和 volatile 變量。這兩種機制的提出都是爲了實現代碼線程的安全性。其中 Volatile變量的同步性較差(但有時它更簡單並且開銷更低),而且其使用也更容易出錯。

5.1、內存泄露

內存泄漏(Memory Leak)是指程序中己動態分配的堆內存由於某種原因程序未釋放或無法釋放,造成系統內存的浪費,導致程序運行速度減慢甚至系統崩潰等嚴重後果。

5.2、內存溢出

內存溢出(out of memory)通俗理解就是內存不夠,通常在運行大型軟件或遊戲時,軟件或遊戲所需要的內存遠遠超出了你主機內安裝的內存所承受大小,就叫內存溢出。此時軟件或遊戲就運行不了,系統會提示內存溢出,有時候會自動關閉軟件,重啓電腦或者軟件後釋放掉一部分內存又可以正常運行該軟件。

5.3、JVM內存結構

JVM內存分爲工作內存和主存。
工作內存:即java線程的本地內存,是單獨給某個線程分配的,存儲局部變量等,同時也會複製主存的共享變量作爲本地的副本,目的是爲了減少和主存通信的頻率,提高效率。
主存:存儲類成員變量等

5.4、爲什麼要GC

GC是垃圾收集的意思,內存處理是編程人員容易出現問題的地方,忘記或者錯誤的內存回收會導致程序或系統的不穩定甚至崩潰,Java提供的GC功能可以自動監測對象是否超過作用域從而達到自動回收內存的目的,Java語言沒有提供釋放已分配內存的顯示操作方法。Java程序員不用擔心內存管理,因爲垃圾收集器會自動進行管理。要請求垃圾收集,可以調用下面的方法之一:
System.gc() 或Runtime.getRuntime().gc() 。
垃圾回收可以有效的防止內存泄露,有效的使用可以使用的內存。垃圾回收器通常是作爲一個單獨的低優先級的線程運行,不可預知的情況下對內存堆中已經死亡的或者長時間沒有使用的對象進行清除和回收,程序員不能實時的調用垃圾回收器對某個對象或所有對象進行垃圾回收。回收機制有分代複製垃圾回收、標記垃圾回收、增量垃圾回收等方式。
補充:標準的Java進程既有棧又有堆。棧保存了原始型局部變量,堆保存了要創建的對象。Java平臺對堆內存回收和再利用的基本算法被稱爲標記和清除,但是Java對其進行了改進,採用“分代式垃圾收集”。這種方法會跟Java對象的生命週期將堆內存劃分爲不同的區域,在垃圾收集過程中,可能會將對象移動到不同區域:
伊甸園(Eden):這是對象最初誕生的區域,並且對大多數對象來說,這裏是它們唯一存在過的區域。

倖存者樂園(Survivor):從伊甸園倖存下來的對象會被挪到這裏。
終身頤養園(Tenured):這是足夠老的倖存對象的歸宿。年輕代收集(Minor-GC)過程是不會觸及這個地方的。當年輕代收集不能把對象放進終身頤養園時,就會觸發一次完全收集(Major-GC),這裏可能還會牽扯到壓縮,以便爲大對象騰出足夠的空間
與垃圾回收相關的JVM參數:

-Xms / -Xmx --- 堆的初始大小 / 堆的最大大小
-Xmn --- 堆中年輕代的大小
-XX:-DisableExplicitGC --- 讓System.gc()不產生任何作用
-XX:+PrintGCDetail --- 打印GC的細節
-XX:+PrintGCDateStamps --- 打印GC操作的時間戳

5.5、GC算法

我們一般討論的垃圾回收主要針對Java堆內存中的新生代和老年代,也正因爲新生代和老年代結構上的不同,所以產生了分代回收算法,即新生代的垃圾回收和老年代的垃圾回收採用的是不同的回收算法。針對新生代,主要採用複製算法,而針對老年代,通常採用標記-清除算法或者標記-整理算法來進行回收。
複製算法的思想是將內存分成大小相等的兩塊區域,每次使用其中的一塊。當這一塊的內存用完了,就將還存活的對象複製到另一塊區域上,然後對該塊進行內存回收。
這個算法實現簡單,並且也相對高效,但是代價就是需要將犧牲一半的內存空間用於進行復制。有研究表明,新生代中的對象98%存活期很短,所以並不需要以1:1的比例來劃分整個新生代,通常的做法是將新生代內存空間劃分成一塊較大的Eden區和兩塊較小的Survivor區,兩塊Survivor區域的大小保持一致。每次使用Eden和其中一塊Survivor區,當回收的時候,將還存活的對象複製到另外一塊Survivor空間上,最後清除Eden區和一開始使用的Survivor區。假如用於複製的Survivor區放不下存活的對象,那麼會將對象存到老年代。
標記-清除(Mark-Sweep)算法分爲兩個階段:
標記–>清除
在標記階段將標記出需要回收的對象空間,然後在下一個階段清除階段裏面,將這些標記出來的對象空間回收掉。這種算法有兩個主要問題:一個是標記和清除的效率不高,另一個問題是在清理之後會產生大量不連續的內存碎片,這樣會導致在分配大對象時候無法找到足夠的連續內存而觸發另一次垃圾收集動作。
標記-整理算法
標記-整理(Mark-Compact)算法有效預防了標記-清除算法中可能產生過多內存碎片的問題。在標記需要回收的對象以後,它會將所有存活的對象空間挪到一起,然後再執行清理。

5.6、JVM啓動參數

參數主要有,內存相關,GC相關,GC日誌相關

5.6.1 堆內存相關

-Xms 與 -Xmx
-Xms用於指定Java應用使用的最小堆內存,如-Xms1024m表示將Java應用最小堆設置爲1024M。-Xmx用於指定Java應用使用的最大堆內存,如-Xmx1024m表示將Java應用最大堆設置爲1024m。過小的堆內存可能會造成程序拋出OOM異常,所以正常發佈的應用應該明確指定這兩個參數。並且,一般會選擇將-Xms與-Xmx設置成一樣大小,防止JVM動態調整堆內存容量對程序造成性能影響。
-Xmn
通過-Xmn可以設置堆內存中新生代的容量,以此達到間接控制老年代容量的作用,因爲沒有JVM參數可以直接控制老年代的容量。如-Xmn256m表示將新生代容量設置爲256M。假如這個時候額外指定了-Xms1024m -Xmx1024m,那麼老年代的容量爲768M(1024-256=768)。
-XX:PermSize 與 -XX:MaxPermSize
-XX:PermSize和-XX:MaxPermSize分別用於設置永久代的容量和最大容量。如-XX:PermSize=64m -XX:MaxPermSize=128m表示將永久代的初始容量設置爲64M,最大容量設置爲128M。
-XX:SurvivorRatio
這個參數用於設置新生代中Eden區和Survivor(S0、S1)的容量比值。默認設置爲-XX:SurvivorRatio=8表示Eden區與Survivor的容量比例爲8:1:1。假設-Xmn256m -XX:Survivor=8,那麼Eden區容量爲204.8M(256M / 10 * 8),S0和S1區的容量大小均爲25.6M(256M / 10 * 1)。

5.6.2、GC收集器相關

XX:+UseSerialGC
虛擬機運行在client模式下的默認值,使用這個參數表示虛擬機將使用Serial + Serial Old收集器組合進行垃圾回收。
-XX:+UseSerialGC表示使用這個設置,而-XX:-UseSerialGC表示禁用這個設置。
-XX:+UseParNewGC
使用這個設置以後,虛擬機將使用ParNew + Serial Old收集器組合進行垃圾回收。
-XX:+UseConcMarkSweepGC
使用這個設置以後,虛擬機將使用ParNew + CMS + Serial Old的收集器組合進行垃圾回收。注意Serial Old收集器將作爲CMS收集器出現Concurrent Mode Failure失敗後的後備收集器來進行回收(將會整理內存碎片)。
-XX:+UseParallelGC
虛擬機運行在server模式下的默認值。使用這個設置,虛擬機將使用Parallel Scavenge + Serial Old(PS MarkSweep)的收集器組合進行垃圾回收。
-XX:+UseParallelOldGC
使用這個設置以後,虛擬機將使用Parallel Scavengen + Parallel Old的收集器組合進行垃圾回收。
-XX:PretenureSizeThreshold
設置直接晉升到老年代的對象大小,大於這個參數的對象將直接在老年代分配,而不是在新生代分配。注意這個值只能設置爲字節,如-XX:PretenureSizeThreshold=3145728表示超過3M的對象將直接在老年代分配。
-XX:MaxTenuringThreshold

設置晉升到老年代的對象年齡。每個對象在堅持過一次Minor GC之後,年齡就會加1,當超過這個值時就進入老年代。

默認設置爲-XX:MaxTenuringThreshold=15。
-XX:ParellelGCThreads
設置並行GC時進行內存回收的線程數。只有當採用的垃圾回收器是採用多線程模式,包括ParNew、Parallel Scavenge、Parallel Old、CMS,這個參數的設置纔會有效。
-XX:CMSInitiatingOccupancyFraction
設置CMS收集器在老年代空間被使用多少(百分比)後觸發垃圾收集。默認設置-XX:CMSInitiatingOccupancyFraction=68表示老年代空間使用比例達到68%時觸發CMS垃圾收集。僅當老年代收集器設置爲CMS時候這個參數纔有效。
-XX:+UseCMSCompactAtFullCollection
設置CMS收集器在完成垃圾收集後是否要進行一次內存碎片整理。僅當老年代收集器設置爲CMS時候這個參數纔有效。
-XX:CMSFullGCsBeforeCompaction
設置CMS收集器在進行多少次垃圾收集後再進行一次內存碎片整理。如設置-XX:CMSFullGCsBeforeCompaction=2表示CMS收集器進行了2次垃圾收集之後,進行一次內存碎片整理。僅當老年代收集器設置爲CMS時候這個參數纔有效。

5.6.3、GC日誌相關

-XX:+PrintGCDetails
表示輸出GC的詳細情況。
-XX:+PrintGCDateStamps
指定輸出GC時的時間格式,比指定-XX:+PrintGCTimeStamps可讀性更高。
-Xloggc
指定gc日誌的存放位置。如-Xloggc:/var/log/myapp-gc.log表示將gc日誌保存在磁盤/var/log/目錄,文件名爲myapp-gc.log。

5.7、查看內存使用情況

命令:top
PID:進程的ID
  USER:進程所有者
  PR:進程的優先級別,越小越優先被執行
  NInice:值
  VIRT:進程佔用的虛擬內存
  RES:進程佔用的物理內存
  SHR:進程使用的共享內存
  S:進程的狀態。S表示休眠,R表示正在運行,Z表示僵死狀態,N表示該進程優先值爲負數
  %CPU:進程佔用CPU的使用率
  %MEM:進程使用的物理內存和總內存的百分比
  TIME+:該進程啓動後佔用的總的CPU時間,即佔用CPU使用時間的累加值。
  COMMAND:進程啓動命令名稱

5.8、YGC、FGC

youngGC、FullGC
當年輕代收集不能把對象放進終身頤養園時,就會觸發一次完全收集(Major-GC),這裏可能還會牽扯到壓縮,以便爲大對象騰出足夠的空間。

5.9、CPU過高、內存佔用過高處理

6、設計模式

使用涉及模式 其目的是爲了提高代碼的可重用性、代碼的可讀性和代碼的可靠性。**
設計模式的本質是面向對象設計原則的實際運用,是對類的封裝性、繼承性和多態性以及類的關聯關係和組合關係的充分理解
使用設計模式的好處:

可以提高程序員的思維能力、編程能力和設計能力。
使程序設計更加標準化、代碼編制更加工程化,使軟件開發效率大大提高,從而縮短軟件的開發週期。
使設計的代碼可重用性高、可讀性強、可靠性高、靈活性好、可維護性強。

6.1、GoF的23種單例模式

單例(Singleton)模式:某個類只能生成一個實例,該類提供了一個全局訪問點供外部獲取該實例,其拓展是有限多例模式。
原型(Prototype)模式:將一個對象作爲原型,通過對其進行復制而克隆出多個和原型類似的新實例。
工廠方法(Factory Method)模式:定義一個用於創建產品的接口,由子類決定生產什麼產品。
抽象工廠(AbstractFactory)模式:提供一個創建產品族的接口,其每個子類可以生產一系列相關的產品。
建造者(Builder)模式:將一個複雜對象分解成多個相對簡單的部分,然後根據不同需要分別創建它們,最後構建成該複雜對象。
代理(Proxy)模式:爲某對象提供一種代理以控制對該對象的訪問。即客戶端通過代理間接地訪問該對象,從而限制、增強或修改該對象的一些特性。
適配器(Adapter)模式:將一個類的接口轉換成客戶希望的另外一個接口,使得原本由於接口不兼容而不能一起工作的那些類能一起工作。
橋接(Bridge)模式:將抽象與實現分離,使它們可以獨立變化。它是用組合關係代替繼承關係來實現,從而降低了抽象和實現這兩個可變維度的耦合度。
裝飾(Decorator)模式:動態的給對象增加一些職責,即增加其額外的功能。
外觀(Facade)模式:爲多個複雜的子系統提供一個一致的接口,使這些子系統更加容易被訪問。
享元(Flyweight)模式:運用共享技術來有效地支持大量細粒度對象的複用。
組合(Composite)模式:將對象組合成樹狀層次結構,使用戶對單個對象和組合對象具有一致的訪問性。
模板方法(TemplateMethod)模式:定義一個操作中的算法骨架,而將算法的一些步驟延遲到子類中,使得子類可以不改變該算法結構的情況下重定義該算法的某些特定步驟。
策略(Strategy)模式:定義了一系列算法,並將每個算法封裝起來,使它們可以相互替換,且算法的改變不會影響使用算法的客戶。
命令(Command)模式:將一個請求封裝爲一個對象,使發出請求的責任和執行請求的責任分割開。
職責鏈(Chain of Responsibility)模式:把請求從鏈中的一個對象傳到下一個對象,直到請求被響應爲止。通過這種方式去除對象之間的耦合。
狀態(State)模式:允許一個對象在其內部狀態發生改變時改變其行爲能力。
觀察者(Observer)模式:多個對象間存在一對多關係,當一個對象發生改變時,把這種改變通知給其他多個對象,從而影響其他對象的行爲。
中介者(Mediator)模式:定義一箇中介對象來簡化原有對象之間的交互關係,降低系統中對象間的耦合度,使原有對象之間不必相互瞭解。
迭代器(Iterator)模式:提供一種方法來順序訪問聚合對象中的一系列數據,而不暴露聚合對象的內部表示。
訪問者(Visitor)模式:在不改變集合元素的前提下,爲一個集合中的每個元素提供多種訪問方式,即每個元素有多個訪問者對象訪問。
備忘錄(Memento)模式:在不破壞封裝性的前提下,獲取並保存一個對象的內部狀態,以便以後恢復它。
解釋器(Interpreter)模式:提供如何定義語言的文法,以及對語言句子的解釋方法,即解釋器。

6.2、單例模式與線程安全

Java 語言包含兩種內在的同步機制:**同步塊(或方法)**和 volatile 變量。
這兩種機制的提出都是爲了實現代碼線程的安全性。其中 Volatile變量的同步性較差(但有時它更簡單並且開銷更低),而且其使用也更容易出錯。

6.3、其他

7、數據庫

7.1、設計
7.1.1、3NF
數據庫設計三大範式:
1nf,每列字段必須具有不可分割性;
2nf 每個屬性必須和主鍵(主屬性)相關;
3nf 每個屬性必須與主屬性直接相關或者說,屬性不依賴於其他非主屬性。

7.2、SQL
7.2.1、SQL執行順序

	```
	sql執行順序:
	(1)from
	(2) on
	(3) join
	(4) where
	(5) group by(開始使用select中的別名,後面的語句中都可以使用)
	(6) avg,sum....
	(7) having
	(8) select
	(9) distinct
	(10) order by
	```

select*
fromtableAjoinBonA.id=B.aId
wheresize>10
groupbysize
havingsum(xxx)>100
Orderbyyyy

7.3、索引

索引提供指向存儲在表的指定列中的數據值的指針,然後根據您指定的排序順序對這些指針排序。數據庫使用索引以找到特定值,然後順指針找到包含該值的行。這樣可以使對應於表的SQL語句執行得更快,可快速訪問數據庫表中的特定信息。
當表中有大量記錄時,若要對錶進行查詢,第一種搜索信息方式是全表搜索,是將所有記錄一一取出,和查詢條件進行一一對比,然後返回滿足條件的記錄,這樣做會消耗大量數據庫系統時間,並造成大量磁盤I/O操作;第二種就是在表中建立索引,然後在索引中找到符合查詢條件的索引值,最後通過保存在索引中的ROWID(相當於頁碼)快速找到表中對應的記錄。
7.3.1、什麼時候建索引

(1)快速取數據;
(2)保證數據記錄的唯一性;
(3)實現表與表之間的參照完整性;
(4)在使用ORDER by、group by子句進行數據檢索時,利用索引可以減少排序和分組的時間。
當表中有大量記錄時,若要對錶進行查詢,第一種搜索信息方式是全表搜索,是將所有記錄一一取出,和查詢條件進行一一對比,然後返回滿足條件的記錄,這樣做會消耗大量數據庫系統時間,並造成大量磁盤I/O操作;第二種就是在表中建立索引,然後在索引中找到符合查詢條件的索引值,最後通過保存在索引中的ROWID(相當於頁碼)快速找到表中對應的記錄。

索引是爲了加速對錶中數據行的檢索而創建的一種分散的存儲結構。
索引是針對表而建立的,它是由數據頁面以外的索引頁面組成的,每個索引頁面中的行都會含有邏輯指針,以便加速檢索物理數據。

7.3.2、索引實現算法,算法複雜度

動態查找樹主要有:二叉查找樹(Binary Search Tree),平衡二叉查找樹(Balanced Binary Search Tree),紅黑樹(Red-Black Tree ),B-tree/B±tree/ B*-tree(B~Tree)。前三者是典型的二叉查找樹結構。
其查找的時間複雜度O(log2N)與樹的深度相關,那麼降低樹的深度自然會提高查找效率。

7.3.3、索引缺點與有點

優點
1)大大加快數據的檢索速度;
2)創建唯一性索引,保證數據庫表中每一行數據的唯一性;
3)加速表和表之間的連接;
4)在使用分組和排序子句進行數據檢索時,可以顯著減少查詢中分組和排序的時間。
缺點
1)索引需要佔物理空間。
2)當對錶中的數據進行增加、刪除和修改的時候,索引也要動態的維護,降低了數據的維護速度。
根據數據庫的功能,可以在數據庫設計器中創建四種索引:普通索引、唯一索引、主鍵索引和聚集索引。

7.3.4、聚簇索引

也稱爲聚集索引,在聚集索引中,表中行的物理順序與鍵值的邏輯(索引)順序相同。一個表只能包含一個聚集索引, 即如果存在聚集索引,就不能再指定CLUSTERED 關鍵字。
是聚集索引的意思.CLUSTERED| NONCLUSTERED
指定爲 PRIMARY KEY 或UNIQUE約束創建聚集或非聚集索引。PRIMARY KEY 約束默認爲CLUSTERED;UNIQUE約束默認爲 NONCLUSTERED。如果表中已存在聚集約束或索引,那麼在 ALTER TABLE 中就不能指定 CLUSTERED。如果表中已存在聚集約束或索引,PRIMARY KEY 約束默認爲 NONCLUSTERED
索引不是聚集索引,則表中行的物理順序與鍵值的邏輯順序不匹配。與非聚集索引相比,聚集索引通常提供更快的數據訪問速度。聚集索引更適用於對很少對基表進行增刪改操作的情況。。

7.3.5、什麼SQL不走索引

你在Instance級別所用的是all_rows的方式
1)你的表的統計信息(最可能的原因)
2)你的表很小,上文提到過的,Oracle的優化器認爲不值得走索引。

1、建立組合索引,但查詢謂詞並未使用組合索引的第一列,此處有一個INDEX SKIP SCAN概念。
2、在包含有null值的table列上建立索引,當時使用select count(*) from table時不會使用索引。
3、在索引列上使用函數時不會使用索引,如果一定要使用索引只能建立函數索引。
4、當被索引的列進行隱式的類型轉換時不會使用索引
5、並不是所有情況使用索引都會加快查詢速度,full scan table 有時會更快,尤其是當查詢的數據量佔整個
表的比重較大時,因爲full scan table採用的是多塊讀,
當Oracle優化器沒有選擇使用索引時不要立即強制使用,要充分證明使用索引確實查詢更快時再使用強制索引。
6、<>
7、like’’百分號在前
8、not in ,not exist.

7.4、分庫、分表

7.4.1、什麼時候分
據庫中的數據量不一定是可控的,在未進行分庫分表的情況下,隨着時間和業務 的發展,庫中的表會越來越多,表中的數據量也會越來越大,相應地,數據操作,增刪改查的開銷也會越來越大;另外,由於無法進行分佈式式部署,而一臺服務器的資源(CPU、磁盤、內存、IO等)是有限的,最終數據庫所能承載的數據量、數據處理能力都將遭遇瓶頸。
分庫分表有垂直切分和水平切分兩種。
何謂垂直切分,即將表按照功能模塊、關係密切程度劃分出來,部署到不同的庫上。例如,我們會建立定義數據庫workDB、商品數據庫payDB、用戶數據庫userDB、日誌數據庫logDB等,分別用於存儲項目數據定義表、商品定義表、用戶數據表、日誌數據表等。
7.4.2、會有什麼問題
1)事務問題:在執行分庫分表之後,由於數據存儲到了不同的庫上,數據庫事務管理出現了困難。如果依賴數據庫本身的分佈式事務管理功能去執行事務,將付出高昂的性能代價;
如果由應用程序去協助控制,形成程序邏輯上的事務,又會造成編程方面的負擔。
2)跨庫跨表的join問題:在執行了分庫分表之後,難以避免會將原本邏輯關聯性很強的數據劃分到不同的表、不同的庫上,這時,表的關聯操作將受到限制,我們無法join位於不同分庫的表,也無法join分表粒度不同的表,結果原本一次查詢能夠完成的業務,可能需要多次查詢才能完成。
3)額外的數據管理負擔和數據運算壓力:

7.5、事務

事務由事務開始(begin transaction)和事務結束(end transaction)之間執行的全體操作組成。

7.5.1、基本屬性、傳播屬性

事務的四大屬性ACID即事務的原子性(Atomicity)、一致性(Consistency)、隔離性(Isolation)、持久性(Durability.。
原子性:一個事務(transaction)中的所有操作,要麼全部完成,要麼全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被回滾(Rollback)到事務開始前的狀態,就像這個事務從來沒有執行過一樣。
一致性:在事務開始之前和事務結束以後,數據庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預設規則,這包含資料的精確度、串聯性以及後續數據庫可以自發性地完成預定的工作。
隔離性:數據庫允許多個併發事務同時對其數據進行讀寫和修改的能力,隔離性可以防止多個事務併發執行時由於交叉執行而導致數據的不一致。事務隔離分爲不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重複讀(repeatable read)和串行化(Serializable)。
持久性:事務處理結束後,對數據的修改就是永久的,即便系統故障也不會丟失。

7.5.2、隔離級別

事務隔離分爲不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重複讀(repeatable read)和串行化

① Serializable (串行化):可避免髒讀、不可重複讀、幻讀的發生。
② Repeatable read (可重複讀):可避免髒讀、不可重複讀的發生。
③ Read committed (讀已提交):可避免髒讀的發生。
④ Read uncommitted (讀未提交):最低級別,任何情況都無法保證。

髒讀、不可重複讀、幻象讀
髒讀:指當一個事務正字訪問數據,並且對數據進行了修改,而這種數據還沒有提交到數據庫中,這時,另外一個事務也訪問這個數據,然後使用了這個數據。因爲這個數據還沒有提交那麼另外一個事務讀取到的這個數據我們稱之爲髒數據。依據髒數據所做的操作肯能是不正確的。
不可重複讀:指在一個事務內,多次讀同一數據。在這個事務還沒有執行結束,另外一個事務也訪問該同一數據,那麼在第一個事務中的兩次讀取數據之間,由於第二個事務的修改第一個事務兩次讀到的數據可能是不一樣的,這樣就發生了在一個事物內兩次連續讀到的數據是不一樣的,這種情況被稱爲是不可重複讀。
幻象讀:一個事務先後讀取一個範圍的記錄,但兩次讀取的紀錄數不同,我們稱之爲幻象讀(兩次執行同一條 select 語句會出現不同的結果,第二次讀會增加一數據行,並沒有說這兩次執行是在同一個事務中

spring事務傳播特性
事務傳播行爲就是多個事務方法相互調用時,事務如何在這些方法間傳播。
spring支持7種事務傳播行爲:

propagation_requierd:如果當前沒有事務,就新建一個事務,如果已存在一個事務中,加入到這個事務中,這是最常見的選擇。
propagation_supports:支持當前事務,如果沒有當前事務,就以非事務方法執行。
propagation_mandatory:使用當前事務,如果沒有當前事務,就拋出異常。
propagation_required_new:新建事務,如果當前存在事務,把當前事務掛起。
propagation_not_supported:以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
propagation_never:以非事務方式執行操作,如果當前事務存在則拋出異常。
propagation_nested:如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則執行與propagation_required類似的操作

Spring 默認的事務傳播行爲是 PROPAGATION_REQUIRED,它適合於絕大多數的情況。

7.5.3、分佈式事務CAP和base理論

分佈式系統對於數據的複製需求一般都來自於以下兩個原因:
1)爲了增加系統的可用性,以防止單點故障引起的系統不可用
2)提高系統的整體性能,通過負載均衡技術,能夠讓分佈在不同地方的數據副本都能夠爲用戶提供服務
數據複製在可用性和性能方面給分佈式系統帶來的巨大好處是不言而喻的,然而數據複製所帶來的一致性挑戰,也是每一個系統研發人員不得不面對的。

7.5.3.1、CAP

CAP理論:一個分佈式系統不可能同時滿足一致性(C:Consistency)、可用性(A:Availability)和分區容錯性(P:Partition tolerance)這三個基本需求,最多隻能同時滿足其中兩項。
1)一致性
在分佈式環境下,一致性是指數據在多個副本之間能否保持一致的特性。在一致性的需求下,當一個系統在數據一致的狀態下執行更新操作後,應該保證系統的數據仍然處於一直的狀態。
對於一個將數據副本分佈在不同分佈式節點上的系統來說,如果對第一個節點的數據進行了更新操作並且更新成功後,卻沒有使得第二個節點上的數據得到相應的更新,於是在對第二個節點的數據進行讀取操作時,獲取的依然是老數據(或稱爲髒數據),這就是典型的分佈式數據不一致的情況。在分佈式系統中,如果能夠做到針對一個數據項的更新操作執行成功後,所有的用戶都可以讀取到其最新的值,那麼這樣的系統就被認爲具有強一致性
2)可用性
可用性是指系統提供的服務必須一直處於可用的狀態,對於用戶的每一個操作請求總是能夠在有限的時間內返回結果。這裏的重點是"有限時間內"和"返回結果"。
"有限時間內"是指,對於用戶的一個操作請求,系統必須能夠在指定的時間內返回對應的處理結果,如果超過了這個時間範圍,那麼系統就被認爲是不可用的。另外,"有限的時間內"是指系統設計之初就設計好的運行指標,通常不同系統之間有很大的不同,無論如何,對於用戶請求,系統必須存在一個合理的響應時間,否則用戶便會對系統感到失望。
"返回結果"是可用性的另一個非常重要的指標,它要求系統在完成對用戶請求的處理後,返回一個正常的響應結果。正常的響應結果通常能夠明確地反映出隊請求的處理結果,即成功或失敗,而不是一個讓用戶感到困惑的返回結果。
3)分區容錯性
分區容錯性約束了一個分佈式系統具有如下特性:分佈式系統在遇到任何網絡分區故障的時候,仍然需要能夠保證對外提供滿足一致性和可用性的服務,除非是整個網絡環境都發生了故障。
網絡分區是指在分佈式系統中,不同的節點分佈在不同的子網絡(機房或異地網絡)中,由於一些特殊的原因導致這些子網絡出現網絡不連通的狀況,但各個子網絡的內部網絡是正常的,從而導致整個系統的網絡環境被切分成了若干個孤立的區域。需要注意的是,組成一個分佈式系統的每個節點的加入與退出都可以看作是一個特殊的網絡分區。

7.5.3.2、BASE

BASE是Basically Available(基本可用)、Soft state(軟狀態)和Eventually consistent(最終一致性)三個短語的縮寫。BASE理論是對CAP中一致性和可用性權衡的結果,其來源於對大規模互聯網系統分佈式實踐的總結,是基於CAP定理逐步演化而來的。BASE理論的核心思想是:即使無法做到強一致性,但每個應用都可以根據自身業務特點,採用適當的方式來使系統達到最終一致性。
1、基本可用
基本可用是指分佈式系統在出現不可預知故障的時候,允許損失部分可用性----注意,這絕不等價於系統不可用。比如:
(1)響應時間上的損失。正常情況下,一個在線搜索引擎需要在0.5秒之內返回給用戶相應的查詢結果,但由於出現故障,查詢結果的響應時間增加了1~2秒
(2)系統功能上的損失:正常情況下,在一個電子商務網站上進行購物的時候,消費者幾乎能夠順利完成每一筆訂單,但是在一些節日大促購物高峯的時候,由於消費者的購物行爲激增,爲了保護購物系統的穩定性,部分消費者可能會被引導到一個降級頁面
2、軟狀態
軟狀態指允許系統中的數據存在中間狀態,並認爲該中間狀態的存在不會影響系統的整體可用性,即允許系統在不同節點的數據副本之間進行數據同步的過程存在延時
3、最終一致性
最終一致性強調的是所有的數據副本,在經過一段時間的同步之後,最終都能夠達到一個一致的狀態。因此,最終一致性的本質是需要系統保證最終數據能夠達到一致,而不需要實時保證系統數據的強一致性。
總的來說,BASE理論面向的是大型高可用可擴展的分佈式系統,和傳統的事物ACID特性是相反的,它完全不同於ACID的強一致性模型,而是通過犧牲強一致性來獲得可用性,並允許數據在一段時間內是不一致的,但最終達到一致狀態。但同時,在實際的分佈式場景中,不同業務單元和組件對數據一致性的要求是不同的,因此在具體的分佈式系統架構設計過程中,ACID特性和BASE理論往往又會結合在一起。

7.6、MySQL

7.6.1、存儲引擎分類
(1):MyISAM存儲引擎(2)InnoDB存儲引擎*,(3):MEMORY存儲引擎,(4)MERGE存儲引擎
7.6.2、不同存儲引擎特點
(1):MyISAM存儲引擎:不支持事務、也不支持外鍵,優勢是訪問速度快,對事務完整性沒有 要求或者以select,insert爲主的應用基本上可以用這個引擎來創建表
支持3種不同的存儲格式,分別是:靜態表;動態表;壓縮表
靜態表:表中的字段都是非變長字段,這樣每個記錄都是固定長度的,優點存儲非常迅速,容易緩存,出現故障容易恢復;缺點是佔用的空間通常比動態表多(因爲存儲時會按照列的寬度定義補足空格)ps:在取數據的時候,默認會把字段後面的空格去掉,如果不注意會把數據本身帶的空格也會忽略。
動態表:記錄不是固定長度的,這樣存儲的優點是佔用的空間相對較少;缺點:頻繁的更新、刪除數據容易產生碎片,需要定期執行OPTIMIZE TABLE或者myisamchk-r命令來改善性能
壓縮表:因爲每個記錄是被單獨壓縮的,所以只有非常小的訪問開支
(2)InnoDB存儲引擎:該存儲引擎提供了具有提交、回滾和崩潰恢復能力的事務安全。但是對比MyISAM引擎,寫的處理效率會差一些,並且會佔用更多的磁盤空間以保留數據和索引。
InnoDB存儲引擎的特點:支持自動增長列,支持外鍵約束
(3):MEMORY存儲引擎:Memory存儲引擎使用存在於內存中的內容來創建表。每個memory表只實際對應一個磁盤文件,格式是.frm。memory類型的表訪問非常的快,因爲它的數據是放在內存中的,並且默認使用HASH索引,但是一旦服務關閉,表中的數據就會丟失掉。
MEMORY存儲引擎的表可以選擇使用BTREE索引或者HASH索引,兩種不同類型的索引有其不同的使用範圍
Hash索引優點:
Hash 索引結構的特殊性,其檢索效率非常高,索引的檢索可以一次定位,不像B-Tree 索引需要從根節點到枝節點,最後才能訪問到頁節點這樣多次的IO訪問,所以 Hash 索引的查詢效率要遠高於 B-Tree 索引。
Hash索引缺點: 那麼不精確查找呢,也很明顯,因爲hash算法是基於等值計算的,所以對於“like”等範圍查找hash索引無效,不支持;
Memory類型的存儲引擎主要用於哪些內容變化不頻繁的代碼表,或者作爲統計操作的中間結果表,便於高效地對中間結果進行分析並得到最終的統計結果,。對存儲引擎爲memory的表進行更新操作要謹慎,因爲數據並沒有實際寫入到磁盤中,所以一定要對下次重新啓動服務後如何獲得這些修改後的數據有所考慮。
(4)MERGE存儲引擎:Merge存儲引擎是一組MyISAM表的組合,這些MyISAM表必須結構完全相同,merge表本身並沒有數據,對merge類型的表可以進行查詢,更新,刪除操作,這些操作實際上是對內部的MyISAM表進行的。
7.6.3、行鎖、表鎖
mysql常用引擎有MYISAM和InnoDB,而InnoDB是mysql默認的引擎。MYISAM不支持行鎖,而InnoDB支持行鎖和表鎖。

類型 行鎖 表鎖 頁鎖
MyISAM
BDB
InnoDB

表鎖:不會出現死鎖,發生鎖衝突機率高,併發低。
行鎖:會出現死鎖,發生鎖衝突機率低,併發高。
鎖衝突:例如說事務A將某幾行上鎖後,事務B又對其上鎖,鎖不能共存否則會出現鎖衝突。(但是共享鎖可以共存,共享鎖和排它鎖不能共存,排它鎖和排他鎖也不可以)
死鎖:例如說兩個事務,事務A鎖住了15行,同時事務B鎖住了610行,此時事務A請求鎖住610行,就會阻塞直到事務B施放610行的鎖,而隨後事務B又請求鎖住15行,事務B也阻塞直到事務A釋放15行的鎖。死鎖發生時,會產生Deadlock錯誤。
7.6.4、行鎖的類型
行鎖分 共享鎖 和 排它鎖。
共享鎖又稱:讀鎖。當一個事務對某幾行上讀鎖時,允許其他事務對這幾行進行讀操作,但不允許其進行寫操作,也不允許其他事務給這幾行上排它鎖,但允許上讀鎖。
排它鎖又稱:寫鎖。當一個事務對某幾個上寫鎖時,不允許其他事務寫,但允許讀。更不允許其他事務給這幾行上任何鎖。包括寫鎖。
7.6.5、行鎖的實現
1.行鎖必須有索引才能實現,否則會自動鎖全表,那麼就不是行鎖了。
2.兩個事務不能鎖同一個索引,例如:
1.事務A先執行:
2.selectmathfromzjewheremath>60forupdate;
3.事務B再執行:
4.selectmathfromzjewheremath<60forupdate;
5.這樣的話,事務B是會阻塞的。如果事務B把math索引換成其他索引就不會阻塞,但注意,換成其他索引鎖住的行不能和math索引鎖住的行有重複。

7.7 Oracle

Oracle的數據結構
oracle數據庫是數據的無聊存儲,包括數據文件ORA或DBF,控制文件,聯機日誌,參數文件,這裏的數據庫是一個操作系統只有一個庫。可以看作是oracle就只有一個大數據庫
實例:一個oracle實例有一系列的後臺進程和內存結構組成,一個數據庫可以有n個實例
數據文件dbf:數據文件是數據庫的物理存儲單位,數據庫的數據是存儲在表空間中的,真正是在某一個或多個數據文件中,而一個表空間
可以由一個或多個數據文件組成,一個數據文件只能屬於一個表空間,一旦數據文件被加入到某個表空間後,就不能刪除這個文件,如果
要刪除文件,只能刪除其所屬的表空間才行
表空間:表空間是oracle對物理數據庫上相關數據文件的邏輯映射,一個數據庫可以被劃分多個表空間,每個數據庫至少有一個表空間
用戶:用戶是在實例下建立的,不同實例中可以建立相同的用戶。
表的數據是由用戶放入某一個表空間,而這個表空間會隨機把這些表數據放到一個或多個數據文件

8、緩存

8.1、時機

remote dictionary server (遠程數據服務) 內存高速緩存數據庫 數據模型爲 k-v 也就是redis 的一種最經常使用的數據類型 stringk-v 的算法時間複雜度 可是 0(1) 而mysql 的查詢是基於表關聯技術 ,這就是nosql的優勢所在。

redis 和memcahe 的比較:

Redis不僅僅支持簡單的k/v類型的數據,同時還提供list,set,zset,hash等數據結構的存儲。
Redis支持master-slave(主-從)模式應用,高可用的cache系統,支持集羣服務器之間數據同步。
Redis支持數據持久化,可以將內存中的數據保持在磁盤中,重啓的時候可以再次加載進行使用。
Redis單個value的最大限制是1GB,(k-v),memcached只能保存1MB的數據。(k:250kb v:1mb)
PS:1 從存儲媒介來看,內存比磁盤的讀取速度 hash查找是100w/s 的數量級
2 多路複用io (todo)

8.2、原因

那麼爲什麼要使用類似redis這樣的Nosql數據庫呢?
1) 當數據量的總大小一個機器放不下時;
2) 數據索引一個機器的內存放不下時;
3) 訪問量(讀寫混合)一個實例放不下時
單機時代,存儲只用一臺機器裝mysql,如果每次存儲成千上萬條數據,這樣很會導致mysql的性能很差,存儲以及讀取速度很慢,然後就演變成緩存+mysql+垂直拆分的方式。
Cache作爲中間緩存時代,將所有的數據先保存到緩存中,然後再存入mysql中,減小數據庫壓力,提高效率。
但是當數據再次增加到又一個量級,上面的方式也不能滿足需求,由於數據庫的寫入壓力增加,緩存只能緩解數據庫的讀取壓力。讀寫集中在一個數據庫上讓數據庫不堪重負,大部分網站開始使用主從複製技術來達到讀寫分離,以提高讀寫性能和讀庫的可擴展性。Mysql的master-slave模式成爲這個時候的網站標配了。
主從分離模式時代,在redis的高速緩存,MySQL的主從複製,讀寫分離的基礎之上,這時MySQL主庫的寫壓力開始出現瓶頸,而數據量的持續猛增,由於MyISAM使用表鎖,在高併發下會出現嚴重的鎖問題,大量的高併發MySQL應用開始使用InnoDB引擎代替MyISAM。

8.3、Redis

爲什麼選擇Redis

1)Redis不僅僅支持簡單的k/v類型的數據,同時還提供string、hash、list、set及zset(sorted set:有序集合)。
2)Redis支持master-slave(主-從)模式應用
3)Redis支持數據持久化,可以將內存中的數據保持在磁盤中,重啓的時候可以再次加載進行使用。
4)Redis單個value的string類型是Redis最大限制是1GB,memcached只能保存1MB的數據

8.3.1 Redisd的幾種數據淘汰策略

定時刪除策略 : 在設置鍵的過期時間的同時,創建一個定時器,讓定時器在鍵的過期時間來臨時,立即執行對鍵的刪除操作。
優點 : 對內存友好,保證過期鍵會儘可能快地被刪除,並釋放過期鍵所佔用的內存。
缺點 : 對CPU時間不友好,佔用太多CPU時間,影響服務器的響應時間和吞吐量。
惰性刪除 策略 : 放任過期鍵不管,每次從鍵空間讀寫操作時,都檢查鍵是否過期,如果過期,刪除該鍵,如果沒有過期,返回該鍵。
優點 : 對CPU時間友好,讀寫操作鍵時纔對鍵進行過期檢查,刪除過期鍵的操作只會在非做不可的情況下進行。
缺點 : 對內存不友好,只要鍵不刪除,就不會釋放內存,浪費太多內存,有內存泄漏風險。
定期刪除 策略 :
對定時刪除策略和惰性刪除策略的一種整合和折中。每隔一段時間執行一次定時刪除,並通過限制刪除操作執行的總時長和總頻率來限制刪除操作對CPU佔用時間的影響。通過定期刪除過期鍵,有效減少了因爲過期鍵而帶來的內存浪費。
難點:確定刪除操作執行的總時長和總頻率。執行太頻繁,執行時間過長,就會退化成定時刪除策略,影響客戶端請求效率;執行得太少,執行時間太短,會演變爲惰性刪除,存在內存浪費的情況。
Redis服務器使用惰性刪除和定期刪除兩種策略,通過配合使用,很好地在合理使用CPU時間和避免浪費內存之間取得平衡。

舉例:
從過期鍵中隨機選取 20 個 key
遍歷這 20 個 key,並對過期的 key進行刪除操作
如果過期的 key 比率超過25%,則重複步驟 1
同時,爲了保證過期掃描不會出現循環過度,導致線程卡死現象,增加了掃描時間的上限,默認不會超過 25ms以及頻次上線10次。

主動清理策略:
當前已用內存超過maxmemory限定時,觸發主動清理策略。
清理時會根據用戶配置的maxmemory-policy來做適當的清理。
主動清理策略主要有一下六種:

volatile-lru : 從已設置過期時間的數據集(server.db[i].expires)中挑選最近最少使用 的數據淘汰。
volatile-ttl : 從已設置過期時間的數據集(server.db[i].expires)中挑選將要過期的數 據淘汰。
volatile-random : 從已設置過期時間的數據集(server.db[i].expires)中任意選擇數據 淘汰。
allkeys-lru : 從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰。
allkeys-random : 從數據集(server.db[i].dict)中任意選擇數據淘汰。
no-enviction : 禁止驅逐數據。

8.4、“緩存擊穿”和“緩存雪崩”

緩存穿透:是指查詢一個數據庫一定不存在的數據。正常的使用緩存流程大致是,數據查詢先進行緩存查詢,如果key不存在或者key已經過期,再對數據庫進行查詢,並把查詢到的對象,放進緩存。如果數據庫查詢對象爲空,則不放進緩存。

避免方式一般會採用緩存空值的方式,也就是【代碼流程】中第5步,如果從數據庫查詢的對象爲空,也放入緩存,只是設定的緩存過期時間較短,比如設置爲60秒。

緩存雪崩:是指在某一個時間段,緩存集中過期失效。
產生雪崩的原因之一,比如在寫本文的時候,馬上就要到雙十二零點,很快就會迎來一波搶購,這波商品時間比較集中的放入了緩存,假設緩存一個小時。那麼到了凌晨一點鐘的時候,這批商品的緩存就都過期了。而對這批商品的訪問查詢,都落到了數據庫上,對於數據庫而言,就會產生週期性的壓力波峯。

一般可以在時間加上一個隨機因子。這樣能儘可能分散緩存過期時間,而且,熱門鍵值緩存時間長一些,冷門類目緩存時間短一些,也能節省緩存服務的資源。

緩存擊穿:是指一個key非常熱點,在不停的扛着大併發,大併發集中對這一個點進行訪問,當這個key在失效的瞬間,持續的大併發就穿破緩存,直接請求數據庫,就像在一個屏障上鑿開了一個洞。

8.5、一致性Hash

CARP :Common Access Redundancy Protocol共用地址冗餘協議Common Access Redundancy Protocol,或簡稱 CARP 能夠使多臺主機共享同一 IP 地址。在某些配置中,這樣做可以提高可用性,或實現負載均衡。這些主機也可以同時使用其他的不同的 IP 地址。
一致性哈希基本解決了在P2P環境中最爲關鍵的問題——如何在動態的網絡拓撲中分佈存儲和路由。每個節點僅需維護少量相鄰節點的信息,並且在節點加入/退出系統時,僅有相關的少量節點參與到拓撲的維護中。所有這一切使得一致性哈希成爲第一個實用的DHT算法。
但是一致性哈希的路由算法尚有不足之處。在查詢過程中,查詢消息要經過O(N)步(O(N)表示與N成正比關係,N代表系統內的節點總數)才能到達被查詢的節點。不難想象,當系統規模非常大時,節點數量可能超過百萬,這樣的查詢效率顯然難以滿足使用的需要。換個角度來看,即使用戶能夠忍受漫長的時延,查詢過程中產生的大量消息也會給網絡帶來不必要的負荷。
DHT(Distributed Hash Table,分佈式哈希表)類似Tracker的根據種子特徵碼返回種子信息的網絡。DHT全稱叫分佈式哈希表(Distributed Hash Table),是一種分佈式存儲方法。在不需要服務器的情況下,每個客戶端負責一個小範圍的路由,並負責存儲一小部分數據,從而實現整個DHT網絡的尋址和存儲。新版BitComet允許同行連接DHT網絡和Tracker,也就是說在完全不連上Tracker服務器的情況下,也可以很好的下載,因爲它可以在DHT網絡中尋找下載同一文件的其他用戶。

9、MQ

9.1 MQ特性

1、順序保證/先進先出
不能先進先出,都不能說是隊列了。消息隊列的順序在入隊的時候就基本已經確定了,一般是不需人工干預的。而且,最重要的是,數據是隻有一條數據在使用中。 這也是MQ在諸多場景被使用的原因。
2、發佈訂閱/異步通信
發佈訂閱是一種很高效的處理方式,如果不發生阻塞,基本可以當做是同步操作。這種處理方式能非常有效的提升服務器利用率,這樣的應用場景非常廣泛。
3、持久化
持久化確保MQ的使用不只是一個部分場景的輔助工具,而是讓MQ能像數據庫一樣存儲核心的數據,消息中間件允許把數據持久化知道他們完全被處理。
4、分佈式
在現在大流量、大數據的使用場景下,只支持單體應用的服務器軟件基本是無法使用的,支持分佈式的部署,才能被廣泛使用。而且,MQ的定位就是一個高性能的中間件。
5、解耦
基於數據的接口層,不同的項目都實現這個接口,允許獨立的修改或者擴展兩邊的處理過程,只要兩邊遵守相同的接口約束即可,從而達到解耦作用。
6、增加緩衝,避免突然大量業務訪問的壓力

9.2 Kafka、RabbitMQ、RocketMQ性能比較:

Kafka:是LinkedIn開源的分佈式發佈-訂閱消息系統,目前歸屬於Apache頂級項目。Kafka主要特點是基於Pull的模式來處理消息消費,追求高吞吐量,一開始的目的就是用於日誌收集和傳輸。0.8版本開始支持複製,不支持事務,對消息的重複、丟失、錯誤沒有嚴格要求,適合產生大量數據的互聯網服務的數據收集業務。
RabbitMQ:是使用Erlang語言開發的開源消息隊列系統,基於AMQP協議來實現。AMQP的主要特徵是面向消息、隊列、路由(包括點對點和發佈/訂閱)、可靠性、安全。AMQP協議更多用在企業系統內,對數據一致性、穩定性和可靠性要求很高的場景,對性能和吞吐量的要求還在其次。
RocketMQ:是阿里開源的消息中間件,它是純Java開發,具有高吞吐量、高可用性、適合大規模分佈式系統應用的特點。RocketMQ思路起源於Kafka,但並不是Kafka的一個Copy,它對消息的可靠傳輸及事務性做了優化,目前在阿里集團被廣泛應用於交易、充值、流計算、消息推送、日誌流式處理、binglog分發等場景。

在服務端處理同步發送的性能上,Kafka>RocketMQ>RabbitMQ

9.1、P2P
peer to peer
9.2、pub/sub
廣播

10、網絡

10.1、OSI模型(計算機網絡分層)

順序分別爲:
7 應用層 6 表示層 5 會話層 4 傳輸層 3 網絡層 2 數據鏈路層 1 物理層
OSI是一個開放性的通信系統互連參考模型,他是一個定義得非常好的協議規範。OSI模型有7層結構,每層都可以有幾個子層。
OSI的7層從上到下分別是: 7 應用層 6 表示層 5 會話層 4 傳輸層 3 網絡層 2 數據鏈路層 1 物理層 ;
其中高層(即7、6、5、4層)定義了應用程序的功能,下面3層(即3、2、1層)主要面向通過網絡的端到端的數據流

10.2、DNS

DNS(Domain Name System,域名系統),萬維網上作爲域名和IP地址相互映射的一個分佈式數據庫,能夠使用戶更方便的訪問互聯網,而不用去記住能夠被機器直接讀取的IP數串。通過域名,最終得到該域名對應的IP地址的過程叫做域名解析(或主機名解析)。
DNS協議運行在UDP協議之上,使用端口號53。在RFC文檔中RFC 2181對DNS有規範說明,RFC 2136對DNS的動態更新進行說明,RFC 2308對DNS查詢的反向緩存進行說明。

10.3、Http協議狀態碼

200 OK 服務器成功處理了請求(這個是我們見到最多的)
301/302 Moved Permanently(重定向)請求的URL已移走。Response中應該包含一個Location URL, 說明資源現在所處的位置
304 Not Modified(未修改)客戶的緩存資源是最新的, 要客戶端使用緩存
404 Not Found 未找到資源
501 Internal Server Error服務器遇到一個錯誤,使其無法對請求提供服務

10.4、TCP、UDP

TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)協議屬於傳輸層協議。其中TCP提供IP環境下的數據可靠傳輸,它提供的服務包括數據流傳送、可靠性、有效流控、全雙工操作和多路複用。通過面向連接、端到端和可靠的數據包發送。通俗說,它是事先爲所發送的數據開闢出連接好的通道,然後再進行數據發送;而UDP則不爲IP提供可靠性、流控或差錯恢復功能。一般來說,TCP對應的是可靠性要求高的應用,而UDP對應的則是可靠性要求低、傳輸經濟的應用。

TCP支持的應用協議主要有:Telnet、FTP、SMTP等
UDP支持的應用層協議主要有:NFS(網絡文件系統)、SNMP(簡單網絡管理協議)、DNS(主域名稱系統)、TFTP(通用文件傳輸協議)等

10.5、IP

網絡之間互連的協議(IP)是Internet Protocol的外語縮寫, [1] 中文縮寫爲“網協”。
網絡之間互連的協議也就是爲計算機網絡相互連接進行通信而設計的協議。在因特網中,它是能使連接到網上的所有計算機網絡實現相互通信的一套規則,規定了計算機在因特網上進行通信時應當遵守的規則。任何廠家生產的計算機系統,只要遵守IP協議就可以與因特網互連互通。IP地址具有唯一性,根據用戶性質的不同,可以分爲5類。另外,IP還有進入防護,知識產權,指針寄存器等含義。

10.6、https

10.6.1 http與https的區別

超文本傳輸協議HTTP協議被用於在Web瀏覽器和網站服務器之間傳遞信息。HTTP協議以明文方式發送內容,不提供任何方式的數據加密,如果攻擊者截取了Web瀏覽器和網站服務器之間的傳輸報文,就可以直接讀懂其中的信息,因此HTTP協議不適合傳輸一些敏感信息,比如信用卡號、密碼等。
爲了解決HTTP協議的這一缺陷,需要使用另一種協議:安全套接字層超文本傳輸協議HTTPS。爲了數據傳輸的安全,HTTPS在HTTP的基礎上加入了SSL協議,SSL依靠證書來驗證服務器的身份,併爲瀏覽器和服務器之間的通信加密。
HTTPS和HTTP的區別主要爲以下四點:

一、https協議需要到ca申請證書,一般免費證書很少,需要交費。
二、http是超文本傳輸協議,信息是明文傳輸,https 則是具有安全性的ssl加密傳輸協議。
三、http和https使用的是完全不同的連接方式,用的端口也不一樣,前者是80,後者是443。
四、http的連接很簡單,是無狀態的;HTTPS協議是由SSL+HTTP協議構建的可進行加密傳輸、身份認證的網絡協議,比http協議安全。

10.6.2、https的通信原理

客戶端在使用HTTPS方式與Web服務器通信時有以下幾個步驟:
HTTPS方式與Web服務器
 (1)客戶使用https的URL訪問Web服務器,要求與Web服務器建立SSL連接。
 (2)Web服務器收到客戶端請求後,會將網站的證書信息(證書中包含公鑰)傳送一份給客戶端。
 (3)客戶端的瀏覽器與Web服務器開始協商SSL連接的安全等級,也就是信息加密的等級。
 (4)客戶端的瀏覽器根據雙方同意的安全等級,建立會話密鑰,然後利用網站的公鑰將會話密鑰加密,並傳送給網站。
 (5)Web服務器利用自己的私鑰解密出會話密鑰。
 (6)Web服務器利用會話密鑰加密與客戶端之間的通信。

10.6.3、https的四次握手:

1、客戶端請求建立SSL鏈接,並向服務端發送一個隨機數–Client random和客戶端支持的加密方法,比如RSA公鑰加密,此時是明文傳輸。

2、服務端回覆一種客戶端支持的加密方法、一個隨機數–Server random、授信的服務器證書和非對稱加密的公鑰。

3.客戶端收到服務端的回覆後利用服務端的公鑰,加上新的隨機數–Premaster secret 通過服務端下發的公鑰及加密方法進行加密,發送給服務器。

4、服務端收到客戶端的回覆,利用已知的加解密方式進行解密,同時利用Client random、Server random和Premaster secret通過一定的算法生成HTTP鏈接數據傳輸的對稱加密key – session key。

11、IO與NIO

一個IO操作可以分爲兩個部分:發出請求、結果完成。如果從發出請求到結果返回,一直Block,那就是Blocking IO;如果發出請求就可以返回(結果完成不考慮),就是non-blocking IO;如果發出請求就返回,結果返回是Block在select或者poll上的,則其只能稱爲IO multiplexing;如果發出請求就返回,結果返回通過Call Back的方式被處理,就是AIO。
11.1、NIO和IO的主要區別:
1)IO是面向流的,NIO是面向緩衝區的
2)阻塞與非阻塞IO:
這意味着,當一個線程調用read() 或 write()時,該線程被阻塞,直到有一些數據被讀取,或數據完全寫入。該線程在此期間不能再幹任何事情了。Java NIO的非阻塞模式,使一個線程從某通道發送請求讀取數據,但是它僅能得到目前可用的數據,如果目前沒有數據可用時,就什麼都不會獲取,而不是保持線程阻塞,所以直至數據變的可以讀取之前,該線程可以繼續做其他的事情。 非阻塞寫也是如此。一個線程請求寫入一些數據到某通道,但不需要等待它完全寫入,這個線程同時可以去做別的事情。 線程通常將非阻塞IO的空閒時間用於在其它通道上執行IO操作,所以一個單獨的線程現在可以管理多個輸入和輸出通道(channel)。
3)選擇器(Selectors)
Java NIO的選擇器允許一個單獨的線程來監視多個輸入通道,你可以註冊多個通道使用一個選擇器,然後使用一個單獨的線程來“選擇”通道:這些通道里已經有可以處理的輸入,或者選擇已準備寫入的通道。這種選擇機制,使得一個單獨的線程很容易來管理多個通道。

12、 Web服務

Web服務器的工作原理並不複雜,一般可分成如下4個步驟:連接過程、請求過程、應答過程以及關閉連接。下面對這4個步驟作一簡單的介紹。連接過程就是Web服務器和其瀏覽器之間所建立起來的一種連接。查看連接過程是否實現,用戶可以找到和打開socket這個虛擬文件,這個文件的建立意味着連接過程這一步驟已經成功建立。請求過程就是Web的瀏覽器運用socket這個文件向其服務器而提出各種請求。應答過程就是運用HTTP協議把在請求過程中所提出來的請求傳輸到Web的服務器,進而實施任務處理,然後運用HTTP協議把任務處理的結果傳輸到Web的瀏覽器,同時在Web的瀏覽器上面展示上述所請求之界面。關閉連接就是當上一個步驟–應答過程完成以後,Web服務器和其瀏覽器之間斷開連接之過程。Web服務器上述4個步驟環環相扣、緊密相聯,邏輯性比較強,可以支持多個進程、多個線程以及多個進程與多個線程相混合的技術。

13、冪等性

冪等操作的特點是人一次或者多次執行產生的影響均與一次執行的影響相同。
冪等函數和冪等方法實質使用了相同的參數重複執行。
在很多場景中,我們可以使用分佈式事務、分佈式鎖等來保證一個方法在同一時間內只能被同一個線程執行,從而保證他的冪等性。

分佈式鎖通常有以下幾種實現方案:
基於數據庫實現分佈式鎖
基於緩存(redis)實現分佈式鎖
給予zookeeper實現分佈式鎖

14 RPC(遠程過程調用)

遠程過程調用
註冊中心中任意一臺機器宕機之後,可以切換到另一臺主機上。如果所有的主機都宕機了,還可以依賴本地緩存進行通信

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章