Java內存模型:java
Java虛擬機規範中將Java運行時數據分爲六種。web
1.程序計數器:是一個數據結構,用於保存當前正常執行的程序的內存地址。Java虛擬機的多線程就是經過線程輪流切換並分配處理器時間來實現的,爲了線程切換後能恢復到正確的位置,每條線程都須要一個獨立的程序計數器,互不影響,該區域爲「線程私有」。算法
2.Java虛擬機棧:線程私有的,與線程生命週期相同,用於存儲局部變量表,操做棧,方法返回值。局部變量表放着基本數據類型,還有對象的引用。數組
3.本地方法棧:跟虛擬機棧很像,不過它是爲虛擬機使用到的Native方法服務。緩存
4.Java堆:全部線程共享的一塊內存區域,對象實例幾乎都在這分配內存。安全
5.方法區:各個線程共享的區域,儲存虛擬機加載的類信息,常量,靜態變量,編譯後的代碼。服務器
6.運行時常量池:表明運行時每一個class文件中的常量表。包括幾種常量:編譯時的數字常量、方法或者域的引用。數據結構
類加載器工做機制:
1.裝載:將Java二進制代碼導入jvm中,生成Class文件。
2.鏈接:a)校驗:檢查載入Class文件數據的正確性 b)準備:給類的靜態變量分配存儲空間 c)解析:將符號引用轉成直接引用
3:初始化:對類的靜態變量,靜態方法和靜態代碼塊執行初始化工做。多線程
雙親委派模型:類加載器收到類加載請求,首先將請求委派給父類加載器完成
用戶自定義加載器->應用程序加載器->擴展類加載器->啓動類加載器。併發
java代理機制
代理的共有優勢:業務類只須要關注業務邏輯自己,保證了業務類的重用性。
Java靜態代理:
代理對象和目標對象實現了相同的接口,目標對象做爲代理對象的一個屬性,具體接口實現中,代理對象能夠在調用目標對象相應方法先後加上其餘業務處理邏輯。
缺點:一個代理類只能代理一個業務類。若是業務類增長方法時,相應的代理類也要增長方法。
Java動態代理:
Java動態代理是寫一個類實現InvocationHandler接口,重寫Invoke方法,在Invoke方法能夠進行加強處理的邏輯的編寫,這個公共代理類在運行的時候才能明確本身要代理的對象,同時能夠實現該被代理類的方法的實現,而後在實現類方法的時候能夠進行加強處理。
實際上:代理對象的方法 = 加強處理 + 被代理對象的方法
JDK和CGLIB生成動態代理類的區別:
JDK動態代理只能針對實現了接口的類生成代理(實例化一個類)。此時代理對象和目標對象實現了相同的接口,目標對象做爲代理對象的一個屬性,具體接口實現中,能夠在調用目標對象相應方法先後加上其餘業務處理邏輯
CGLIB是針對類實現代理,主要是對指定的類生成一個子類(沒有實例化一個類),覆蓋其中的方法 。
Spring AOP應用場景
性能檢測,訪問控制,日誌管理,事務等。
默認的策略是若是目標類實現接口,則使用JDK動態代理技術,若是目標對象沒有實現接口,則默認會採用CGLIB代理
Java GC
在何時:
1.新生代有一個Eden區和兩個survivor區,首先將對象放入Eden區,若是空間不足就向其中的一個survivor區上放,若是仍然放不下就會引起一次發生在新生代的minor GC,將存活的對象放入另外一個survivor區中,而後清空Eden和以前的那個survivor區的內存。在某次GC過程當中,若是發現仍然又放不下的對象,就將這些對象放入老年代內存裏去。
2.大對象以及長期存活的對象直接進入老年區。
3.當每次執行minor GC的時候應該對要晉升到老年代的對象進行分析,若是這些立刻要到老年區的老年對象的大小超過了老年區的剩餘大小,那麼執行一次Full GC以儘量地得到老年區的空間。
對什麼東西:從GC Roots搜索不到,並且通過一次標記清理以後仍沒有復活的對象。
作什麼:
新生代:複製清理;
老年代:標記-清除和標記-壓縮算法;
永久代:存放Java中的類和加載類的類加載器自己。
GC Roots都有哪些:
1. 虛擬機棧中的引用的對象
2. 方法區中靜態屬性引用的對象,常量引用的對象
3. 本地方法棧中JNI(即通常說的Native方法)引用的對象。
ThreadLocal(線程變量副本)
Synchronized實現內存共享,ThreadLocal爲每一個線程維護一個本地變量。
採用空間換時間,它用於線程間的數據隔離,爲每個使用該變量的線程提供一個副本,每一個線程均可以獨立地改變本身的副本,而不會和其餘線程的副本衝突。
ThreadLocal類中維護一個Map,用於存儲每個線程的變量副本,Map中元素的鍵爲線程對象,而值爲對應線程的變量副本。
ThreadLocal在Spring中發揮着巨大的做用,在管理Request做用域中的Bean、事務管理、任務調度、AOP等模塊都出現了它的身影。
Spring中絕大部分Bean均可以聲明成Singleton做用域,採用ThreadLocal進行封裝,所以有狀態的Bean就可以以singleton的方式在多線程中正常工做了。
Synchronized 與Lock都是可重入鎖,同一個線程再次進入同步代碼的時候.可使用本身已經獲取到的鎖。
Synchronized是悲觀鎖機制,獨佔鎖。而Locks.ReentrantLock是,每次不加鎖而是假設沒有衝突而去完成某項操做,若是由於衝突失敗就重試,直到成功爲止。
ReentrantLock適用場景
Volatile和Synchronized四個不一樣點:
1 粒度不一樣,前者針對變量 ,後者鎖對象和類
2 syn阻塞,volatile線程不阻塞
3 syn保證三大特性,volatile不保證原子性
4 syn編譯器優化,volatile不優化
volatile具有兩種特性:
1. 保證此變量對全部線程的可見性,指一條線程修改了這個變量的值,新值對於其餘線程來講是可見的,但並非多線程安全的。
2. 禁止指令重排序優化。
Volatile如何保證內存可見性:
1.當寫一個volatile變量時,JMM會把該線程對應的本地內存中的共享變量刷新到主內存。
2.當讀一個volatile變量時,JMM會把該線程對應的本地內存置爲無效。線程接下來將從主內存中讀取共享變量。
同步:就是一個任務的完成須要依賴另一個任務,只有等待被依賴的任務完成後,依賴任務才能完成。
異步:不須要等待被依賴的任務完成,只是通知被依賴的任務要完成什麼工做,只要本身任務完成了就算完成了,被依賴的任務是否完成會通知回來。(異步的特色就是通知)。
打電話和發短信來比喻同步和異步操做。
阻塞:CPU停下來等一個慢的操做完成之後,纔會接着完成其餘的工做。
非阻塞:非阻塞就是在這個慢的執行時,CPU去作其餘工做,等這個慢的完成後,CPU纔會接着完成後續的操做。
非阻塞會形成線程切換增長,增長CPU的使用時間能不能補償系統的切換成本須要考慮。
wait()和sleep()的區別
sleep來自Thread類,和wait來自Object類
調用sleep()方法的過程當中,線程不會釋放對象鎖。而調用 wait 方法線程會釋放對象鎖
sleep睡眠後不出讓系統資源,wait讓出系統資源其餘線程能夠佔用CPU
sleep(milliseconds)須要指定一個睡眠時間,時間一到會自動喚醒
CAS(Compare And Swap) 無鎖算法:
CAS是樂觀鎖技術,當多個線程嘗試使用CAS同時更新同一個變量時,只有其中一個線程能更新變量的值,而其它線程都失敗,失敗的線程並不會被掛起,而是被告知此次競爭中失敗,並能夠再次嘗試。CAS有3個操做數,內存值V,舊的預期值A,要修改的新值B。當且僅當預期值A和內存值V相同時,將內存值V修改成B,不然什麼都不作。
SpringMVC運行原理
1. 客戶端請求提交到DispatcherServlet
2. 由DispatcherServlet控制器查詢HandlerMapping,找到並分發到指定的Controller中。
4. Controller調用業務邏輯處理後,返回ModelAndView
5. DispatcherServlet查詢一個或多個ViewResoler視圖解析器,找到ModelAndView指定的視圖
6. 視圖負責將結果顯示到客戶端
Spring IOC (控制反轉,依賴注入)
Spring支持三種依賴注入方式,分別是屬性(Setter方法)注入,構造注入和接口注入。
在Spring中,那些組成應用的主體及由Spring IOC容器所管理的對象被稱之爲Bean。
Spring的IOC容器經過反射的機制實例化Bean並創建Bean之間的依賴關係。
簡單地講,Bean就是由Spring IOC容器初始化、裝配及被管理的對象。
獲取Bean對象的過程,首先經過Resource加載配置文件並啓動IOC容器,而後經過getBean方法獲取bean對象,就能夠調用他的方法。
Spring Bean的做用域:
Singleton:Spring IOC容器中只有一個共享的Bean實例,通常都是Singleton做用域。
Prototype:每個請求,會產生一個新的Bean實例。
Request:每一次http請求會產生一個新的Bean實例。
servlet和Filter的區別:
整的流程是:Filter對用戶請求進行預處理,接着將請求交給Servlet進行處理並生成響應,最後Filter再對服務器響應進行後處理。
Filter有以下幾個用處:
Filter能夠進行對特定的url請求和相應作預處理和後處理。
在HttpServletRequest到達Servlet以前,攔截客戶的HttpServletRequest。
根據須要檢查HttpServletRequest,也能夠修改HttpServletRequest頭和數據。
在HttpServletResponse到達客戶端以前,攔截HttpServletResponse。
根據須要檢查HttpServletResponse,也能夠修改HttpServletResponse頭和數據。
實際上Filter和Servlet極其類似,區別只是Filter不能直接對用戶生成響應。實際上Filter裏doFilter()方法裏的代碼就是從多個Servlet的service()方法裏抽取的通用代碼,經過使用Filter能夠實現更好的複用。
Filter和Servlet的生命週期:
1.Filter在web服務器啓動時初始化
2.若是某個Servlet配置了 1 ,該Servlet也是在Tomcat(Servlet容器)啓動時初始化。
3.若是Servlet沒有配置1 ,該Servlet不會在Tomcat啓動時初始化,而是在請求到來時初始化。
4.每次請求, Request都會被初始化,響應請求後,請求被銷燬。
5.Servlet初始化後,將不會隨着請求的結束而註銷。
6.關閉Tomcat時,Servlet、Filter依次被註銷。
HashMap與HashTable的區別。
一、HashMap是非線程安全的,HashTable是線程安全的。
二、HashMap的鍵和值都容許有null值存在,而HashTable則不行。
三、由於線程安全的問題,HashMap效率比HashTable的要高。
HashMap的實現機制:
1. 維護一個每一個元素是一個鏈表的數組,並且鏈表中的每一個節點是一個Entry[]鍵值對的數據結構。
2. 實現了數組+鏈表的特性,查找快,插入刪除也快。
3. 對於每一個key,他對應的數組索引下標是 int i = hash(key.hashcode)&(len-1);
4. 每一個新加入的節點放在鏈表首,而後該新加入的節點指向原鏈表首
HashMap,ConcurrentHashMap與LinkedHashMap的區別
ConcurrentHashMap應用場景
1:ConcurrentHashMap的應用場景是高併發,可是並不能保證線程安全,而同步的HashMap和HashMap的是鎖住整個容器,而加鎖以後ConcurrentHashMap不須要鎖住整個容器,只須要鎖住對應的Segment就行了,因此能夠保證高併發同步訪問,提高了效率。
2:能夠多線程寫。
ConcurrentHashMap把HashMap分紅若干個Segmenet
1.get時,不加鎖,先定位到segment而後在找到頭結點進行讀取操做。而value是volatile變量,因此能夠保證在競爭條件時保證讀取最新的值,若是讀到的value是null,則可能正在修改,那麼就調用ReadValueUnderLock函數,加鎖保證讀到的數據是正確的。
2.Put時會加鎖,一概添加到hash鏈的頭部。
3.Remove時也會加鎖,因爲next是final類型不可改變,因此必須把刪除的節點以前的節點都複製一遍。
4.ConcurrentHashMap容許多個修改操做併發進行,其關鍵在於使用了鎖分離技術。它使用了多個鎖來控制對Hash表的不一樣Segment進行的修改。
ConcurrentHashMap的應用場景是高併發,可是並不能保證線程安全,而同步的HashMap和HashTable的是鎖住整個容器,而加鎖以後ConcurrentHashMap不須要鎖住整個容器,只須要鎖住對應的segment就行了,因此能夠保證高併發同步訪問,提高了效率。
ConcurrentHashMap可以保證每一次調用都是原子操做,可是並不保證屢次調用之間也是原子操做。
ThreadPoolExecutor 的內部工做原理
有了以上定義好的數據,下面來看看內部是如何實現的 。 Doug Lea 的整個思路總結起來就是 5 句話:
1. 若是當前池大小 poolSize 小於 corePoolSize ,則建立新線程執行任務。
2. 若是當前池大小 poolSize 大於 corePoolSize ,且等待隊列未滿,則進入等待隊列
3. 若是當前池大小 poolSize 大於 corePoolSize 且小於 maximumPoolSize ,且等待隊列已滿,則建立新線程執行任務。
4. 若是當前池大小 poolSize 大於 corePoolSize 且大於 maximumPoolSize ,且等待隊列已滿,則調用拒絕策略來處理該任務。
5. 線程池裏的每一個線程執行完任務後不會馬上退出,而是會去檢查下等待隊列裏是否還有線程任務須要執行,若是在 keepAliveTime 裏等不到新的任務了,那麼線程就會退出。
Executor包結構
CopyOnWriteArrayList : 寫時加鎖,當添加一個元素的時候,將原來的容器進行copy,複製出一個新的容器,而後在新的容器裏面寫,寫完以後再將原容器的引用指向新的容器,而讀的時候是讀舊容器的數據,因此能夠進行併發的讀,但這是一種弱一致性的策略。 使用場景:CopyOnWriteArrayList適合使用在讀操做遠遠大於寫操做的場景裏,好比緩存。