1.寫出synchronized的使用方式
synchronized的三種應(yīng)用方式
synchronized關(guān)鍵字最主要有以下3種應(yīng)用方式,下面分別介紹
修飾實例方法,作用于當(dāng)前實例加鎖,進入同步代碼前要獲得當(dāng)前實例的鎖
修飾靜態(tài)方法,作用于當(dāng)前類對象加鎖,進入同步代碼前要獲得當(dāng)前類對象的鎖
修飾代碼塊,指定加鎖對象,對給定對象加鎖,進入同步代碼庫前要獲得給定對象的鎖。
Java 虛擬機中的同步(Synchronization)基于進入和退出管程(Monitor)對象實現(xiàn), 無論是顯式同步(有明確的 monitorenter 和 monitorexit 指令,即同步代碼塊)還是隱式同步都是如此。在 Java 語言中,同步用的最多的地方可能是被 synchronized 修飾的同步方法。
Java虛擬機對synchronized的優(yōu)化
鎖的狀態(tài)總共有四種,無鎖狀態(tài)、偏向鎖、輕量級鎖和重量級鎖。隨著鎖的競爭,鎖可以從偏向鎖升級到輕量級鎖,再升級的重量級鎖,但是鎖的升級是單向的,也就是說只能從低到高升級,不會出現(xiàn)鎖的降級,關(guān)于重量級鎖,前面我們已詳細分析過,下面我們將介紹偏向鎖和輕量級鎖以及JVM的其他優(yōu)化手段,這里并不打算深入到每個鎖的實現(xiàn)和轉(zhuǎn)換過程更多地是闡述Java虛擬機所提供的每個鎖的核心優(yōu)化思想,畢竟涉及到具體過程比較繁瑣,如需了解詳細過程可以查閱《深入理解Java虛擬機原理》。
偏向鎖是Java 6之后加入的新鎖,它是一種針對加鎖操作的優(yōu)化手段,經(jīng)過研究發(fā)現(xiàn),在大多數(shù)情況下,鎖不僅不存在多線程競爭,而且總是由同一線程多次獲得,因此為了減少同一線程獲取鎖(會涉及到一些CAS操作,耗時)的代價而引入偏向鎖。偏向鎖的核心思想是,如果一個線程獲得了鎖,那么鎖就進入偏向模式,此時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)層面掛起,還會進行一項稱為自旋鎖的優(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)后,如果得到鎖,就順利進入臨界區(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)存大小進行調(diào)整。在相同物理內(nèi)存下,減小這個值能生成更 多的線程。但是操作系統(tǒng)對一個進程內(nèi)的線程數(shù)還是有限制的,不能無限生成,經(jīng)驗值在3000~5000左右。
3.volatile的作用
https://blog.csdn.net/roy_70/article/details/69524115
4.多個線程同時讀寫,讀線程的數(shù)量遠遠對于寫線程,你認為應(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不需要進行內(nèi)置緩存與映射文件的同步。SessionFactory的外置緩存是一個可配置的插件。在默認情況下,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可以進行更為細致的SQL優(yōu)化,可以減少查詢字段。
MyBatis容易掌握,而Hibernate門檻較高。
Hibernate的DAO層開發(fā)比MyBatis簡單,Mybatis需要維護SQL和結(jié)果映射。
Hibernate對對象的維護和緩存要比MyBatis好,對增刪改查的對象的維護要方便。
Hibernate數(shù)據(jù)庫移植性很好,MyBatis的數(shù)據(jù)庫移植性不好,不同的數(shù)據(jù)庫需要寫不同SQL。
Hibernate有更好的二級緩存機制,可以使用第三方緩存。MyBatis本身提供的緩存機制不佳。
------
使用Hibernate進行編程有以下好處:
? ? 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進而操作數(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進行優(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.itdecent.cn/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)存大小進行調(diào)整。在相同物理內(nèi)存下,減小這個值能生成更 多的線程。但是操作系統(tǒng)對一個進程內(nèi)的線程數(shù)還是有限制的,不能無限生成,經(jīng)驗值在3000~5000左右。
24. 1.8后 Perm Space有哪些變動, MetaSpace默認是有限的么?還是你們通過什么方式指定
PermGen 空間的狀況
這部分內(nèi)存空間將全部移除。
JVM的參數(shù):PermSize 和 MaxPermSize 會被忽略并給出警告(如果在啟用時設(shè)置了這兩個參數(shù))。
大部分類元數(shù)據(jù)都在本地內(nèi)存中分配。
用于描述類元數(shù)據(jù)的“klasses”已經(jīng)被移除。
默認情況下,類元數(shù)據(jù)只受可用的本地內(nèi)存限制(容量取決于是32位或是64位操作系統(tǒng)的可用虛擬內(nèi)存大?。?。
新參數(shù)(MaxMetaspaceSize)用于限制本地內(nèi)存分配給類元數(shù)據(jù)的大小。如果沒有指定這個參數(shù),元空間會在運行時根據(jù)需要動態(tài)調(diào)整。
對于僵死的類及類加載器的垃圾回收將在元數(shù)據(jù)使用達到“MaxMetaspaceSize”參數(shù)的設(shè)定值時進行。
適時地監(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問題,也不再需要你進行調(diào)優(yōu)及監(jiān)控內(nèi)存空間的使用……但請等等,這么說還為時過早。在默認情況下,這些改變是透明的,接下來我們的展示將使你知道仍然要關(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進程中最耗費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)達到了設(shè)置的最大值(通過-Xmx)設(shè)置最大值,則拋出OutOfMemoryError異常。
方法區(qū)內(nèi)存溢出
方法區(qū)用于存放java類的相關(guān)信息,如類名、訪問修飾符、常量池、字段描述、方法描述等。在類加載器加載class文件到內(nèi)存中的時候,JVM會提取其中的類信息,并將這些類信息放到方法區(qū)中。?
當(dāng)需要存儲這些類信息,而方法區(qū)的內(nèi)存占用又已經(jīng)達到最大值(通過-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)前實例加鎖,進入同步代碼前要獲得當(dāng)前實例的鎖
修飾靜態(tài)方法,作用于當(dāng)前類對象加鎖,進入同步代碼前要獲得當(dāng)前類對象的鎖
修飾代碼塊,指定加鎖對象,對給定對象加鎖,進入同步代碼庫前要獲得給定對象的鎖。
Java 虛擬機中的同步(Synchronization)基于進入和退出管程(Monitor)對象實現(xiàn), 無論是顯式同步(有明確的 monitorenter 和 monitorexit 指令,即同步代碼塊)還是隱式同步都是如此。在 Java 語言中,同步用的最多的地方可能是被 synchronized 修飾的同步方法。
Java虛擬機對synchronized的優(yōu)化
鎖的狀態(tài)總共有四種,無鎖狀態(tài)、偏向鎖、輕量級鎖和重量級鎖。隨著鎖的競爭,鎖可以從偏向鎖升級到輕量級鎖,再升級的重量級鎖,但是鎖的升級是單向的,也就是說只能從低到高升級,不會出現(xiàn)鎖的降級,關(guān)于重量級鎖,前面我們已詳細分析過,下面我們將介紹偏向鎖和輕量級鎖以及JVM的其他優(yōu)化手段,這里并不打算深入到每個鎖的實現(xiàn)和轉(zhuǎn)換過程更多地是闡述Java虛擬機所提供的每個鎖的核心優(yōu)化思想,畢竟涉及到具體過程比較繁瑣,如需了解詳細過程可以查閱《深入理解Java虛擬機原理》。
偏向鎖是Java 6之后加入的新鎖,它是一種針對加鎖操作的優(yōu)化手段,經(jīng)過研究發(fā)現(xiàn),在大多數(shù)情況下,鎖不僅不存在多線程競爭,而且總是由同一線程多次獲得,因此為了減少同一線程獲取鎖(會涉及到一些CAS操作,耗時)的代價而引入偏向鎖。偏向鎖的核心思想是,如果一個線程獲得了鎖,那么鎖就進入偏向模式,此時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)層面掛起,還會進行一項稱為自旋鎖的優(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)后,如果得到鎖,就順利進入臨界區(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.itdecent.cn/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)該如何處理,線程池默認有哪幾種拒絕機制
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.itdecent.cn/p/ee8c9dccc953
http://www.itdecent.cn/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是什么就不需要多說了吧,一句話:隊列是先進先出。相對的,棧是后進先出。如果不熟悉的話先找本基礎(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)進行訪問時,如果其中一個線程執(zhí)行的中途因為一些原因出現(xiàn)故障,其他的線程能夠檢測并幫助完成剩下的操作。這就需要把對數(shù)據(jù)結(jié)構(gòu)的操作過程精細的劃分成多個狀態(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é)果進行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進行了一些操作變成了B,然后two又將V位置的數(shù)據(jù)變成A,這時候線程one進行CAS操作發(fā)現(xiàn)內(nèi)存中仍然是A,然后one操作成功。盡管線程one的CAS操作成功,但是不代表這個過程就是沒有問題的。如果鏈表的頭在變化了兩次后恢復(fù)了原值,但是不代表鏈表就沒有變化。要解決"ABA問題",我們需要增加一個版本號,在更新變量值的時候不應(yīng)該只更新一個變量值,而應(yīng)該更新兩個值,分別是變量值和版本號,AtomicStampedReference支持在兩個變量上進行原子的條件更新,可以使用該類進行更新操作。
45.string分析 1000次循環(huán) substring用了多少內(nèi)存
http://www.importnew.com/14105.html