1.寫出synchronized的使用方式
synchronized的三種應(yīng)用方式
synchronized關(guān)鍵字最主要有以下3種應(yīng)用方式树瞭,下面分別介紹
修飾實例方法孝偎,作用于當(dāng)前實例加鎖衣盾,進(jìn)入同步代碼前要獲得當(dāng)前實例的鎖
修飾靜態(tài)方法,作用于當(dāng)前類對象加鎖果复,進(jìn)入同步代碼前要獲得當(dāng)前類對象的鎖
修飾代碼塊,指定加鎖對象迈窟,對給定對象加鎖车酣,進(jìn)入同步代碼庫前要獲得給定對象的鎖。
Java 虛擬機中的同步(Synchronization)基于進(jìn)入和退出管程(Monitor)對象實現(xiàn)破衔, 無論是顯式同步(有明確的 monitorenter 和 monitorexit 指令,即同步代碼塊)還是隱式同步都是如此晰筛。在 Java 語言中读第,同步用的最多的地方可能是被 synchronized 修飾的同步方法。
Java虛擬機對synchronized的優(yōu)化
鎖的狀態(tài)總共有四種吴汪,無鎖狀態(tài)漾橙、偏向鎖、輕量級鎖和重量級鎖淘捡。隨著鎖的競爭,鎖可以從偏向鎖升級到輕量級鎖踢京,再升級的重量級鎖瓣距,但是鎖的升級是單向的,也就是說只能從低到高升級逻杖,不會出現(xiàn)鎖的降級荸百,關(guān)于重量級鎖蓝翰,前面我們已詳細(xì)分析過,下面我們將介紹偏向鎖和輕量級鎖以及JVM的其他優(yōu)化手段爆雹,這里并不打算深入到每個鎖的實現(xiàn)和轉(zhuǎn)換過程更多地是闡述Java虛擬機所提供的每個鎖的核心優(yōu)化思想,畢竟涉及到具體過程比較繁瑣拒啰,如需了解詳細(xì)過程可以查閱《深入理解Java虛擬機原理》剩失。
偏向鎖是Java 6之后加入的新鎖拴孤,它是一種針對加鎖操作的優(yōu)化手段,經(jīng)過研究發(fā)現(xiàn)芒粹,在大多數(shù)情況下,鎖不僅不存在多線程競爭座云,而且總是由同一線程多次獲得朦拖,因此為了減少同一線程獲取鎖(會涉及到一些CAS操作,耗時)的代價而引入偏向鎖捍岳。偏向鎖的核心思想是作喘,如果一個線程獲得了鎖窖贤,那么鎖就進(jìn)入偏向模式,此時Mark Word 的結(jié)構(gòu)也變?yōu)槠蜴i結(jié)構(gòu)授嘀,當(dāng)這個線程再次請求鎖時,無需再做任何同步操作巷折,即獲取鎖的過程锻拘,這樣就省去了大量有關(guān)鎖申請的操作署拟,從而也就提供程序的性能。所以缨恒,對于沒有鎖競爭的場合岭佳,偏向鎖有很好的優(yōu)化效果,畢竟極有可能連續(xù)多次是同一個線程申請相同的鎖。但是對于鎖競爭比較激烈的場合衩辟,偏向鎖就失效了,因為這樣場合極有可能每次申請鎖的線程都是不相同的,因此這種場合下不應(yīng)該使用偏向鎖狈究,否則會得不償失,需要注意的是宁改,偏向鎖失敗后,并不會立即膨脹為重量級鎖谜喊,而是先升級為輕量級鎖鞋邑。下面我們接著了解輕量級鎖逾一。
倘若偏向鎖失敗箱玷,虛擬機并不會立即升級為重量級鎖壳坪,它還會嘗試使用一種稱為輕量級鎖的優(yōu)化手段(1.6之后加入的),此時Mark Word 的結(jié)構(gòu)也變?yōu)檩p量級鎖的結(jié)構(gòu)弥虐。輕量級鎖能夠提升程序性能的依據(jù)是“對絕大部分的鎖扩灯,在整個同步周期內(nèi)都不存在競爭”媚赖,注意這是經(jīng)驗數(shù)據(jù)霜瘪。需要了解的是,輕量級鎖所適應(yīng)的場景是線程交替執(zhí)行同步塊的場合惧磺,如果存在同一時間訪問同一鎖的場合,就會導(dǎo)致輕量級鎖膨脹為重量級鎖番捂。
自旋鎖
輕量級鎖失敗后魄梯,虛擬機為了避免線程真實地在操作系統(tǒng)層面掛起肝箱,還會進(jìn)行一項稱為自旋鎖的優(yōu)化手段。這是基于在大多數(shù)情況下粥脚,線程持有鎖的時間都不會太長纤怒,如果直接掛起操作系統(tǒng)層面的線程可能會得不償失诺祸,畢竟操作系統(tǒng)實現(xiàn)線程之間的切換時需要從用戶態(tài)轉(zhuǎn)換到核心態(tài),這個狀態(tài)之間的轉(zhuǎn)換需要相對比較長的時間,時間成本相對較高,因此自旋鎖會假設(shè)在不久將來,當(dāng)前的線程可以獲得鎖静浴,因此虛擬機會讓當(dāng)前想要獲取鎖的線程做幾個空循環(huán)(這也是稱為自旋的原因)软免,一般不會太久胚委,可能是50個循環(huán)或100循環(huán),在經(jīng)過若干次循環(huán)后荚板,如果得到鎖,就順利進(jìn)入臨界區(qū)婶希。如果還不能獲得鎖壁晒,那就會將線程在操作系統(tǒng)層面掛起不撑,這就是自旋鎖的優(yōu)化方式,這種方式確實也是可以提升效率的。最后沒辦法也就只能升級為重量級鎖了。
2.Java中設(shè)置最大堆和最小堆的參數(shù)是什么
-Xmx128m:設(shè)置JVM最大可用內(nèi)存為128M型型。
????? -Xms128m:設(shè)置JVM最小內(nèi)存為128m。此值可以設(shè)置與-Xmx相同,以避免每次垃圾回收完成后JVM重新分配內(nèi)存啤握。
????? -Xmn2g:設(shè)置年輕代大小為2G咖祭。整個堆大小=年輕代大小 + 年老代大小 + 持久代大小骚腥。持久代一般固定大小為64m口予,所以增大年輕代后且轨,將會減小年老代大小嫌变。此值對系統(tǒng)性能影響較大增热,Sun官方推薦配置為整個堆的3/8。
????? -Xss128k:設(shè)置每個線程的堆棧大小讼载。 JDK5.0以后每個線程堆棧大小為1M舆逃,以前每個線程堆棧大小為256K砂轻。根據(jù)應(yīng)用的線程所需內(nèi)存大小進(jìn)行調(diào)整抒痒。在相同物理內(nèi)存下寨辩,減小這個值能生成更 多的線程。但是操作系統(tǒng)對一個進(jìn)程內(nèi)的線程數(shù)還是有限制的缸榛,不能無限生成周叮,經(jīng)驗值在3000~5000左右。
3.volatile的作用
https://blog.csdn.net/roy_70/article/details/69524115
4.多個線程同時讀寫,讀線程的數(shù)量遠(yuǎn)遠(yuǎn)對于寫線程,你認(rèn)為應(yīng)該如何解決 并發(fā)的問題,你會加什么樣的鎖?
https://www.cnblogs.com/zzlp/p/5174745.html
5.java中的AQS是否了解,它是干嘛的呢?
http://www.360doc.com/content/14/0813/15/1073512_401561812.shtml
6. 除了synchronized關(guān)鍵字之外,你是這么來保障線程安全的?
7.什么時候需要加volatile關(guān)鍵字,它能保證線程安全嗎?
https://blog.csdn.net/roy_70/article/details/69524115
8.mybaties怎么防止SQL注入
#{}是經(jīng)過預(yù)編譯的各薇,是安全的项贺;${}是未經(jīng)過預(yù)編譯的,僅僅是取變量的值得糜,是非安全的敬扛,存在SQL注入。
9.Hibernate的緩存機制
10.Hibernate的一級緩存:?Session
11.Hibernate的二級緩存 :?SessionFactory?
Hibernate的緩存包括Session的緩存和SessionFactory的緩存朝抖,其中SessionFactory的緩存又可以分為兩類:內(nèi)置緩存和外置緩存啥箭。Session的緩存是內(nèi)置的,不能被卸載治宣,也被稱為Hibernate的第一級緩存急侥。SessionFactory的內(nèi)置緩存和Session的緩存在實現(xiàn)方式上比較相似砌滞,前者是SessionFactory對象的一些集合屬性包含的數(shù)據(jù),后者是指Session的一些集合屬性包含的數(shù)據(jù)坏怪。SessionFactory的內(nèi)置緩存中存放了映射元數(shù)據(jù)和預(yù)定義SQL語句昔脯,映射元數(shù)據(jù)是映射文件中數(shù)據(jù)的拷貝,而預(yù)定義SQL語句是在Hibernate初始化階段根據(jù)映射元數(shù)據(jù)推導(dǎo)出來护戳,SessionFactory的內(nèi)置緩存是只讀的看成,應(yīng)用程序不能修改緩存中的映射元數(shù)據(jù)和預(yù)定義SQL語句,因此SessionFactory不需要進(jìn)行內(nèi)置緩存與映射文件的同步鹏秋。SessionFactory的外置緩存是一個可配置的插件尊蚁。在默認(rèn)情況下,SessionFactory不會啟用這個插件侣夷。外置緩存的數(shù)據(jù)是數(shù)據(jù)庫數(shù)據(jù)的拷貝横朋,外置緩存的介質(zhì)可以是內(nèi)存或者硬盤。SessionFactory的外置緩存也被稱為Hibernate的第二級緩存百拓。
12.什么的數(shù)據(jù)適合放到第二級緩存中
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Hibernate二級緩存適用場景
1) 很少被后臺修改的數(shù)據(jù)
2) 不是很重要的數(shù)據(jù)琴锭,允許出現(xiàn)偶爾并發(fā)的數(shù)據(jù)
3) 訪問量大,不會被并發(fā)訪問的數(shù)據(jù)衙传,如個人資料
4) 參考數(shù)據(jù),指的是供應(yīng)用參考的常量數(shù)據(jù)决帖,它的實例數(shù)目有限,它的實例會被許多其他類的實例引用粪牲,實例極少或者從來不會被修改古瓤。
2.不適合存放到第二級緩存的數(shù)據(jù)
1) 經(jīng)常被后臺修改的數(shù)據(jù) ,這里指的是前臺后臺使用了不同的orm實現(xiàn)
2) 財務(wù)數(shù)據(jù)腺阳,絕對不允許出現(xiàn)并發(fā)
3) 與其他應(yīng)用共享的數(shù)據(jù)落君。
4)訪問量不大的數(shù)據(jù)
13.Mybatis和Hibernate的區(qū)別(優(yōu)缺點)
Mybatis優(yōu)勢
MyBatis可以進(jìn)行更為細(xì)致的SQL優(yōu)化,可以減少查詢字段亭引。
MyBatis容易掌握绎速,而Hibernate門檻較高。
Hibernate的DAO層開發(fā)比MyBatis簡單焙蚓,Mybatis需要維護(hù)SQL和結(jié)果映射纹冤。
Hibernate對對象的維護(hù)和緩存要比MyBatis好,對增刪改查的對象的維護(hù)要方便购公。
Hibernate數(shù)據(jù)庫移植性很好萌京,MyBatis的數(shù)據(jù)庫移植性不好,不同的數(shù)據(jù)庫需要寫不同SQL宏浩。
Hibernate有更好的二級緩存機制知残,可以使用第三方緩存。MyBatis本身提供的緩存機制不佳比庄。
------
使用Hibernate進(jìn)行編程有以下好處:
? ? 1求妹,消除了代碼的映射規(guī)則乏盐,它全部分離到了xml或者注解里面去配置。
? ? 2制恍,無需在管理數(shù)據(jù)庫連接父能,它也配置到xml里面了。
? ? 3净神,一個會話中不需要操作多個對象何吝,只需要操作Session對象。
? ? 4强挫,關(guān)閉資源只需要關(guān)閉一個Session便可岔霸。
? ? 這就是Hibernate的優(yōu)勢薛躬,在配置了映射文件和數(shù)據(jù)庫連接文件后俯渤,Hibernate就可以通過Session操作,非常容易型宝,消除了jdbc帶來的大量代碼八匠,大大提高了編程的簡易性和可讀性。Hibernate還提供了級聯(lián)趴酣,緩存梨树,映射,一對多等功能岖寞。Hibernate是全表映射抡四,通過HQL去操作pojo進(jìn)而操作數(shù)據(jù)庫的數(shù)據(jù)。
? ? Hibernate的缺點:
? ? 1仗谆,全表映射帶來的不便指巡,比如更新時需要發(fā)送所有的字段。
? ? 2隶垮,無法根據(jù)不同的條件組裝不同的SQL藻雪。
? ? 3,對多表關(guān)聯(lián)和復(fù)雜的sql查詢支持較差狸吞,需要自己寫sql勉耀,返回后,需要自己將數(shù)據(jù)封裝為pojo蹋偏。
? ? 4便斥,不能有效的支持存儲過程。
? ? 5威始,雖然有HQL枢纠,但是性能較差,大型互聯(lián)網(wǎng)系統(tǒng)往往需要優(yōu)化sql字逗,而hibernate做不到京郑。
Mybatis:
? ? 為了解決Hibernate的不足宅广,Mybatis出現(xiàn)了,Mybatis是半自動的框架些举。之所以稱它為半自動跟狱,是因為它需要手工匹配提供POJO,sql和映射關(guān)系户魏,而全表映射的Hibernate只需要提供pojo和映射關(guān)系即可驶臊。
? ?Mybatis需要提供的映射文件包含了一下三個部分:sql,映射規(guī)則叼丑,pojo关翎。在Mybatis里面你需要自己編寫sql,雖然比Hibernate配置多鸠信,但是Mybatis可以配置動態(tài)sql纵寝,解決了hibernate表名根據(jù)時間變化,不同條件下列不一樣的問題星立,同時你也可以對sql進(jìn)行優(yōu)化爽茴,通過配置決定你的sql映射規(guī)則,也能支持存儲過程绰垂,所以對于一些復(fù)雜和需要優(yōu)化性能的sql查詢它就更加方便室奏。Mybatis幾乎可以做到j(luò)dbc所有能做到的事情。
什么時候使用Hibernate劲装,Mybatis
Hibernate作為留下的Java?orm框架胧沫,它確實編程簡易,需要我們提供映射的規(guī)則占业,完全可以通過IDE生成绒怨,同時無需編寫sql確實開發(fā)效率優(yōu)于Mybatis。此外Hibernate還提供了緩存纺酸,日志窖逗,級聯(lián)等強大的功能,但是Hibernate的缺陷也是十分明顯餐蔬,多表關(guān)聯(lián)復(fù)雜sql碎紊,數(shù)據(jù)系統(tǒng)權(quán)限限制,根據(jù)條件變化的sql樊诺,存儲過程等場景使用Hibernate十分不方便仗考,而性能又難以通過sql優(yōu)化,所以注定了Hibernate只適用于在場景不太復(fù)雜词爬,要求性能不太苛刻的時候使用秃嗜。
? ? 如果你需要一個靈活的,可以動態(tài)生成映射關(guān)系的框架,那么Mybatis確實是一個最好的選擇锅锨。它幾乎可以替代jdbc叽赊,擁有動態(tài)列,動態(tài)表名必搞,存儲過程支持必指,同時提供了簡易的緩存,日志恕洲,級聯(lián)塔橡。但是它的缺陷是需要你提供映射規(guī)則和sql,所以開發(fā)工作量比hibernate要大些霜第。
14.redis的使用場景
https://www.cnblogs.com/NiceCui/p/7794659.html
15.Tomcat本身的參數(shù)你一般會這么調(diào)整
https://blog.csdn.net/ldx891113/article/details/51735171
16.如果有很多的數(shù)據(jù)插入MYSQL,你會選擇什么引擎
MYISAM
19.如何自定義類加載器,你用過哪些場景需要自定義類加載器?
https://www.zhihu.com/question/46719811
http://www.reibang.com/p/acc7595f1b9d
20.堆內(nèi)存設(shè)置的參數(shù)是什么
-Xmx128m:設(shè)置JVM最大可用內(nèi)存為128M葛家。
????? -Xms128m:設(shè)置JVM最小內(nèi)存為128m。此值可以設(shè)置與-Xmx相同泌类,以避免每次垃圾回收完成后JVM重新分配內(nèi)存癞谒。
????? -Xmn2g:設(shè)置年輕代大小為2G。整個堆大小=年輕代大小 + 年老代大小 + 持久代大小末誓。持久代一般固定大小為64m扯俱,所以增大年輕代后,將會減小年老代大小喇澡。此值對系統(tǒng)性能影響較大,Sun官方推薦配置為整個堆的3/8殊校。
????? -Xss128k:設(shè)置每個線程的堆棧大小晴玖。 JDK5.0以后每個線程堆棧大小為1M,以前每個線程堆棧大小為256K为流。根據(jù)應(yīng)用的線程所需內(nèi)存大小進(jìn)行調(diào)整呕屎。在相同物理內(nèi)存下,減小這個值能生成更 多的線程敬察。但是操作系統(tǒng)對一個進(jìn)程內(nèi)的線程數(shù)還是有限制的秀睛,不能無限生成,經(jīng)驗值在3000~5000左右莲祸。
24. 1.8后 Perm Space有哪些變動, MetaSpace默認(rèn)是有限的么?還是你們通過什么方式指定
PermGen 空間的狀況
這部分內(nèi)存空間將全部移除蹂安。
JVM的參數(shù):PermSize 和 MaxPermSize 會被忽略并給出警告(如果在啟用時設(shè)置了這兩個參數(shù))。
大部分類元數(shù)據(jù)都在本地內(nèi)存中分配锐帜。
用于描述類元數(shù)據(jù)的“klasses”已經(jīng)被移除田盈。
默認(rèn)情況下,類元數(shù)據(jù)只受可用的本地內(nèi)存限制(容量取決于是32位或是64位操作系統(tǒng)的可用虛擬內(nèi)存大薪裳帧)允瞧。
新參數(shù)(MaxMetaspaceSize)用于限制本地內(nèi)存分配給類元數(shù)據(jù)的大小。如果沒有指定這個參數(shù),元空間會在運行時根據(jù)需要動態(tài)調(diào)整述暂。
對于僵死的類及類加載器的垃圾回收將在元數(shù)據(jù)使用達(dá)到“MaxMetaspaceSize”參數(shù)的設(shè)定值時進(jìn)行痹升。
適時地監(jiān)控和調(diào)整元空間對于減小垃圾回收頻率和減少延時是很有必要的。持續(xù)的元空間垃圾回收說明畦韭,可能存在類视卢、類加載器導(dǎo)致的內(nèi)存泄漏或是大小設(shè)置不合適。
一些雜項數(shù)據(jù)已經(jīng)移到Java堆空間中廊驼。升級到JDK8之后据过,會發(fā)現(xiàn)Java堆 空間有所增長。
元空間(Metaspace):
JDK8 HotSpot JVM 使用本地內(nèi)存來存儲類元數(shù)據(jù)信息并稱之為:元空間(Metaspace)妒挎;這與Oracle JRockit?和IBM JVM’s很相似绳锅。這將是一個好消息:意味著不會再有java.lang.OutOfMemoryError: PermGen問題,也不再需要你進(jìn)行調(diào)優(yōu)及監(jiān)控內(nèi)存空間的使用……但請等等酝掩,這么說還為時過早鳞芙。在默認(rèn)情況下,這些改變是透明的期虾,接下來我們的展示將使你知道仍然要關(guān)注類元數(shù)據(jù)內(nèi)存的占用原朝。請一定要牢記,這個新特性也不能神奇地消除類和類加載器導(dǎo)致的內(nèi)存泄漏镶苞。你需求使用不同的方法以及遵守新的命名約定來追蹤這些問題喳坠。我推薦大家閱讀有關(guān)PermGen移除總結(jié)和Jon對此的評論。
25.Jstack 是干什么的? Jstat呢? 如果線上程序周期性出現(xiàn)卡頓,你懷疑是否是GC導(dǎo)致的
? 你會這么來排查這個問題? 線程日志你會看其中的什么部分?
http://www.51testing.com/html/92/77492-203728.html
https://www.cnblogs.com/chengJAVA/p/5821218.html
jstack可以定位到線程堆棧茂蚓,根據(jù)堆棧信息我們可以定位到具體代碼壕鹉,所以它在JVM性能調(diào)優(yōu)中使用得非常多。下面我們來一個實例找出某個Java進(jìn)程中最耗費CPU的Java線程并定位堆棧信息聋涨,用到的命令有ps晾浴、top、printf牍白、jstack脊凰、grep。
26.StackOverFlow異常有沒有遇到過,一般會在什么情況下觸發(fā),如何指定堆棧的大小,一般你們寫多少
stackoverflow:
每當(dāng)java程序啟動一個新的線程時茂腥,java虛擬機會為他分配一個棧狸涌,java棧以幀為單位保持線程運行狀態(tài);當(dāng)線程調(diào)用一個方法是础芍,jvm壓入一個新的棧幀到這個線程的棧中杈抢,只要這個方法還沒返回,這個棧幀就存在仑性。?
如果方法的嵌套調(diào)用層次太多(如遞歸調(diào)用),隨著java棧中的幀的增多惶楼,最終導(dǎo)致這個線程的棧中的所有棧幀的大小的總和大于-Xss設(shè)置的值,而產(chǎn)生生StackOverflowError溢出異常。
outofmemory:
2.1歼捐、棧內(nèi)存溢出
java程序啟動一個新線程時何陆,沒有足夠的空間為改線程分配java棧,一個線程java棧的大小由-Xss設(shè)置決定豹储;JVM則拋出OutOfMemoryError異常贷盲。
2.2、堆內(nèi)存溢出
java堆用于存放對象的實例剥扣,當(dāng)需要為對象的實例分配內(nèi)存時巩剖,而堆的占用已經(jīng)達(dá)到了設(shè)置的最大值(通過-Xmx)設(shè)置最大值,則拋出OutOfMemoryError異常钠怯。
方法區(qū)內(nèi)存溢出
方法區(qū)用于存放java類的相關(guān)信息佳魔,如類名、訪問修飾符晦炊、常量池鞠鲜、字段描述、方法描述等断国。在類加載器加載class文件到內(nèi)存中的時候贤姆,JVM會提取其中的類信息,并將這些類信息放到方法區(qū)中稳衬。?
當(dāng)需要存儲這些類信息霞捡,而方法區(qū)的內(nèi)存占用又已經(jīng)達(dá)到最大值(通過-XX:MaxPermSize);將會拋出OutOfMemoryError異常對于這種情況的測試宋彼,基本的思路是運行時產(chǎn)生大量的類去填滿方法區(qū)弄砍,直到溢出。這里需要借助CGLib直接操作字節(jié)碼運行時输涕,生成了大量的動態(tài)類。
27.簡述synchronized? Object;Monitor機制
synchronized的三種應(yīng)用方式
synchronized關(guān)鍵字最主要有以下3種應(yīng)用方式慨畸,下面分別介紹
修飾實例方法莱坎,作用于當(dāng)前實例加鎖,進(jìn)入同步代碼前要獲得當(dāng)前實例的鎖
修飾靜態(tài)方法寸士,作用于當(dāng)前類對象加鎖檐什,進(jìn)入同步代碼前要獲得當(dāng)前類對象的鎖
修飾代碼塊,指定加鎖對象弱卡,對給定對象加鎖乃正,進(jìn)入同步代碼庫前要獲得給定對象的鎖。
Java 虛擬機中的同步(Synchronization)基于進(jìn)入和退出管程(Monitor)對象實現(xiàn)婶博, 無論是顯式同步(有明確的 monitorenter 和 monitorexit 指令,即同步代碼塊)還是隱式同步都是如此瓮具。在 Java 語言中,同步用的最多的地方可能是被 synchronized 修飾的同步方法。
Java虛擬機對synchronized的優(yōu)化
鎖的狀態(tài)總共有四種名党,無鎖狀態(tài)叹阔、偏向鎖、輕量級鎖和重量級鎖传睹。隨著鎖的競爭耳幢,鎖可以從偏向鎖升級到輕量級鎖,再升級的重量級鎖欧啤,但是鎖的升級是單向的睛藻,也就是說只能從低到高升級,不會出現(xiàn)鎖的降級邢隧,關(guān)于重量級鎖店印,前面我們已詳細(xì)分析過,下面我們將介紹偏向鎖和輕量級鎖以及JVM的其他優(yōu)化手段府框,這里并不打算深入到每個鎖的實現(xiàn)和轉(zhuǎn)換過程更多地是闡述Java虛擬機所提供的每個鎖的核心優(yōu)化思想吱窝,畢竟涉及到具體過程比較繁瑣,如需了解詳細(xì)過程可以查閱《深入理解Java虛擬機原理》迫靖。
偏向鎖是Java 6之后加入的新鎖院峡,它是一種針對加鎖操作的優(yōu)化手段,經(jīng)過研究發(fā)現(xiàn)系宜,在大多數(shù)情況下照激,鎖不僅不存在多線程競爭,而且總是由同一線程多次獲得盹牧,因此為了減少同一線程獲取鎖(會涉及到一些CAS操作,耗時)的代價而引入偏向鎖俩垃。偏向鎖的核心思想是,如果一個線程獲得了鎖汰寓,那么鎖就進(jìn)入偏向模式口柳,此時Mark Word 的結(jié)構(gòu)也變?yōu)槠蜴i結(jié)構(gòu),當(dāng)這個線程再次請求鎖時有滑,無需再做任何同步操作跃闹,即獲取鎖的過程,這樣就省去了大量有關(guān)鎖申請的操作毛好,從而也就提供程序的性能望艺。所以,對于沒有鎖競爭的場合肌访,偏向鎖有很好的優(yōu)化效果找默,畢竟極有可能連續(xù)多次是同一個線程申請相同的鎖。但是對于鎖競爭比較激烈的場合吼驶,偏向鎖就失效了惩激,因為這樣場合極有可能每次申請鎖的線程都是不相同的店煞,因此這種場合下不應(yīng)該使用偏向鎖,否則會得不償失咧欣,需要注意的是浅缸,偏向鎖失敗后,并不會立即膨脹為重量級鎖魄咕,而是先升級為輕量級鎖衩椒。下面我們接著了解輕量級鎖。
倘若偏向鎖失敗哮兰,虛擬機并不會立即升級為重量級鎖毛萌,它還會嘗試使用一種稱為輕量級鎖的優(yōu)化手段(1.6之后加入的),此時Mark Word 的結(jié)構(gòu)也變?yōu)檩p量級鎖的結(jié)構(gòu)喝滞。輕量級鎖能夠提升程序性能的依據(jù)是“對絕大部分的鎖阁将,在整個同步周期內(nèi)都不存在競爭”,注意這是經(jīng)驗數(shù)據(jù)右遭。需要了解的是做盅,輕量級鎖所適應(yīng)的場景是線程交替執(zhí)行同步塊的場合,如果存在同一時間訪問同一鎖的場合窘哈,就會導(dǎo)致輕量級鎖膨脹為重量級鎖吹榴。
自旋鎖
輕量級鎖失敗后,虛擬機為了避免線程真實地在操作系統(tǒng)層面掛起滚婉,還會進(jìn)行一項稱為自旋鎖的優(yōu)化手段图筹。這是基于在大多數(shù)情況下,線程持有鎖的時間都不會太長让腹,如果直接掛起操作系統(tǒng)層面的線程可能會得不償失远剩,畢竟操作系統(tǒng)實現(xiàn)線程之間的切換時需要從用戶態(tài)轉(zhuǎn)換到核心態(tài),這個狀態(tài)之間的轉(zhuǎn)換需要相對比較長的時間骇窍,時間成本相對較高瓜晤,因此自旋鎖會假設(shè)在不久將來,當(dāng)前的線程可以獲得鎖腹纳,因此虛擬機會讓當(dāng)前想要獲取鎖的線程做幾個空循環(huán)(這也是稱為自旋的原因)活鹰,一般不會太久,可能是50個循環(huán)或100循環(huán)只估,在經(jīng)過若干次循環(huán)后,如果得到鎖着绷,就順利進(jìn)入臨界區(qū)蛔钙。如果還不能獲得鎖,那就會將線程在操作系統(tǒng)層面掛起荠医,這就是自旋鎖的優(yōu)化方式吁脱,這種方式確實也是可以提升效率的桑涎。最后沒辦法也就只能升級為重量級鎖了。
28.簡述 happen-before規(guī)則
http://mp.weixin.qq.com/s?__biz=MzUxNDA1NDI3OA==&mid=2247484068&idx=1&sn=ee27564362a1db89e114ae173d0d930d&chksm=f94a834dce3d0a5b52694e9e85983975b79c434b69575a10ca682b780aa8e7589ebb357b16b4&mpshare=1&scene=1&srcid=0330lEoyj8JDo7DCze8oSt2E#rd
29. JUC和 Object; Monitor機制區(qū)別是什么; 簡述 AQS原理
synchronized和lock的用法區(qū)別
synchronized:在需要同步的對象中加入此控制兼贡,synchronized可以加在方法上攻冷,也可以加在特定代碼塊中,括號中表示需要鎖的對象遍希。
lock:需要顯示指定起始位置和終止位置等曼。一般使用ReentrantLock類做為鎖,多個線程中必須要使用一個ReentrantLock類做為對象才能保證鎖的生效凿蒜。且在加鎖和解鎖處需要通過lock()和unlock()顯示指出禁谦。所以一般會在finally塊中寫unlock()以防死鎖。
ReentrantLock 擁有Synchronized相同的并發(fā)性和內(nèi)存語義废封,此外還多了 鎖投票州泊,定時鎖等候和中斷鎖等候
線程A和B都要獲取對象O的鎖定,假設(shè)A獲取了對象O鎖漂洋,B將等待A釋放對O的鎖定遥皂,
如果使用 synchronized ,如果A不釋放刽漂,B將一直等下去演训,不能被中斷
如果 使用ReentrantLock,如果A不釋放爽冕,可以使B在等待了足夠長的時間以后仇祭,中斷等待,而干別的事情
ReentrantLock獲取鎖定與三種方式:
a) lock(), 如果獲取了鎖立即返回颈畸,如果別的線程持有鎖乌奇,當(dāng)前線程則一直處于休眠狀態(tài),直到獲取鎖眯娱。
b) tryLock(), 如果獲取了鎖立即返回true礁苗,如果別的線程正持有鎖,立即返回false徙缴。
c)tryLock(long timeout,TimeUnit unit)试伙, 如果獲取了鎖定立即返回true,如果別的線程正持有鎖于样,會等待參數(shù)給定的時間疏叨,在等待的過程中,如果獲取了鎖定穿剖,就返回true蚤蔓,如果等待超時,返回false糊余。
d) lockInterruptibly:如果獲取了鎖定立即返回秀又,如果沒有獲取鎖定单寂,當(dāng)前線程處于休眠狀態(tài),直到獲得鎖定吐辙,或者當(dāng)前線程被別的線程中斷宣决。
在非常復(fù)雜的同步應(yīng)用中,請考慮使用ReentrantLock昏苏,特別是遇到下面2種需求的時候尊沸。
某個線程在等待一個鎖的控制權(quán)的這段時間需要中斷
需要分開處理一些wait-notify,ReentrantLock里面的Condition應(yīng)用捷雕,能夠控制notify哪個線程
具有公平鎖功能椒丧,每個到來的線程都將排隊等候
2、synchronized是在JVM層面上實現(xiàn)的救巷,不但可以通過一些監(jiān)控工具監(jiān)控synchronized的鎖定壶熏,而且在代碼執(zhí)行時出現(xiàn)異常,JVM會自動釋放鎖定浦译,但是使用Lock則不行棒假,lock是通過代碼實現(xiàn)的,要保證鎖定一定會被釋放精盅,就必須將unLock()放到finally{}中
3帽哑、在資源競爭不是很激烈的情況下,Synchronized的性能要優(yōu)于ReetrantLock叹俏,但是在資源競爭很激烈的情況下妻枕,Synchronized的性能會下降幾十倍,但是ReetrantLock的性能能維持常態(tài)粘驰;
AQS:
https://segmentfault.com/a/1190000008471362
30. 簡述 DCL失效原因,解決方法
https://blog.csdn.net/zhaojw_420/article/details/70477921
DCL失效原因是:獲得鎖的線程正在執(zhí)行構(gòu)造函數(shù)的時候屡谐,其他的線程執(zhí)行到第一次檢查if?(m_instance?==?null)的時候,會返回false蝌数,因為已經(jīng)在執(zhí)行構(gòu)造函數(shù)了愕掏,就不是null,因此,會把沒有構(gòu)造完全的對象返回給線程使用顶伞。這是不安全的饵撑。
解決方案:?
1、最簡單而且安全的解決方法是使用static內(nèi)部類的思想唆貌,它利用的思想是:一個類直到被使用時才被初始化滑潘,而類初始化的過程是非并行的,這些都有JLS保證锨咙。?
如下述代碼:
31.簡述nio原理
33.gc算法有哪些; gc收集器有哪些
https://blog.csdn.net/canot/article/details/51038328
https://www.cnblogs.com/ityouknow/p/5614961.html
34.簡述class加載各階段過程
https://blog.csdn.net/tangdong3415/article/details/53768099
35, 簡述JDK命令行工具
https://blog.csdn.net/ochangwen/article/details/52971913
36.簡述字節(jié)碼文件組成
37.講講你平常是如何針對具體的SQL做優(yōu)化
http://www.reibang.com/p/22b5add93264
38.mysql的存儲有哪些,區(qū)別
innodb . ?MYISAM
39.gc內(nèi)存模型
40.如何實現(xiàn)一個定時調(diào)度和循環(huán)調(diào)度的工具類,當(dāng)提交任務(wù)處理不過來的時候,拒絕機制應(yīng)該如何處理,線程池默認(rèn)有哪幾種拒絕機制
https://blog.csdn.net/heyutao007/article/details/38797335
http://www.importnew.com/19011.html
41. 如何實現(xiàn)一個 ThreadLocal
當(dāng)前線程Id 為 key 的Map
http://www.reibang.com/p/ee8c9dccc953
http://www.reibang.com/p/ee8c9dccc953
42. 說說你了解的線程安全隊列
在Java多線程應(yīng)用中众羡,隊列的使用率很高,多數(shù)生產(chǎn)消費模型的首選數(shù)據(jù)結(jié)構(gòu)就是隊列蓖租。Java提供的線程安全的Queue可以分為阻塞隊列和非阻塞隊列粱侣,其中阻塞隊列的典型例子是BlockingQueue,非阻塞隊列的典型例子是ConcurrentLinkedQueue蓖宦,在實際應(yīng)用中要根據(jù)實際需要選用阻塞隊列或者非阻塞隊列齐婴。
注:什么叫線程安全?這個首先要明確稠茂。線程安全的類?柠偶,指的是類內(nèi)共享的全局變量的訪問必須保證是不受多線程形式影響的。如果由于多線程的訪問(比如修改睬关、遍歷诱担、查看)而使這些變量結(jié)構(gòu)被破壞或者針對這些變量操作的原子性被破壞,則這個類就不是線程安全的电爹。
今天就聊聊這兩種Queue蔫仙,本文分為以下兩個部分,用分割線分開:?
BlockingQueue? 阻塞算法
ConcurrentLinkedQueue丐箩,非阻塞算法
Queue是什么就不需要多說了吧摇邦,一句話:隊列是先進(jìn)先出。相對的屎勘,棧是后進(jìn)先出施籍。如果不熟悉的話先找本基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)的書看看吧。?
從上表可以很明顯看出每個方法的作用概漱,這個不用多說丑慎。我想說的是:?
add(e) remove() element() 方法不會阻塞線程。當(dāng)不滿足約束條件時瓤摧,會拋出IllegalStateException 異常竿裂。例如:當(dāng)隊列被元素填滿后,再調(diào)用add(e)姻灶,則會拋出異常铛绰。
offer(e) poll() peek() 方法即不會阻塞線程,也不會拋出異常产喉。例如:當(dāng)隊列被元素填滿后捂掰,再調(diào)用offer(e),則不會插入元素曾沈,函數(shù)返回false这嚣。
要想要實現(xiàn)阻塞功能,需要調(diào)用put(e) take() 方法塞俱。當(dāng)不滿足約束條件時姐帚,會阻塞線程。
------------
下面再來說說ConcurrentLinkedQueue障涯,它是一個無鎖的并發(fā)線程安全的隊列罐旗。?
以下部分的內(nèi)容參照了這個帖子http://yanxuxin.iteye.com/blog/586943
對比鎖機制的實現(xiàn)膳汪,使用無鎖機制的難點在于要充分考慮線程間的協(xié)調(diào)。簡單的說就是多個線程對內(nèi)部數(shù)據(jù)結(jié)構(gòu)進(jìn)行訪問時九秀,如果其中一個線程執(zhí)行的中途因為一些原因出現(xiàn)故障遗嗽,其他的線程能夠檢測并幫助完成剩下的操作。這就需要把對數(shù)據(jù)結(jié)構(gòu)的操作過程精細(xì)的劃分成多個狀態(tài)或階段鼓蜒,考慮每個階段或狀態(tài)多線程訪問會出現(xiàn)的情況痹换。
ConcurrentLinkedQueue有兩個volatile的線程共享變量:head,tail都弹。要保證這個隊列的線程安全就是保證對這兩個Node的引用的訪問(更新娇豫,查看)的原子性和可見性,由于volatile本身能夠保證可見性畅厢,所以就是對其修改的原子性要被保證冯痢。
43. Atomic包的實現(xiàn)原理
Compare and swap(CAS) ?通過CAS實現(xiàn)的,可能 涉及ABA問題
https://blog.csdn.net/zhangerqing/article/details/43057799
44.CAS是這么保證原子性的
在JDK 5之前Java語言是靠synchronized關(guān)鍵字保證同步的,這會導(dǎo)致有鎖(后面的章節(jié)還會談到鎖)或详。
? ? ? 鎖機制存在以下問題:
? ? ? (1)在多線程競爭下系羞,加鎖、釋放鎖會導(dǎo)致比較多的上下文切換和調(diào)度延時霸琴,引起性能問題椒振。
? ? ? (2)一個線程持有鎖會導(dǎo)致其它所有需要此鎖的線程掛起。
? ? ? (3)如果一個優(yōu)先級高的線程等待一個優(yōu)先級低的線程釋放鎖會導(dǎo)致優(yōu)先級倒置梧乘,引起性能風(fēng)險澎迎。
? ? ? volatile是不錯的機制,但是volatile不能保證原子性选调。因此對于同步最終還是要回到鎖機制上來夹供。
? ? ? 獨占鎖是一種悲觀鎖,synchronized就是一種獨占鎖仁堪,會導(dǎo)致其它所有需要鎖的線程掛起哮洽,等待持有鎖的線程釋放鎖。而另一個更加有效的鎖就是樂觀鎖弦聂。所謂樂觀鎖就是鸟辅,每次不加鎖而是假設(shè)沒有沖突而去完成某項操作,如果因為沖突失敗就重試莺葫,直到成功為止匪凉。
? ? ? CAS 操作
? ? ? 上面的樂觀鎖用到的機制就是CAS,Compare and Swap捺檬。
? ? ? CAS有3個操作數(shù)再层,內(nèi)存值V,舊的預(yù)期值A(chǔ)缺猛,要修改的新值B览徒。當(dāng)且僅當(dāng)預(yù)期值A(chǔ)和內(nèi)存值V相同時不脯,將內(nèi)存值V修改為B启摄,否則什么都不做。
非阻塞算法 (nonblocking algorithms)
一個線程的失敗或者掛起不應(yīng)該影響其他線程的失敗或掛起的算法贴届。
? ? ? 現(xiàn)代的CPU提供了特殊的指令卤材,可以自動更新共享數(shù)據(jù)洲胖,而且能夠檢測到其他線程的干擾瘫俊,而 compareAndSet() 就用這些代替了鎖定。
? ? ? 拿出AtomicInteger來研究在沒有鎖的情況下是如何做到數(shù)據(jù)正確性的悴灵。
private volatile int value;
? ? 首先毫無疑問扛芽,在沒有鎖的機制下需要借助volatile原語,保證線程間的數(shù)據(jù)是可見的(共享的)积瞒,這樣獲取變量值的時候才能直接讀取川尖。
public final int get() {
return value;
}
? ? ? 然后來看看++i是怎么做到的。
public final int incrementAndGet() {
for (;;) {
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
? ? ? 在這里采用了CAS操作茫孔,每次從內(nèi)存中讀取數(shù)據(jù)然后將此數(shù)據(jù)和+1后的結(jié)果進(jìn)行CAS操作叮喳,如果成功就返回結(jié)果,否則重試直到成功為止缰贝。
? ? ? 而compareAndSet利用JNI來完成CPU指令的操作馍悟。
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
? ? ? 整體的過程就是這樣子的,利用CPU的CAS指令剩晴,同時借助JNI來完成Java的非阻塞算法锣咒。其它原子操作都是利用類似的特性完成的。
? ? ? 而整個J.U.C都是建立在CAS之上的赞弥,因此對于synchronized阻塞算法毅整,J.U.C在性能上有了很大的提升。參考資料的文章中介紹了如果利用CAS構(gòu)建非阻塞計數(shù)器绽左、隊列等數(shù)據(jù)結(jié)構(gòu)悼嫉。
? ? ? CAS看起來很爽,但是會導(dǎo)致“ABA問題”拼窥。
? ? ? CAS算法實現(xiàn)一個重要前提需要取出內(nèi)存中某時刻的數(shù)據(jù)戏蔑,而在下時刻比較并替換,但是在這個時間差內(nèi)任何變化都可能發(fā)生闯团。
? ? ? 比如說一個線程one從內(nèi)存位置V中取出A辛臊,這時候另一個線程two也從內(nèi)存中取出A,并且two進(jìn)行了一些操作變成了B房交,然后two又將V位置的數(shù)據(jù)變成A彻舰,這時候線程one進(jìn)行CAS操作發(fā)現(xiàn)內(nèi)存中仍然是A,然后one操作成功。盡管線程one的CAS操作成功刃唤,但是不代表這個過程就是沒有問題的隔心。如果鏈表的頭在變化了兩次后恢復(fù)了原值,但是不代表鏈表就沒有變化尚胞。要解決"ABA問題"硬霍,我們需要增加一個版本號,在更新變量值的時候不應(yīng)該只更新一個變量值笼裳,而應(yīng)該更新兩個值唯卖,分別是變量值和版本號,AtomicStampedReference支持在兩個變量上進(jìn)行原子的條件更新躬柬,可以使用該類進(jìn)行更新操作拜轨。
45.string分析 1000次循環(huán) substring用了多少內(nèi)存
http://www.importnew.com/14105.html