1.線程安全定義
當多個線程訪問某個類時衬廷,不管運行時環(huán)境采用何種調(diào)度方式或者這些線程將如何交替執(zhí)行蝶怔,并且在調(diào)用代碼中不需要任何額外的同步或協(xié)同,這個類都能表現(xiàn)出正確的行為,那么這個類就是線程安全的佛南。
2.Spring全家桶基本概念
Spring
Spring是一個開源容器框架,可以接管web層嵌言,業(yè)務(wù)層嗅回,dao層,持久層的組件呀页,并且可以配置各種bean,和維護bean與bean之間的關(guān)系妈拌。其核心就是控制反轉(zhuǎn)(IOC),和面向切面(AOP),簡單的說就是一個分層的輕量級開源框架。
為依賴注入、事務(wù)管理尘分、WEB應(yīng)用猜惋、數(shù)據(jù)訪問等提供了核心的支持
SpringMVC
Spring MVC屬于SpringFrameWork的后續(xù)產(chǎn)品,已經(jīng)融合在Spring Web Flow里面培愁。
SpringMVC是一種web層mvc框架著摔,用于替代servlet(處理|響應(yīng)請求,獲取表單參數(shù)定续,表單校驗等谍咆。SpringMVC是一個MVC的開源框架,SpringMVC=struts2+spring私股,springMVC就相當于是Struts2加上Spring的整合摹察。
Springboot
Springboot是一個微服務(wù)框架,延續(xù)了spring框架的核心思想IOC和AOP倡鲸,簡化了應(yīng)用的開發(fā)和部署供嚎。
Spring Boot是為了簡化Spring應(yīng)用的創(chuàng)建、運行峭状、調(diào)試克滴、部署等而出現(xiàn)的,使用它可以做到專注于Spring應(yīng)用的開發(fā)优床,而無需過多關(guān)注XML的配置劝赔。提供了一堆依賴打包,并已經(jīng)按照使用習(xí)慣解決了依賴問題--->約定大于配置胆敞。
spring springboot開發(fā)區(qū)別
spring framework的Java Web開發(fā)模式:
- pom文件中引入相關(guān)jar包着帽,包括spring、springmvc竿秆、redis启摄、mybaits、log4j幽钢、mysql-connector-java 等等相關(guān)jar ...
- 配置web.xml,Listener配置傅是、Filter配置匪燕、Servlet配置、log4j配置喧笔、error配置 ...
- 配置數(shù)據(jù)庫連接帽驯、配置spring事務(wù)
- 配置視圖解析器
- 開啟注解、自動掃描功能
- 配置完成后部署tomcat书闸、啟動調(diào)試
springboot的Java Web開發(fā)模式:
- pom.xml配置需要引用的相關(guān)jar包
- yml中配置數(shù)據(jù)源尼变,服務(wù)器,持久層
- springboot啟動類加相關(guān)注解
SpringClod
Spring Cloud事實上是一整套基于Spring Boot的微服務(wù)解決方案。它為開發(fā)者提供了很多工具嫌术,用于快速構(gòu)建分布式系統(tǒng)的一些通用模式哀澈,例如:配置管理、注冊中心度气、服務(wù)發(fā)現(xiàn)割按、限流、網(wǎng)關(guān)磷籍、鏈路追蹤等适荣。
3.如果讓你自己實現(xiàn)一個springboot怎樣實現(xiàn)
ConfigurationProperties和AutoConfiguration。因為Spring Boot堅信“約定大于配置”這一理念院领,所以我們使用ConfigurationProperties來保存我們的配置弛矛,并且這些配置都可以有一個默認值,即在我們沒有主動覆寫原始配置的情況下比然,默認值就會生效丈氓,這在很多情況下是非常有用的。除此之外谈秫,starter的ConfigurationProperties還使得所有的配置屬性被聚集到一個文件中(一般在resources目錄下的application.properties)扒寄,這樣我們就告別了Spring項目中XML地獄。
創(chuàng)建自己的springboot starter
如果你想要自己創(chuàng)建一個starter拟烫,那么基本上包含以下幾步
- 創(chuàng)建一個starter項目该编,關(guān)于項目的命名你可以參考這里
- 創(chuàng)建一個ConfigurationProperties用于保存你的配置信息(如果你的項目不使用配置信息則可以跳過這一步,不過這種情況非常少見)
- 創(chuàng)建一個AutoConfiguration硕淑,引用定義好的配置信息课竣;在AutoConfiguration中實現(xiàn)所有starter應(yīng)該完成的操作,并且把這個類加入spring.factories配置文件中進行聲明
- 打包項目置媳,之后在一個SpringBoot項目中引入該項目依賴于樟,然后就可以使用該starter了
4.JVM調(diào)優(yōu)工具使用經(jīng)驗
jstat查看內(nèi)存回收概況,實時查看各個分區(qū)的分配回收情況拇囊,jmap查看內(nèi)存棧迂曲,查看內(nèi)存中對象占用大小,jstack查看線程棧寥袭,死鎖路捧,性能瓶頸,某個線程使用cpu過高導(dǎo)致服務(wù)整體慢等都可以通過在這些命令輔助Linux命令看出來传黄。
5.volatile關(guān)鍵字
volatile的特性
可見性:對一個volatile變量的讀杰扫,總能獲取其他任意線程對該變量最后的寫入。
有序性:JMM會限制volatile變量相關(guān)的編譯器重排序和處理器重排序膘掰。
可見性的內(nèi)存語義
volatile寫的內(nèi)存語義:當寫入一個volatile變量的時候章姓,JMM將線程工作內(nèi)存中的該變量的值刷新到主內(nèi)存。
volatile讀的內(nèi)存語義:當讀取一個volatile變量的時候,JMM首先將該線程工作內(nèi)存中的這個變量設(shè)置為無效凡伊,迫使該線程重新從主內(nèi)存獲取最新的有效值零渐。
編譯器對于有序性重排序的限制
- volatile讀寫不能被更改順序
- 普通讀寫之前的volatile讀不能被重排序到后面
- 普通讀寫之后的volatile寫不能被重排序到前面
內(nèi)存屏障實現(xiàn)有序性
LoadLoad屏障
對于這樣的語句Load1; LoadLoad; Load2,在Load2及后續(xù)讀取操作要讀取的數(shù)據(jù)被訪問前窗声,保證Load1要讀取的數(shù)據(jù)被讀取完畢相恃。
StoreStore屏障
對于這樣的語句Store1; StoreStore; Store2,在Store2及后續(xù)寫入操作執(zhí)行前笨觅,保證Store1的寫入操作對其它處理器可見拦耐。
LoadStore屏障
對于這樣的語句Load1; LoadStore; Store2,在Store2及后續(xù)寫入操作被刷出前见剩,保證Load1要讀取的數(shù)據(jù)被讀取完畢杀糯。
StoreLoad屏障
對于這樣的語句Store1; StoreLoad; Load2,在Load2及后續(xù)所有讀取操作執(zhí)行前苍苞,保證Store1的寫入對所有處理器可見固翰。它的開銷是四種屏障中最大的。 在大多數(shù)處理器的實現(xiàn)中羹呵,這個屏障是個萬能屏障骂际,兼具其它三種內(nèi)存屏障的功能。
JMM內(nèi)存屏障的插入策略
volatile寫操作前面插入一個StoreStore屏障
對比StoreStore屏障的定義冈欢,這里的volatile寫是那個Store2,該屏障保證在volatile寫執(zhí)行之前歉铝,Store1的寫入操作對其他處理器可見,那么可以得出凑耻,該屏障不僅保證了Store1已經(jīng)執(zhí)行完畢(有序性)太示,也保證了可見性。
每個volatile寫操作的后面插入一個StoreLoad屏障
對比StoreLoad屏障的定義香浩,這里的volatile寫是那個Store1,該屏障也保證了有序性和可見性类缤。其他都是類似的。
每個volatile讀操作后面插入一個LoadLoad屏障邻吭。
每個volatile讀操作后面插入一個LoadStore屏障餐弱。
6.cas
cas用來保證操作的原子性操作
Unsafe類中的compareAndSwapInt,是一個native方法囱晴,該方法的實現(xiàn)位于unsafe.cpp中
先想辦法拿到內(nèi)存地址岸裙,再通過Atomic::cmpxchg(x, addr, e)實現(xiàn)比較交換。e是原內(nèi)存值速缆,x為新值。這個函數(shù)在WindowsX86下實現(xiàn)如下:
inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) {
int mp = os::isMP(); #判斷是否是多處理器
_asm {
mov edx, dest #變量內(nèi)存位置放edx
mov ecx, exchange_value #要更新的值放ecx
mov eax, compare_value #原內(nèi)存值放eax
LOCK_IF_MP(mp) #決定是否Lock
#這句是真正的CAS操作
cmpxchg dword ptr [edx], ecx
# dword ptr 將 [edx] 強制類型轉(zhuǎn)換成雙字
# cmpxchg 將 eax 里 內(nèi)存原值 與(轉(zhuǎn)換后的)對象值 比較
# 如果相等恩闻,就是沒別的線程在改變這個對象艺糜,那么這個線程就可以改了,將ecx值更新到這個對象。
}
}
如果是多處理器破停,LOCK_IF_MP(mp)為cmpxchg指令添加lock前綴翅楼。反之,就省略lock前綴真慢。(單處理器會不需要lock前綴提供的內(nèi)存屏障效果)
7.單例模式
- 懶漢餓漢
- 枚舉實現(xiàn)
- 雙重校驗
雙重校驗使用volatile關(guān)鍵字的原因
假如有兩個并發(fā)線程a毅臊、b,a線程主動調(diào)用了靜態(tài)方法getInstance()黑界,這時開始加載和初始化該類的靜態(tài)變量管嬉,b線程調(diào)用getInstance()并等待獲得同步鎖,當a線程初始化對象過程中朗鸠,到了第二階段即連接階段的準備步驟時蚯撩,靜態(tài)變量doubleKey 被賦予了一個默認值,但是這時還沒有進行初始化烛占,這時當a線程釋放鎖后胎挎,b線程判斷doubleKey != null忆家,則直接返回了一個沒有初始化的doubleKey 對象犹菇,問題就出現(xiàn)在這里了,b線程拿到的是一個被賦予了默認值但是未初始化的對象芽卿,剛剛可以通過鎖的檢索揭芍!
8.隔離級別
四種隔離級別,舉例說明
mysql的隔離級別實現(xiàn)
MySQL默認使用rr的隔離級別
RR使用gap lock來解決幻讀問題
MySQL RR/RC區(qū)別
簡單來說蹬竖,semi-consistent read是read committed與consistent read兩者的結(jié)合沼沈。一個update語句,如果讀到一行已經(jīng)加鎖的記錄币厕,此時InnoDB返回記錄最近提交的版本列另,由MySQL上層判斷此版本是否滿足 update的where條件。若滿足(需要更新)旦装,則MySQL會重新發(fā)起一次讀操作页衙,此時會讀取行的最新版本(并加鎖)。semi-consistent read只會發(fā)生在read committed隔離級別下阴绢,或者是參數(shù)innodb_locks_unsafe_for_binlog被設(shè)置為true(該參數(shù)即將被廢棄)店乐。
對比RR隔離級別,update語句會使用當前讀呻袭,如果一行被鎖定了眨八,那么此時會被阻塞,發(fā)生鎖等待左电。而不會讀取最新的提交版本廉侧,然后來判斷是否符合where條件页响。
半一致性讀的優(yōu)點:
減少了update語句時行鎖的沖突;對于不滿足update更新條件的記錄段誊,可以提前放鎖闰蚕,減少并發(fā)沖突的概率。
9.什么時候OOM什么時候stackoverflow
OOM的情況
- 給應(yīng)用程序分配的內(nèi)存不夠,只能通過增大內(nèi)存來解決.
- 內(nèi)存泄漏.有一部分內(nèi)存"無用"了,但是因為編碼問題導(dǎo)致的沒有被垃圾回收掉,產(chǎn)生了泄漏,最終導(dǎo)致了內(nèi)存溢出(OOM).
stackoverflow的情況
- 無限的遞歸,相當于你的參數(shù)無限多,那么棧放不下.
- 局部變量太大了,正常分配的椓幔空間(1M)不夠用.