負(fù)載均衡
負(fù)載均衡,英文名稱為Load Balance,其意思就是分?jǐn)偟蕉鄠€操作單元上進行執(zhí)行,例如Web服務(wù)器、FTP服務(wù)器、企業(yè)關(guān)鍵應(yīng)用服務(wù)器和其它關(guān)鍵任務(wù)服務(wù)器等,從而共同完成工作任務(wù)。
棧、隊列中“先進先出”,“后進先出”的含義
舉例子說明.
棧的概念是彈壓,就像子彈殼裝彈,一粒一粒壓進去,但是打出來的時候是從上面打出來的,最先壓進去的最后彈出來,如果進去順序是123,打出來順序是321,這就是后進先出
隊列的概念就是我們平時排隊,按次序來,你排在第1個,那你就第一個輪到,就是先進先出,先到先來。
JAVA中的NATIVE方法
本地方法,可以編譯成C語言,native方法在JVM中運行時數(shù)據(jù)區(qū)也和其它方法不一樣,它有專門的本地方法棧。native方法主要用于加載文件和動態(tài)鏈接庫,由于Java語言無法訪問操作系統(tǒng)底層信息(比如:底層硬件設(shè)備等),這時候就需要借助C語言來完成了。被native修飾的方法可以被C語言重寫。
如何設(shè)置JAVA虛擬機JVM啟動內(nèi)存參數(shù)
1 TOMCAT
2 ECLIPSE
3 JAVA直接編譯
4 WEBLOGIC
各服務(wù)器容器都可以找到相關(guān)方法進行設(shè)置。具體設(shè)置,請參考相關(guān)文檔。
JAVA?虛擬機
Java虛擬機是用于支撐JAVA在不同硬件環(huán)境下運行java代碼。
JVM是Java Virtual Machine(Java虛擬機)的縮寫,是一個虛構(gòu)出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現(xiàn)的。Java虛擬機主要由字節(jié)碼指令集、寄存器、棧、垃圾回收堆和存儲方法域等構(gòu)成。 JVM屏蔽了與具體操作系統(tǒng)平臺相關(guān)的信息,使Java程序只需生成在Java虛擬機上運行的目標(biāo)代碼(字節(jié)碼),就可以在多種平臺上不加修改地運行。JVM在執(zhí)行字節(jié)碼時,實際上最終還是把字節(jié)碼解釋成具體平臺上的機器指令執(zhí)行。
JVM聲明周期
JVM伴隨Java程序的開始而開始,程序的結(jié)束而停止。一個Java程序會開啟一個JVM進程,一臺計算機上可以運行多個程序,也就可以運行多個JVM進程。
JVM將線程分為兩種:守護線程和普通線程。守護線程是JVM自己使用的線程,比如垃圾回收(GC)就是一個守護線程。普通線程一般是Java程序的線程,只要JVM中有普通線程在執(zhí)行,那么JVM就不會停止。
JVM內(nèi)存模型組成
JVM內(nèi)存模型主要由堆內(nèi)存、方法區(qū)、程序計數(shù)器、虛擬機棧和本地方法棧組成,其組成的結(jié)構(gòu)如下圖所示。
其中,堆和方法區(qū)是所有線程共有的,而虛擬機棧,本地方法棧和程序計數(shù)器則是線程私有的。
堆內(nèi)存
堆內(nèi)存是所有線程共有的,可以分為兩個部分:年輕代和老年代。下圖中的Perm代表的是永久代,但是注意永久代并不屬于堆內(nèi)存中的一部分,同時jdk1.8之后永久代也將被移除。
堆內(nèi)存是我們在生產(chǎn)環(huán)境中進行內(nèi)存性能調(diào)優(yōu)中的一個重要的內(nèi)容,而內(nèi)存回收的一些機制和算法也是常見的考點,大家可以訪問下面的鏈接:Java性能優(yōu)化之JVM GC
方法區(qū)
方法區(qū)與Java堆一樣,是各個線程共享的區(qū)域,它用于存儲已被虛擬機加載的類信息,常量,靜態(tài)變量,即時編譯(JIT)后的代碼等數(shù)據(jù)。
由于程序中所有的線程共享一個方法區(qū),所以訪問方法區(qū)的信息必須確保線程是安全的。如果有兩個線程同時去加載一個類,那么只能有一個線程被允許去加載這個類,另一個必須等待。
在程序運行時,方法區(qū)的大小是可以改變的,程序在運行時可以擴展。同時,方法區(qū)里面的對象也可以被垃圾回收,但條件非常嚴(yán)苛,必須在該類沒有任何引用的情況下才能被GC回收。
程序計數(shù)器
在JVM的概念模型里,字節(jié)碼解釋器工作時就是通過改變這個計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令。分支、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個計數(shù)器來完成。
JVM的多線程是通過線程輪流切換并分配處理器執(zhí)行時間的方式來實現(xiàn)的,為了各條線程之間的切換后計數(shù)器能恢復(fù)到正確的執(zhí)行位置,所以每條線程都會有一個獨立的程序計數(shù)器。
當(dāng)線程正在執(zhí)行一個Java方法,程序計數(shù)器記錄的是正在執(zhí)行的JVM字節(jié)碼指令的地址;如果正在執(zhí)行的是一個Natvie(本地方法),那么這個計數(shù)器的值則為空(Underfined)。
程序計數(shù)器占用的內(nèi)存空間很少,也是唯一一個在JVM規(guī)范中沒有規(guī)定任何OutOfMemoryError(內(nèi)存不足錯誤)的區(qū)域。
Java虛擬機棧
與程序計數(shù)器一樣,Java虛擬機棧也是線程私有的,用通俗的話將它就是我們常常聽說到堆棧中的那個“棧內(nèi)存”。虛擬機棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個方法在執(zhí)行的同時都會創(chuàng)建一個棧幀(Stack Frame)用于存儲局部變量表(局部變量表需要的內(nèi)存在編譯期間就確定了所以在方法運行期間不會改變大小),操作數(shù)棧,動態(tài)鏈接,方法出口等信息。每一個方法從調(diào)用至出棧的過程,就對應(yīng)著棧幀在虛擬機中從入棧到出棧的過程。
本地方法棧
棧作為一種線性的管道結(jié)構(gòu),遵循先進后出的原則。主要用于存儲本地方法的局部變量表,本地方法的操作數(shù)棧等信息。當(dāng)棧內(nèi)的數(shù)據(jù)在超出其作用域后,會被自動釋放掉。
本地方法棧是在程序調(diào)用或JVM調(diào)用本地方法接口(Native)時候啟用。
Spring中BEAN的作用域singleton和prototype的不同
Spring中的BEAN默認(rèn)作用域為singleton,當(dāng)我們需要獲得bean時,容器將按照BEAN的生命周期過程,實例化相應(yīng)的BEAN,并且放入Spring IOC容的緩存池中,并將BEAN的引用返回給調(diào)用者,由Spring對這些BEAN進行后續(xù)的生命管理。下次如果再使用到這個BEAN,可以直接從緩存中獲得。
如果Bean的作用范圍是scope=‘prototype’,當(dāng)我們需要Bean時,容器在實例化Bean以后,會將Bean返回給調(diào)用者,調(diào)用者負(fù)責(zé)Bean后續(xù)生命的管理,Spring不再負(fù)責(zé)管理這個Bean的生命周。且第二次用getBean()時,生命周期的方法會繼續(xù)調(diào)用,因為prototype范圍的Bean每次都返回新的實例。
ApplicationContext和BeanFactory的區(qū)別?
初始化的區(qū)別:ApplicationContext在初始化應(yīng)用上下文時,就實例化所有單實例的Bean.而BeanFactory在初始化容器時,并未實例化Bean,直到第一次訪問某個Bean時才實例化目標(biāo)Bean.因此ApplicationContext的初始化時間會比BeanFactory的時間稍微長一點。
其次,還有一個最大不同,ApplicationContext會利用反射機制,自動識別配置文件中定義的BeanPostProcessor,InstantiationAwareBeanPostProcessor和BeanFactoryPostProcessor,并自動將他們注冊到應(yīng)用上下文。但是BeanFactory需要在代碼中手工調(diào)用addBeanPostProcessor()進行注冊。
Java中如何理解overload , override
overload實現(xiàn)多態(tài)性,同一個類里面,同樣的方法,可以包含不同的參數(shù)。
override,子類繼承父類時,可以定義同名同參數(shù)的方法,這樣當(dāng)子類調(diào)用這一方法時,自動調(diào)用子類的方法,父類的方法可以通過super來調(diào)用。
ClassLoader類加載的工作機制
1.裝載:查找和導(dǎo)入Class文件
2.鏈接:執(zhí)行校驗,準(zhǔn)備和解析的步驟。校驗,檢查Class文件數(shù)據(jù)的正確性。準(zhǔn)備,將類的靜態(tài)變量分配存儲空間。解析,將符號引用轉(zhuǎn)成直接引用。
3.初始化:將類的靜態(tài)變量,,靜態(tài)代碼塊執(zhí)行初始化工作。
JVM運行時,產(chǎn)生三個類加載器:根加載器,ExtClassLoader(擴展類加載器),AppClassLoader(系統(tǒng)類加載器)。根加載由C++編寫,負(fù)責(zé)加載RE核心類庫。如JRE目錄下的rt.jar包。擴展類加載JRE的擴展目錄ext中的JAR包。系統(tǒng)加載負(fù)責(zé)裝載Classpath路徑下的JAR包。
三個加載器按照全盤負(fù)責(zé)委托機制加載,先通過父類進行類加載,如果加載不到,在通過子類加載。
符號引用和直接引用
符號引用以一組符號來描述所引用的目標(biāo),符號可以是任何形式的字面量,只要使用時能夠無歧義的定位到目標(biāo)即可。例如,在Class文件中它以CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等類型的常量出現(xiàn)。
? 直接引用可以是
(1)直接指向目標(biāo)的指針(比如,指向“類型”【Class對象】、類變量、類方法的直接引用可能是指向方法區(qū)的指針)
(2)相對偏移量(比如,指向?qū)嵗兞?、實例方法的直接引用都是偏移量?/p>
(3)一個能間接定位到目標(biāo)的句柄
直接引用是和虛擬機的布局相關(guān)的,同一個符號引用在不同的虛擬機實例上翻譯出來的直接引用一般不會相同。如果有了直接引用,那引用的目標(biāo)必定已經(jīng)被加載入內(nèi)存中了。
Java中的String,StringBuilder,StringBuffer三者的區(qū)別
首先說運行速度,或者說是執(zhí)行速度,在這方面運行速度快慢為:StringBuilder > StringBuffer > String
String最慢的原因:
? ? ?String采用連接運算符(+)效率低下,都是上述循環(huán)、大批量數(shù)據(jù)情況造成的,每做一次"+"就產(chǎn)生個StringBuilder對象,然后append后就扔掉。下次循環(huán)再到達時重新產(chǎn)生個StringBuilder對象,然后append字符串,如此循環(huán)直至結(jié)束。如果我們直接采用StringBuilder對象進行append的話,我們可以節(jié)省創(chuàng)建和銷毀對象的時間。如果只是簡單的字面量拼接或者很少的字符串拼接,性能都是差不多的。
String為字符串常量,而StringBuilder和StringBuffer均為字符串變量,即String對象一旦創(chuàng)建之后該對象是不可更改的,但后兩者的對象是變量,是可以更改的。
在線程安全上,StringBuilder是線程不安全的,而StringBuffer是線程安全的
如果一個StringBuffer對象在字符串緩沖區(qū)被多個線程使用時,StringBuffer中很多方法可以帶有synchronized關(guān)鍵字,所以可以保證線程是安全的,但StringBuilder的方法則沒有該關(guān)鍵字,所以不能保證線程安全,有可能會出現(xiàn)一些錯誤的操作。所以如果要進行的操作是多線程的,那么就要使用StringBuffer,但是在單線程的情況下,還是建議使用速度比較快的StringBuilder。
String:適用于少量的字符串操作的情況
StringBuilder:適用于單線程下在字符緩沖區(qū)進行大量操作的情況
StringBuffer:適用多線程下在字符緩沖區(qū)進行大量操作的情況
線程安全
線程安全是多線程編程時的計算機程序代碼中的一個概念。在擁有共享數(shù)據(jù)的多條線程并行執(zhí)行的程序中,線程安全的代碼會通過同步機制保證各個線程都可以正常且正確的執(zhí)行,不會出現(xiàn)數(shù)據(jù)污染等意外情況。簡單說,就是多個線程對一個數(shù)據(jù)或者對象進行內(nèi)容的修改時,不會出現(xiàn)數(shù)據(jù)沖突和不一致的問題。
HashMap,Hashtable,ConcurrentHashMap
HashMap中鍵值?允許為空?并且是非同步的
Hashtable中鍵值不允許為空?是同步的
繼承不同,但都實現(xiàn)了Map接口
? ? ? ? ? ? ? ? ? ? ? ? ? ? HashMap????????????????Hashtable
父類???????????????? ? AbstractMap??????????Dictiionary
是否同步??????????? 否??????????????????????????? 是
k,v可否null???? ? 是 ? ? ? ? ? ? ? ? ? ? ? ? ? ?否
現(xiàn)在都會用ConcurrentHashMap進行同步操作。ConcurrentHashMap僅僅鎖定map的某個部分,而Hashtable則會鎖定整個map。
volatile 關(guān)鍵字
Volatile原理
Java語言提供了一種稍弱的同步機制,即volatile變量,用來確保將變量的更新操作通知到其他線程。當(dāng)把變量聲明為volatile類型后,編譯器與運行時都會注意到這個變量是共享的,因此不會將該變量上的操作與其他內(nèi)存操作一起重排序。volatile變量不會被緩存在寄存器或者對其他處理器不可見的地方,因此在讀取volatile類型的變量時總會返回最新寫入的值。
在訪問volatile變量時不會執(zhí)行加鎖操作,因此也就不會使執(zhí)行線程阻塞,因此volatile變量是一種比sychronized關(guān)鍵字更輕量級的同步機制。

當(dāng)對非 volatile 變量進行讀寫的時候,每個線程先從內(nèi)存拷貝變量到CPU緩存中。如果計算機有多個CPU,每個線程可能在不同的CPU上被處理,這意味著每個線程可以拷貝到不同的 CPU cache 中。
而聲明變量是 volatile 的,JVM 保證了每次讀變量都從內(nèi)存中讀,跳過 CPU cache 這一步。
當(dāng)一個變量定義為 volatile 之后,將具備兩種特性:
1.保證此變量對所有的線程的可見性,這里的“可見性”,如本文開頭所述,當(dāng)一個線程修改了這個變量的值,volatile 保證了新值能立即同步到主內(nèi)存,以及每次使用前立即從主內(nèi)存刷新。但普通變量做不到這點,普通變量的值在線程間傳遞均需要通過主內(nèi)存(詳見:Java內(nèi)存模型)來完成。
2.禁止指令重排序優(yōu)化。有volatile修飾的變量,賦值后多執(zhí)行了一個“l(fā)oad addl $0x0, (%esp)”操作,這個操作相當(dāng)于一個內(nèi)存屏障(指令重排序時不能把后面的指令重排序到內(nèi)存屏障之前的位置),只有一個CPU訪問內(nèi)存時,并不需要內(nèi)存屏障;(什么是指令重排序:是指CPU采用了允許將多條指令不按程序規(guī)定的順序分開發(fā)送給各相應(yīng)電路單元處理)。
volatile 性能:
volatile 的讀性能消耗與普通變量幾乎相同,但是寫操作稍慢,因為它需要在本地代碼中插入許多內(nèi)存屏障指令來保證處理器不發(fā)生亂序執(zhí)行。
final 關(guān)鍵字
針對Java語言中的final關(guān)鍵字,想必都不陌生了。本來主要是來對final做關(guān)鍵字做一個總結(jié)。
final關(guān)鍵字用法
1 修飾類當(dāng)用final去修飾一個類的時候,表示這個類不能被繼承。注意:a. 被final修飾的類,final類中的成員變量可以根據(jù)自己的實際需要設(shè)計為fianl。b. final類中的成員方法都會被隱式的指定為final方法。說明:在自己設(shè)計一個類的時候,要想好這個類將來是否會被繼承,如果可以被繼承,則該類不能使用fianl修飾,在這里呢,一般來說工具類我們往往都會設(shè)計成為一個fianl類。在JDK中,被設(shè)計為final類的有String、System等。
2??修飾方法
被final修飾的方法不能被重寫。
注意:
a. 一個類的private方法會隱式的被指定為final方法。
b. 如果父類中有final修飾的方法,那么子類不能去重寫。
3??修飾成員變量
注意:
a. 必須要賦初始值,而且是只能初始化一次。
4?修飾成員變量
注意:
a. 必須初始化值。
b. 被fianl修飾的成員變量賦值,有兩種方式:1、直接賦值 2、全部在構(gòu)造方法中賦初值。
c. 如果修飾的成員變量是基本類型,則表示這個變量的值不能改變。
d. 如果修飾的成員變量是一個引用類型,則是說這個引用的地址的值不能修改,但是這個引用所指向的對象里面的內(nèi)容還是可以改變的。
樂觀鎖和悲觀鎖
悲觀鎖:總是假設(shè)最壞的情況,每次去拿數(shù)據(jù)的時候都認(rèn)為別人會修改,所以每次在拿數(shù)據(jù)的時候都會上鎖,這樣別人想拿這個數(shù)據(jù)就會阻塞直到它拿到鎖。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫里邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。再比如Java里面的同步原語synchronized關(guān)鍵字的實現(xiàn)也是悲觀鎖。
樂觀鎖:顧名思義,就是很樂觀,每次去拿數(shù)據(jù)的時候都認(rèn)為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數(shù)據(jù),可以使用版本號等機制。樂觀鎖適用于多讀的應(yīng)用類型,這樣可以提高吞吐量,像數(shù)據(jù)庫提供的類似于write_condition機制,其實都是提供的樂觀鎖。在Java中java.util.concurrent.atomic包下面的原子變量類就是使用了樂觀鎖的一種實現(xiàn)方式CAS實現(xiàn)的。
Compare And Swap(CAS)
CAS是一種有名的無鎖(lock-free)算法。也是一種現(xiàn)代 CPU 廣泛支持的CPU指令級的操作,只有一步原子操作,所以非??臁6褻AS避免了請求操作系統(tǒng)來裁定鎖的問題,不用麻煩操作系統(tǒng),直接在CPU內(nèi)部就搞定了。
CAS有三個操作參數(shù):
內(nèi)存位置V(它的值是我們想要去更新的)
預(yù)期原值A(chǔ)(上一次從內(nèi)存中讀取的值)
新值B(應(yīng)該寫入的新值)
CAS的操作過程:將內(nèi)存位置V的值與A比較(compare),如果相等,則說明沒有其它線程來修改過這個值,所以把內(nèi)存V的的值更新成B(swap),如果不相等,說明V上的值被修改過了,不更新,而是返回當(dāng)前V的值,再重新執(zhí)行一次任務(wù)再繼續(xù)這個過程。
所以,當(dāng)多個線程嘗試使用CAS同時更新同一個變量時,其中一個線程會成功更新變量的值,剩下的會失敗。失敗的線程可以重試或者什么也不做。
簡單來說,CAS 的含義是“我認(rèn)為原有的值應(yīng)該是什么,如果是,則將原有的值更新為新值,否則不做修改,并告訴我這個值現(xiàn)在是多少”。(這段描述引自《Java并發(fā)編程實踐》)
map迭代的四種方式
方式一:通過Map.keySet遍歷key和value
方式二:通過Map.entrySet遍歷key和value,推薦,尤其是容量大時.
方式三:通過Map.entrySet使用iterator遍歷key和value.
方式四:通過Map.values()遍歷所有的value,但不能遍歷key.
JVM調(diào)優(yōu)內(nèi)容太多,可以參考下面帖子
HASH算法
hash算法也稱散列算法,將不同長度的值輸出成固定長度的值,然后通過鍵值對的方式,存儲在散列表中,這樣查找相應(yīng)的值,就可以通過相應(yīng)的散列KEY來查找,而KEY存的就是對象的地址,就可以實現(xiàn)快速查找。理論上時間復(fù)雜度可以O(shè)(1)。
Java 對象序 列化的機制
Socket通信
SPRING IOC?和AOP