版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領
文檔簡介
基礎知識
1.為什么要使用并發(fā)編程
?提升多核CPU的利用率:一般來說一臺主機上的會有多個CPU核心,我們可以創(chuàng)建多個線程,理論
上講操作系統(tǒng)可以將多個線程分配給不同的CPU去執(zhí)行,每個CPU執(zhí)行一個線程,這樣就提高了
CPU的使用效率,如果使用單線程就只能有一個CPU核心被使用。
?比如當我們在網(wǎng)上購物時,為了提升響應速度,需要拆分,減庫存,生成訂單等等這些操作,就可
以進行拆分利用多線程的技術(shù)完成。面對復雜業(yè)務模型,并行程序會比串行程序更適應業(yè)務需求,
而并發(fā)編程更能吻合這種業(yè)務拆分。
?簡單來說就是:
。充分利用多核CPU的計算能力;
。方便進行業(yè)務拆分,提升應用性能
2.多線程應用場景
?例如:迅雷多線程下載、數(shù)據(jù)庫連接池、分批發(fā)送短信等。
3.并發(fā)編程有什么缺點
?并發(fā)編程的目的就是為了能提高程序的執(zhí)行效率,提高程序運行速度,但是并發(fā)編程并不總是能提
高程序運行速度的,而且并發(fā)編程可能會遇到很多問題,比如:內(nèi)存泄漏、上下文切換、線程安
全、死鎖等問題。
4.并發(fā)編程三介必要因素是什么?
?原子性:原子,即一個不可再被分割的顆粒。原子性指的是一個或多個操作要么全部執(zhí)行成功要么
全部執(zhí)行失敗.
?可見性:一個線程對共享變量的修改,另一線程能夠立刻看到。(synchronized,volatile)
?有序性:程序執(zhí)行的順序按照代碼的先后順序執(zhí)行。(處理器可能會對指令進行重排序)
5.Java程序中怎么保證多線程的運行安全?
?出現(xiàn)線程安全問題的原因一般都是三個原因:
。線程切換帶來的原子性問題解決辦法:使用多線程之間同步synchronized或使用鎖(lock)。
。緩存導致的可見性問題解決辦法:synchronized,volatile.LOCK,可以解決可見性問題
。編譯優(yōu)化帶來的有序性問題解決辦法:H叩pens-Before規(guī)則可以解決有序性問題
6.并行和并發(fā)有什么區(qū)別?
?并發(fā):多個任務在同一個CPU核上,按細分的時間片輪流(交替)執(zhí)行,從邏輯上來看那些任務是
同時執(zhí)行。
?并行:單位時間內(nèi),多個處理器或多核處理器同時處理多個任務,是真正意義上的“同時進行"。
?串行:有n個任務,由一個線程按順序執(zhí)行。由于任務、方法都在一個線程執(zhí)行所以不存在線程不
安全情況,也就不存在臨界區(qū)的問題。
做一個形象的比喻:
?并發(fā)=倆個人用一臺電腦。
?并行=倆個人分配了倆臺電腦。
?串行=倆個人排隊使用一臺電腦。
7.什么是多線程
?多線程:多線程是指程序中包含多個執(zhí)行流,即在一個程序中可以同時運行多個不同的線程來執(zhí)行
不同的任務。
8.多線程的好處
?可以提高CPU的利用率。在多線程程序中,一個線程必須等待的時候,CPU可以運行其它的線程
而不是等待,這樣就大大提高了程序的效率。也就是說允許單個程序創(chuàng)建多個并行執(zhí)行的線程來完
成各自的任務.
9.多線程的劣勢:
?線程也是程序,所以線程需要占用內(nèi)存,線程越多占用內(nèi)存也越多;
?多線程需要協(xié)調(diào)和管理,所以需要CPU時間跟蹤線程;
?線程之間對共享資源的訪問會相互影響,必須解決競用共享資源的問題。
10.線程和進程區(qū)別
?什么是線程和進程?
。進程
一個在內(nèi)存中運行的應用程序。每個正在系統(tǒng)上運行的程序都是一個進程
?線程
進程中的一個執(zhí)行任務(控制單元),它負責在程序里獨立執(zhí)行。
一個進程至少有一個線程,?個進程可以運行多個線程,多個線程可共享數(shù)據(jù)。
?進程與線程的區(qū)別
。根本區(qū)別:進程是操作系統(tǒng)資源分配的基本單位,而線程是處理器任務調(diào)度和執(zhí)行的基本單
位
。資源開銷:每個進程都有獨立的代碼和數(shù)據(jù)空間(程序上下文),程序之間的切換會有較大
的開銷;線程可以看做輕量級的進程,同一類線程共享代碼和數(shù)據(jù)空間,每個線程都有自己
獨立的運行榭口程序計數(shù)器(PC),線程之間切換的開銷小。
。包含關系:如果一個進程內(nèi)有多個線程,則執(zhí)行過程不是一條線的,而是多條線(線程)共
同完成的;線程是進程的一部分,所以線程也被稱為輕權(quán)進程或者輕量級進程。
。內(nèi)存分配:同一進程的線程共享本進程的地址空間和資源,而進程與進程之間的地址空間和
資源是相互獨立的
。影響關系:一個進程崩潰后,在保護模式下不會對其他進程產(chǎn)生影響,但是一個線程崩潰有
可能導致整個進程都死掉。所以多進程要比多線程健壯。
。執(zhí)行過程:每個獨立的進程有程序運行的入口、順序執(zhí)行序列和程序出口。但是線程不能獨
立執(zhí)行,必須依存在應用程序中,由應用程序提供多個線程執(zhí)行控制,兩者均可并發(fā)執(zhí)行
11.什么是上下文切換?
?多線程編程中一般線程的個數(shù)都大于CPU核心的個數(shù),而一個CPU核心在任意時刻只能被一個線
程使用,為了讓這些線程都能得到有效執(zhí)行,CPU采取的策略是為每個線程分配時間片并輪轉(zhuǎn)的
形式。當一個線程的時間片用完的時候就會重新處于就緒狀態(tài)讓給其他線程使用,這個過程就屬于
一次上下文切換。
?概括來說就是:當前任務在執(zhí)行完CPU時間片切換到另一個任務之前會先保存自己的狀態(tài),以便
下次再切換回這個任務時,可以再加載這個任務的狀態(tài)。任務從保存到再加載的過程就是一次上下
文切換。
?上下文切換通常是計算密集型的。也就是說,它需要相當可觀的處理器時間,在每秒幾十上百次的
切換中,每次切換都需要納秒量級的時間。所以,上下文切換對系統(tǒng)來說意味著消耗大量的CPU
時間,事實上,可能是操作系統(tǒng)中時間消耗最大的操作。
?Linux相比與其他操作系統(tǒng)(包括其他類Unix系統(tǒng))有很多的優(yōu)點,其中有一項就是,其上下文
切換和模式切換的時間消耗非常少。
12.守護線程和用戶線程有什么區(qū)別呢?
?用戶(User)線程:運行在前臺,執(zhí)行具體的任務,如程序的主線程、連接網(wǎng)絡的子線程等都是用
戶線程
?守護(Daemon)線程:運行在后臺,為其他前臺線程^務。也可以說守護線程是JVM中非守護線
程的“傭人"。一旦所有用戶線程都結(jié)束運行,守護線程會隨JVM一起結(jié)束工作
13.如何在Windows和Linux上查找哪個線程cpu利用率最高?
?windows上面用任務管理器看,linux下可以用top這個工具看。
。找出cpu耗用厲害的進程pid,終端執(zhí)行top命令,然后按下shift+p(shi代+m是找出消耗內(nèi)存
最高)查找出cpu利用最厲害的pid號
根據(jù)上面第一^拿到的pid號,top-H-ppid。然后按下shift+p,查找出cpu利用率最厲害的
線程號,比如top-H-p1328
■將獲取到的線程號轉(zhuǎn)換成16進制,去百度轉(zhuǎn)換一下就行
。使用jstack工具將進程信息打印輸出,jstackpid號>/tmp/t.dat,比如jstack31365>
/tmp/t.dat
■編輯/tmp/t.dat文件,查找線程號對應的信息
或者直接使用JDK自帶的工具查看“jconsole"、“visualvm",這都是JDK自帶的,可以直接在JDK的bin目錄
下找到直接使用
14.什么是線程死鎖
?死鎖是指兩個或兩個以上的進程(線程)在執(zhí)行過程中,由于競爭資源或者由于彼此通信而造成的
一種阻塞的現(xiàn)象,若無外力作用,它們都將無法推進下去.此時稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了
死鎖,這些永遠在互相等待的進程(線程)稱為死鎖進程(線程)。
?多個線程同時被阻塞,它們中的一個或者全部都在等待某個資源被釋放。由于線程被無限期地阻
塞,因此程序不可能正常終止。
?如下圖所示,線程A持有資源2,線程B持有資源1,他們同時都想申請對方的資源,所以這兩個
線程就會互相等待而進入死鎖狀態(tài)。
線程一線程二
15.形成死鎖的四介必要條件是什么
?互斥條件:在一段時間內(nèi)某資源只由一個進程占用。如果此時還有其它進程請求資源,就只能等
待,直至占有資源的進程用畢釋放。
?占有且等待條件:指進程已經(jīng)保持至少一個資源,但又提出了新的資源請求,而該資源已被其它進
程占有,此時請求進程阻塞,但又對自己已獲得的其它資源保持不放。
?不可搶占條件:別人已經(jīng)占有了某項資源,你不能因為自己也需要該資源,就去把別人的資源搶過
來。
?循環(huán)等待條件:若干進程之間形成一種頭尾相接的循環(huán)等待資源關系。(比如一個進程集合,A在
等B,B在等C,C在等A)
16.如何避免線程死鎖
1.避免一個線程同時獲得多個鎖
2.避免一個線程在鎖內(nèi)同時占用多個資源,盡量保證每個鎖只占用一個資源
3.嘗試使用定時鎖,使用此1<.四1_。d<e1716。戊)來替代使用內(nèi)部鎖機制
17.創(chuàng)建線程的四種方式
?繼承Thread類;
publicclassMyThreadextendsThread{
?Override
publicvoidrun(){
System.out.println(Thread.currentThread().getName()+"run()方法正在執(zhí)
行…”);
?
?實現(xiàn)Runnable接口;
publicclassMyRunnableimplementsRunnable{
?Override
publicvoidrun(){
System.out.println(Thread.currentThread().getName()+"run()方法執(zhí)彳亍
中??.”);
)
?實現(xiàn)Callable接口;
publicclassMyCallableimplementsCal1able<lnteger>{
?Override
publicintegercall(){
System.out.println(Thread.currentThread().getName()+"call()方法執(zhí)彳亍
中…”);
return1;
)
?使用匿名內(nèi)部類方式
publicclassCreateRunnable{
publicstaticvoidmain(String[]args){
//創(chuàng)建多線程創(chuàng)建開始
Threadthread=newThread(newRunnable(){
publicvoidrun(){
for(inti=0;i<10;i++){
System.out.println("i:"+i);
)
)
});
thread.startf);
)
}
18.說一下runnable和callable有什么區(qū)別
相同點:
?都是接口
?都可以編寫多線程程序
?都采用Thread.start。啟動線程
主要區(qū)別:
?Runnable接口run方法無返回值;Callable接口call方法有返回值,是個泛型,和Future、
FutureTask配合可以用來獲取異步執(zhí)行的結(jié)果
?Runnable接口run方法只能拋出運行時異常,且無法捕獲處理;Callable接口call方法允許拋出
異常,可以獲取異常信息注:Callalbe接口支持返回執(zhí)行結(jié)果,需要調(diào)用FutureTask.getO得到,
此方法會阻塞主進程的繼續(xù)往下執(zhí)行,如果不調(diào)用不會阻塞。
19.線程的run。和start。有什么區(qū)別?
?每個線程都是通過某個特定Thread對象所對應的方法run()來完成其操作的,run()方法稱為線程
體。通過調(diào)用Thread類的start。方法來啟動一個線程。
?start。方法用于啟動線程,run()方法用于執(zhí)行線程的運行時代碼。run()可以重復調(diào)用,而start。
只能調(diào)用一次。
?start。方法來啟動一個線程,真正實現(xiàn)了多線程運行。調(diào)用start。方法無需等待run方法體代碼執(zhí)
行完畢,可以直接繼續(xù)執(zhí)行其他的代碼;此時線程是處于就緒狀態(tài),并沒有運行。然后通過此
Thread類調(diào)用方法run()來完成其運行狀態(tài),run()方法運行結(jié)束,此線程終止。然后CPU再調(diào)度
其它線程。
?run()方法是在本線程里的,只是線程里的一個函數(shù),而不是多線程的。如果直接調(diào)用run(),其實
就相當于是調(diào)用了一個普通函數(shù)而已,直接待用run()方法必須等待run()方法執(zhí)行完畢才能執(zhí)行下
面的代碼,所以執(zhí)行路徑還是只有一條,根本就沒有線程的特征,所以在多線程執(zhí)行時要使用
start。方法而不是run()方法。
20.為什么我們調(diào)用start()方法時會執(zhí)行run。方法,為什么我們不能直接調(diào)用
run()方法?
這是另一個非常經(jīng)典的java多線程面試問題,而且在面試中會經(jīng)常被問到。很簡單,但是很多人都會
答不上來!
?new一個Thread,線程進入了新建狀態(tài)。調(diào)用start。方法,會啟動一個線程并使線程進入了就緒
狀態(tài),當分配到時間片后就可以開始運行了。start。會執(zhí)行線程的相應準備工作,然后自動執(zhí)行
run()方法的內(nèi)容,這是真正的多線程工作。
?而直接執(zhí)行run()方法,會把run方法當成—main線程下的普通方法去執(zhí)行,并不會在某個線
程中執(zhí)行它,所以這并不是多線程工作。
總結(jié):調(diào)用start方法方可啟動線程并使線程進入就緒狀態(tài),而run方法只是thread的一個普通方法
調(diào)用,還是在主線程里執(zhí)行。
21.什么是Callable和Future?
?Callable接口類似于Runnable,從名字就可以看出來了,但是Runnable不會返回結(jié)果,并且無
法拋出返回結(jié)果的異常,而Callable功能更強大一些,被線程執(zhí)行后,可以返回值,這個返回值
可以被Future拿到,也就是說,F(xiàn)uture可以拿到異步執(zhí)行任務的返回值。
?Future接口表示異步任務,是一可能還沒有完成的異步任務的結(jié)果.所以說Callable用于產(chǎn)生
結(jié)果,F(xiàn)uture用于獲取結(jié)果。
22.什么是FutureTask
?FutureTask表示一個異步運算的任務。FutureTask里面可以傳入一個Capable的具體實現(xiàn)類,可
以對這個異步運算的任務的結(jié)果進行等待獲取、判斷是否已經(jīng)完成、取消任務等操作。只有當運算
完成的時候結(jié)果才能取回,如果運算尚未完成get方法將會阻塞。一個FutureTask對象可以對調(diào)
用了Callable和Runnable的對象進行包裝,由于FutureTask也是Runnable接口的實現(xiàn)類,所
以FutureTask也可以放入線程池中。
23.線程的狀態(tài)
被其他線程喚醒:
不會釋放鎖
?新建(new):新創(chuàng)建了一個線程對象。
?就緒(可運行狀態(tài))(runnable):線程對象創(chuàng)建后,當調(diào)用線程對象的start。方法,該線程處于就
緒狀態(tài),等待被線程調(diào)度選中,獲取cpu的使用權(quán)。
?運行(running):可運行狀態(tài)(runnable)的線程獲得了cpu時間片(timeslice),執(zhí)行程序代碼。
注:就緒狀態(tài)是進入到運行狀態(tài)的唯一入口,也就是說,線程要想進入運行狀態(tài)執(zhí)行,首先必須處
于就緒狀態(tài)中;
?阻塞(block):處于運行狀態(tài)中的線程由于某種原因,暫時放棄對CPU的使用權(quán),停止執(zhí)行,止匕時
進入阻塞狀態(tài),直到其進入到就緒狀態(tài),才有機會再次被CPU調(diào)用以進入到運行狀態(tài)。
。阻塞的情況分三種:
。(一).等待阻塞:運行狀態(tài)中的線程執(zhí)行wait。方法,JVM會把該線程放入等待隊列(waitting
queue)中,使本線程進入到等待阻塞狀態(tài);
。(二).同步阻塞:線程在獲取synchronized同步鎖失敗(因為鎖被其它線程所占用),,貝!JJVM
會把該線程放入鎖池(lockpool)*,線程會進入同步阻塞狀態(tài);
。(三).其他阻塞:通過調(diào)用線程的sleep。或join?;虬l(fā)出了I/O請求時,線程會進入到阻塞狀
態(tài)。當sleep。狀態(tài)超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉(zhuǎn)入
就緒狀態(tài)。
?死亡(dead)(結(jié)束):線程run()、main。方法執(zhí)行結(jié)束,或者因異常退出了run()方法,則該線程結(jié)束
生命周期。死亡的線程不可再次復生。
24.Java中用到的線程調(diào)度算法是什么?
?計算機通常只有一個CPU,在任意時刻只能執(zhí)行一條機器指令,每個線程只有獲得CPU的使用權(quán)
才能執(zhí)行指令。所謂多線程的并發(fā)運行,其實是指從宏觀上看,各個線程輪流獲得CPU的使用
權(quán),分別執(zhí)行各自的任務。在運行池中,會有多個處于就緒狀態(tài)的線程在等待CPU,JAVA虛擬機
的一項任務就是負責線程的調(diào)度,線程調(diào)度是指按照特定機制為多個線程分配CPU的使用權(quán)。
(Java是由JVM中的線程計數(shù)器來實現(xiàn)線程調(diào)度)
?有兩種調(diào)度模型:分時調(diào)度模型和搶占式調(diào)度模型。
。分時調(diào)度模型是指讓所有的線程輪流獲得cpu的使用權(quán),并且平均分配每個線程占用的CPU
的時間片這個也比較好理解。
。Java虛擬機采用搶占式調(diào)度模型,是指優(yōu)先讓可運行池中優(yōu)先級高的線程占用CPU,如果可
運行池中的線程優(yōu)先級相同,那么就隨機選擇一個線程,使其占用CPU。處于運行狀態(tài)的線
程會一直運行,直至它不得不放棄CPU。
25.線程的調(diào)度策略
線程調(diào)度器選擇優(yōu)先級最高的線程運行,但是,如果發(fā)生以下情況,就會終止線程的運行:
?(1)線程體中調(diào)用了yield方法讓出了對cpu的占用權(quán)利
?(2)線程體中調(diào)用了sleep方法使線程進入睡眠狀態(tài)
?(3)線程由于I0操作受到阻塞
?(4)另夕一個更高優(yōu)先級線程出現(xiàn)
?(5)在支持時間片的系統(tǒng)中,該線程的時間片用完
26.什么是線程調(diào)度器(ThreadScheduler)和時間分片(TimeSlicing)?
?線程調(diào)度器是一個操作系統(tǒng)服務,它負責為Runnable狀態(tài)的線程分配CPU時間。一旦我們創(chuàng)建
一個線程并啟動它,它的執(zhí)行便依賴于線程調(diào)度器的實現(xiàn).
?時間分片是指將可用的CPU時間分配給可用的Runnable線程的過程。分配CPU時間可以基于線
程優(yōu)先級或者線程等待的時間。
?線程調(diào)度并不受到Java虛擬機控制,所以由應用程序來控制它是更好的選擇(也就是說不要讓你
的程序依賴于線程的優(yōu)先級)。
27.請說出與線程同步以及線程調(diào)度相關的方法。
?(Dwait():使一個線程處于等待(阻塞)狀態(tài),并且釋放所持有的對象的鎖;
?(2)sleep。:使一個正在運行的線程處于睡眠狀態(tài),是一個靜態(tài)方法,調(diào)用此方法要處理
InterruptedException異常;
?(3)notify。:喚醒一個處于等待狀態(tài)的線程,當然在調(diào)用此方法的時候,并不能確切的喚醒某一
個等待狀態(tài)的線程,而是由JVM確定喚醒哪個線程,而且與優(yōu)先級無關;
?(4)notityAIIO:喚醒所有處于等待狀態(tài)的線程,該方法并不是將對象的鎖給所有線程,而是讓它
們競爭,只有獲得鎖的線程才能進入就緒狀態(tài);
28.sleep()和wait()有什么區(qū)別?
兩者都可以暫停線程的執(zhí)行
?類的不同:sleep。是Thread線程類的靜態(tài)方法,wait。是Object類的方法。
?是否釋放鎖:sleep。不釋放鎖;wait。釋放鎖。
?用途不同:Wait通常被用于線程間交互/通信,sleep通常被用于暫停執(zhí)行。
?用法不同:wait()方法被調(diào)用后,線程不會自動蘇醒,需要別的線程調(diào)用同一個對象上的notify。
或者notifyAII()方法。sleep。方法執(zhí)行完成后,線程會自動蘇醒?;蛘呖梢允褂脀ait(long
timeout)超時后線程會自動蘇醒。
29.你是如何調(diào)用wait。方法的?使用if塊還是循環(huán)?為什么?
?處于等待狀態(tài)的線程可能會收到錯誤警報和偽喚醒,如果不在循環(huán)中檢杳等待條件,程序就會在沒
有滿足結(jié)束條件的情況下退出。
?wait。方法應該在循環(huán)調(diào)用,因為當線程獲取到CPU開始執(zhí)行的時候,其他條件可能還沒有滿
足,所以在處理前,循環(huán)檢測條件是否滿足會更好。下面是一段標準的使用wait和notify方法的
代碼:
synchronized(monitor){
//判斷條件謂詞是否得到滿足
while(!locked){
//等待喚醒
monitor;
)
//處理其他的業(yè)務邏輯
30.為什么線程通信的方法wait(),notify。和notifyAII。被定義在Object類里?
?因為Java所有類的都繼承了Object,Java想讓任何對象都可以作為鎖,并且wait(),notify。等方法
用于等待對象的鎖或者喚醒線程,在Java的線程中并沒有可供任何對象使用的鎖,所以任意對象
調(diào)用方法一定定義在Object類中。
?有的人會說,既然是線程放棄對象鎖,那也可以把wait。定義在Thread類里面啊,新定義的線程繼
承于Thread類,也不需要重新定義wait()方法的實現(xiàn)。然而,這樣做有一個非常大的問題,一個線
程完全可以持有很多鎖,你一個線程放棄鎖的時候,到底要放棄哪個鎖?當然了,這種設計并不是
不能實現(xiàn),只是管理起來更加復雜。
31.為什么wait。,notify。和notifyAH。必須在同步方法或者同步塊中被調(diào)用?
?當一個線程需要調(diào)用對象的wait。方法的時候,這個線程必須擁有該對象的鎖,接著它就會釋放這
個對象鎖并進入等待狀態(tài)直到其他線程調(diào)用這個對象上的notify。方法。同樣的,當一個線程需要
調(diào)用對象的notify。方法時,它會釋放這個對象的鎖,以便其他在等待的線程就可以得到這個對象
鎖。由于所有的這些方法都需要線程持有對象的鎖,這樣就只能通過同步來實現(xiàn),所以他們只能在
同步方法或者同步塊中被調(diào)用。
32.Thread類中的yield方法有什么作用?
?使當前線程從執(zhí)行狀態(tài)(運行狀態(tài))變?yōu)榭蓤?zhí)行態(tài)(就緒狀態(tài)).
?當前線程到了就緒狀態(tài),那么接下來哪個線程會從就緒狀態(tài)變成執(zhí)行狀態(tài)呢?可能是當前線程,也
可能是其他線程,看系統(tǒng)的分配了。
33.為什么Thread類的sleep。和yield()方法是靜態(tài)的?
?Thread類的sleep。和yield。方法將在當前正在執(zhí)行的線程上運行。所以在其他處于等待狀態(tài)的線
程上調(diào)用這些方法是沒有意義的。這就是為什么這些方法是靜態(tài)的。它們可以在當前正在執(zhí)行的線
程中工作,并避免程序員錯誤的認為可以在其他^運行線程調(diào)用這些方法。
34.線程的sleep。方法和yield。方法有什么區(qū)別?
?(Dsleep。方法給其他線程運行機會時不考慮線程的優(yōu)先級,因此會給低優(yōu)先級的線程以運行的
機會;yield。方法只會給相同優(yōu)先級或更高優(yōu)先級的線程以運行的機會;
?(2)線程執(zhí)行sleep。方法后轉(zhuǎn)入阻塞(blocked)狀態(tài),而執(zhí)行yield。方法后轉(zhuǎn)入就緒
(ready)狀態(tài);
?(3)sleep。方法聲明拋出InterruptedException,而yield。方法沒有聲明任何異常;
?(4)sleep。方法比yield。方法(跟操作系統(tǒng)CPU調(diào)度相關)具有更好的可移植性,通常不建議
使用yield。方法來控制并發(fā)線程的執(zhí)行。
35.如何停止一個正在運行的線程?
?在java中有以下3種方法可以終止正在運行的線程:
。使用退出標志,使線程正常退出,也就是當run方法完成后線程終止。
。使用Stop方法強行終止,但是不推薦這個方法,因為stop和suspend及resume一樣都是過期
作廢的方法。
。使用interrupt方法中斷線程。
36.Java中interrupted和islnterrupted方法的區(qū)別?
?interrupt:用于中斷線程。調(diào)用該方法的線程的狀態(tài)為將被置為"中斷"狀態(tài)。
注意:線程中斷僅僅是置線程的中斷狀態(tài)位,不會停止線程。需要用戶自己去監(jiān)視線程的狀態(tài)為并做處
理。支持線程中斷的方法他就是線程中斷后會拋出interruptedException的方法)就是在監(jiān)視線程的
中斷狀態(tài),一旦線程的中斷狀態(tài)被置為"中斷狀態(tài)",就會拋出中斷異常.
?interrupted:是靜態(tài)方法,查看當前中斷信號是true還是faIse并且清除中斷信號。如果一個線程
被中斷了,第一次調(diào)用interrupted則返回true,第二次和后面的就返回false了。
?islnterrupted:是可以返回當前中斷信號是true還是false,與interrupt最大的差別
37.什么是阻塞式方法?
?阻塞式方法是指程序會一直等待該方法完成期間不做其他事情,Serversocket的accept。方法就是
一直等待客戶端連接.這里的阻塞是指調(diào)用結(jié)果返回之前,當前線程會被掛起,直到得到結(jié)果之后
才會返回。此外,還有異步和非阻塞式方法在任務完成前就返回。
38.Java中你怎樣喚醒一個阻塞的線程?
?首先,wait。、notify。方法是針對對象的,調(diào)用任意對象的wait。方法都將導致線程阻塞,阻塞
的同時也將釋放該對象的鎖,相應地,調(diào)用任意對象的notify。方法則將隨機解除該對象阻塞的線
程,但它需要重新獲取該對象的鎖,直到獲取成功才能往下執(zhí)行;
?其次,wait、notify方法必須在synchronized塊或方法中被調(diào)用,并且要保證同步塊或方法的鎖
對象與調(diào)用wait、notify方法的對象是同一個,如此一來在調(diào)用wait之前當前線程就已經(jīng)成功獲
取某對象的鎖,執(zhí)行wait阻塞后當前線程就將之前獲取的對象鎖釋放。
39.notifyO和notifyAIK)有什么區(qū)別?
?如果線程調(diào)用了對象的wait()方法,那么線程便會處于該對象的等待池中,等待池中的線程不會去
競爭該對象的鎖。
?notifyAIK)會喚醒所有的線程,notify。只會喚醒一個線程。
?notifyAIK)調(diào)用后,會將全部線程由等待池移到鎖池,然后參與鎖的競爭,競爭成功則繼續(xù)執(zhí)行,
如果不成功則留在鎖池等待鎖被釋放后再次參與競爭。而notify。只會喚醒一個線程,具體喚醒哪
一個線程由虛擬機控制。
40.如何在兩個線程間共享數(shù)據(jù)?
?在兩個線程間共享變量即可實現(xiàn)共享。
一般來說,共享變量要求變量本身是線程安全的,然后在線程內(nèi)使用的時候,如果有對共享變量的復合操作,那么
也得保證復合操作的線程安全性。
41.Java如何實現(xiàn)多線程之間的通訊和協(xié)作?
?可以通過中斷和共享變量的方式實現(xiàn)線程間的通訊和I協(xié)作
?比如說最經(jīng)典的生產(chǎn)者-消費者模型:當隊列滿時,生產(chǎn)者需要等待隊列有空間才能繼續(xù)往里面放
入商品,而在等待的期間內(nèi),生產(chǎn)者必須釋放對臨界資源(即隊列)的占用權(quán).因為生產(chǎn)者如果不
釋放對臨界資源的占用權(quán),那么消費者就無法消費隊列中的商品,就不會讓隊列有空間,那么生產(chǎn)
者就會一直無限等待下去。因此,一般情況下,當隊列滿時,會讓生產(chǎn)者交出對臨界資源的占用
權(quán),并進入掛起狀態(tài).然后等待消費者消費了商品,然后消費者通知生產(chǎn)者隊列有空間了。同樣
地,當隊列空時,消費者也必須等待,等待生產(chǎn)者通知它隊列中有商品了。這種互相通信的過程就
是線程間的協(xié)作。
?Java中線程通信協(xié)作的最常見方式:
o—.syncrhoized加鎖的線程的Object類的wait()/notify()/notifyAII()
■二.ReentrantLock類力口鎖的線程的Condition類的await()/signal()/signalAII()
?線程間直接的數(shù)據(jù)交換:
。三.通過管道進行線程間通信:字節(jié)流、字符流
42.同步方法和同步塊,哪個是更好的選擇?
?同步塊是更好的選擇,因為它不會鎖住整個對象(當然你也可以讓它鎖住整個對象).同步方法會
鎖住整個對象,哪怕這個類中有多個不相關聯(lián)的同步塊,這通常會導致他們停止執(zhí)行并需要等待獲
得這個對象上的鎖。
?同步塊更要符合開放調(diào)用的原則,只在需要鎖住的代碼塊鎖住相應的對象,這樣從側(cè)面來說也可以
避免死鎖。
請知道一條原則:同步的范圍越小越好。
43.什么是線程同步和線程互斥,有哪幾種實現(xiàn)方式?
?當一個線程對共享的數(shù)據(jù)進行操作時,應使之成為一個"原子操作",即在沒有完成相關操作之前,
不允許其他線程打斷它,否則,就會破壞數(shù)據(jù)的完整性,必然會得到錯誤的處理結(jié)果,這就是線程
的同步。
?在多線程應用中,考慮不同線程之間的數(shù)據(jù)同步和防止死鎖。當兩個或多個線程之間同時等待對方
釋放資源的時候就會形成線程之間的死鎖。為了防止死鎖的發(fā)生,需要通過同步來實現(xiàn)線程安全。
?線程互斥是指對于共享的進程系統(tǒng)資源,在各單個線程訪問時的排它性。當有若干個線程都要使用
某一共享資源時,任何時刻最多只允許一個線程去使用,其它要使用該資源的線程必須等待,直到
占用資源者釋放該資源。線程互斥可以看成是一種特殊的線程同步。
?線程間的同步方法大體可分為兩類:用戶模式和內(nèi)核模式。顧名思義,內(nèi)核模式就是指利用系統(tǒng)內(nèi)
核對象的單一性來進行同步,使用時需要切換內(nèi)核態(tài)與用戶態(tài),而用戶模式就是不需要切換到內(nèi)核
態(tài),只在用戶態(tài)完成操作。
?用戶模式下的方法有:原子操作(例如一個單一的全局變量),臨界區(qū)。內(nèi)核模式下的方法有:事
件,信號量,互斥量。
?實現(xiàn)線程同步的方法
。同步代碼方法:sychronized關鍵字修飾的方法
。同步代碼塊:sychronized關鍵字修飾的代碼塊
。使用特殊變量域volatile實現(xiàn)線程同步:volatile關犍字為域變量的訪問提供了一種免鎖機制
。使用重入鎖實現(xiàn)線程同步:reentrantlock類是可沖入、互斥、實現(xiàn)了lock接口的鎖他與
sychronized方法具有相同的基本行為和語義
44.在監(jiān)視器(Monitor)內(nèi)部,是如何做線程同步的?程序應該做哪種級別的同
步?
?在java虛擬機中,監(jiān)視器和鎖在Java虛擬機中是一塊使用的。監(jiān)視器監(jiān)視一塊同步代碼塊,確保
一次只有一個線程執(zhí)行同步代碼塊。每一個監(jiān)視器都和一個對象引用相關聯(lián)。線程在獲取鎖之前不
允許執(zhí)行同步代碼。
?一旦方法或者代碼塊被synchronized修飾,那么這個部分就放入了監(jiān)視器的監(jiān)視區(qū)域,確保一次
只能有一個線程執(zhí)行該部分的代碼,線程在獲取鎖之前不允許執(zhí)行該部分的代碼
?另外java還提供了顯式監(jiān)視器(Lock)和隱式監(jiān)視器(synchronized)兩種鎖方案
45.如果你提交任務時,線程池隊列已滿,這時會發(fā)生什么
?有倆種可能:
(1)如果使用的是無界隊歹ULinkedBlockingQueue,也就是無界隊列的話,沒關系,繼續(xù)添加任務到
阻塞隊列中等待執(zhí)行,因為LinkedBlockingQueue可以近乎認為是一個無窮大的隊列,可以無限存放
彳鎊
(2)如果使用的是有界隊列比如ArrayBlockingQueue,任務首先會被添加到ArrayBlockingQueue
中,ArrayBlockingQueue滿了,會根據(jù)maximumPoolSize的值增加線程數(shù)量,如果增加了線程數(shù)量
還是處理不過來,ArrayBlockingQueue繼續(xù)滿,那么則會使用拒絕策略RejectedExecutionHandler
處理滿了的任務,默認是AbortPolicy
46.什么叫線程安全?servlet是線程安全嗎?
?線程安全是編程中的術(shù)語,指某個方法在多線程環(huán)境中被調(diào)用時,能夠正確地處理多個線程之間的
共享變量,使程序功能正確完成。
?Servlet不是線程安全的,servlet是單實例多線程的,當多個線程同時訪問同f方法,是不能保
證共享變量的線程安全性的。
?Struts2的action是多實例多線程的,是線程安全的,每個請求過來都會new一個新的action分
配給這個請求,請求完成后銷毀。
?SpringMVC的Controller是線程安全的嗎?不是的,和Servlet類似的處理流程。
?Struts2好處是不用考慮線程安全問題;Servlet和SpringMVC需要考慮線程安全問題,但是性能
可以提升不用處理太多的gc,可以使用ThreadLocal來處理多線程的問題。
47.在Java程序中怎么保證多線程的運行安全?
?方法一:使用安全類,比如java.util.concurrent下的類,使用原子類Atomiclnteger
?方法二:使用自動鎖synchronized。
?方法三:使用手動鎖Lock。
?手動鎖Java示例代碼如下:
Locklock=newReentrantLock();
lock.lock();
try{
System,out.printing獲得鎖”);
}catch(Exceptione){
//TODO:handleexception
}finally{
System.out.printin(“釋放鎖”);
lock.unlock();
)
48.你對線程優(yōu)先級的理解是什么?
?每一個線程都是有優(yōu)先級的,一般來說,高優(yōu)先級的線程在運行時會具有優(yōu)先權(quán),但這依賴于線程
調(diào)度的實現(xiàn),這個實現(xiàn)是和操作系統(tǒng)相關的(OSdependent)。我們可以定義線程的優(yōu)先級,但是
這并不能保證高優(yōu)先級的線程會在低優(yōu)先級的線程前執(zhí)行。線程優(yōu)先級是一個int變量(從1-10),
1代表最低優(yōu)先級,10代表最高優(yōu)先級。
?Java的線程優(yōu)先級調(diào)度會委托給操作系統(tǒng)去處理,所以與具體的操作系統(tǒng)優(yōu)先級有關,如非特別
需要,一般無需設置線程優(yōu)先級。
?當然,如果你真的想設置優(yōu)先級可以通過setPriority()方法設置,但是設置了不一定會該變,這個
是不準確的
49.線程類的構(gòu)造方法、靜態(tài)塊是被哪個線程調(diào)用的
?這是一個非常刁鉆和狡猾的問題。請記?。壕€程類的構(gòu)造方法、靜態(tài)塊是被new這個線程類所在
的線程所調(diào)用的,而run方法里面的代碼才是被線程自身所調(diào)用的。
?如果說上面的說法讓你感到困惑,那么我舉個例子,假設Thread2中new了Threadl,main函
數(shù)中new了Thread2,那么:
(1)Thread2的構(gòu)造方法、靜態(tài)塊是main線程調(diào)用的,Thread2的run。方法是Thread2自己調(diào)用的
(2)Thread1的構(gòu)造方法、靜態(tài)塊是Thread2調(diào)用的,Thread1的run。方法是ThreacH自己調(diào)用的
50.Java中怎么獲取一份線程dump文件?你如何在Java中獲取線程堆棧?
?Dump文件是進程的內(nèi)存鏡像??梢园殉绦虻膱?zhí)行狀態(tài)通過調(diào)試器保存到dump文件中。
?在Linux下,你可以通過命令kill-3PID(Java進程的進程ID)來獲取Java應用的dump文件。
?在Windows下,你可以按下Ctrl+Break來獲取。這樣JVM就會將線程的dump文件打E倒標
準輸出或錯誤文件中,它可能打印在控制臺或者日志文件中,具體位置依賴應用的配置。
51.一個線程運行時發(fā)生異常會怎樣?
?如果異常沒有被捕獲該線程將會停止執(zhí)行。Thread.UncaughtExceptionHandler是用于處理未捕
獲異常造成線程突然中斷情況的一個內(nèi)嵌接口。當一個未捕獲異常將造成線程中斷的時候,JVM
會使用Thread.getUncaughtExceptionHandler。來查詢線程的UncaughtExceptionHandler并將
線程和異常作為參數(shù)傳遞給handler的uncaughtException()方法進行處理。
52.Java線程數(shù)過多會造成什么異常?
?線程的生命周期開銷非常高
?消耗過多的CPU
資源如果可運行的線程數(shù)量多于可用處理器的數(shù)量,那么有線程將會被閑置。大量空閑的線程會占
用許多內(nèi)存,給垃圾回收器帶來壓力,而且大量的線程在競爭CPU資源時還將產(chǎn)生其他性能的開
銷。
?降低穩(wěn)定'由VM
在可創(chuàng)建線程的數(shù)量上存在一個限制,這個限制值將隨著平臺的不同而不同,并且承受著多個因素
制約,包括JVM的啟動參數(shù)、Thread構(gòu)造函數(shù)中請求棧的大小,以及底層操作系統(tǒng)對線程的限制
等。如果破壞了這些限制,那么可能拋出。戊0£1\/16巾。》£汗。「異常。
53.多線程的常用方法
方法名描述
sleepO強迫一個線程睡眠N毫秒
isAlive()判哈個編魄否存活。
join()等待線程終止。
activeCount()程序中活躍的線程數(shù)。
enumerateO枚舉程序中的線程.
currentThreadO得到當前線程。
isDaemonO一個線程是否為守護線程.
setDaemon()設置一個線程為守護線程。
setName()為線程設置一個名稱。
wait()強迫一個線程等待。
notifyO通知一個線程繼續(xù)運行。
setPriorityO設置一個線程的優(yōu)先級。
并發(fā)理論
1.Java中垃圾回收有什么目的?什么時候進行垃圾回收?
?垃圾回收是在內(nèi)存中存在沒有引用的對象或超過作用域的對象時進行的.
?垃圾回收的目的是識別并且丟棄應用不再使用的對象來釋放和重用資源。
2.線程之間如何通信及線程之間如何同步
?在并發(fā)編程中,我們需要處理兩個關鍵問題:線程之間如何通信及線程之間如何同步。通信是指線
程之間以如何來交換信息。一般線程之間的通信機制有兩種:共享內(nèi)存和消息傳遞。
?Java的并發(fā)采用的是共享內(nèi)存模型,Java線程之間的通信總是隱式進行,整個通信過程對程序員完
全透明。如果編寫多線程程序的Java程序員不理解隱式進行的線程之間通信的工作機制,很可能會
遇到各種奇怪的內(nèi)存可見性問題。
3.Java內(nèi)存模型
?共享內(nèi)存模型指的就是Java內(nèi)存模型(簡稱JMM),JMM決定一個線程對共享變量的寫入時,能對另一
個線程可見。從抽象的角度來看,JMM定義了線程和主內(nèi)存之間的抽象關系:線程之間的共享變
量存儲在主內(nèi)存(mainmemory)中,每個線程都有一個私有的本地內(nèi)存(localmemory),本
地內(nèi)存中存儲了該線程以讀/寫共享變量的副本。本地內(nèi)存是JMM的一個抽象概念,并不真實存
在。它涵蓋了緩存,寫緩沖區(qū),寄存器以及其他的硬件和編譯器優(yōu)化。
?從上圖來看,線程A與線程B之間如要通信的話,必須要經(jīng)歷下面2個步驟:
1.首先,線程A把本地內(nèi)存A中更新過的共享變量刷新到主內(nèi)存中去。
2.然后,線程B到主內(nèi)存中去讀取線程A之前已更新過的共享變量。
下面通過示意圖來說明線程之間的通信
主內(nèi)存
:c-l
?總結(jié):什么是Java內(nèi)存模型:java內(nèi)存模型簡稱jmm,定義了一個線程對另一個線程可見。共享變
量存放在主內(nèi)存中,每個線程都有自己的本地內(nèi)存,當多個線程同時訪問一個數(shù)據(jù)的時候,可能本
地內(nèi)存沒有及時刷新到主內(nèi)存,所以就會發(fā)生線程安全問題。
4.如果對象的引用被置為null,垃圾收集器是否會立即釋放對象占用的內(nèi)存?
?不會,在下一個垃圾回調(diào)周期中,這個對象將是被可回收的。
?也就是說并不會立即被垃圾收集器立刻回收,而是在下一次垃圾回收時才會釋放其占用的內(nèi)存。
5.finalize。方法什么時候被調(diào)用?析構(gòu)函數(shù)(finalization)的目的是什么?
?1.垃圾回收器(garbagecolector)決定回收某對象時,就會運行該對象的finalize。方法;
finalize是Object類的一?"方法,該方法在Object類中的聲明protectedvoidfinalize()throws
Throwable{)在垃圾回收器執(zhí)行時會調(diào)用被回收對象的finalize。方法,可以覆蓋此方法來實現(xiàn)對
其資源的回收。注意:一旦垃圾回收器準備釋放對象占用的內(nèi)存,將首先調(diào)用該對象的finalize。方
法,并且下一次垃圾回收動作發(fā)生時,才真正回收對象占用的內(nèi)存空間
?1.GC本來就是內(nèi)存回收了,應用還需要在finalization做什么呢?答案是大部分時候,什么都
不用做(也就是不需要重載)。只有在某些很特殊的情況下,比如你調(diào)用了一些native的方法
(一般是C寫的),可以要在finaliztion里去調(diào)用C的釋放函數(shù)。
。Finalizetion主要用來釋放被對象占用的資源(不是指內(nèi)存,而是指其他資源,比如文件(File
Handle),端口(ports)、數(shù)據(jù)庫連接(DBConnection)等)。然而,它不能真正有效地工作。
6.什么是重排序
?程序執(zhí)行的順序按照代碼的先后I放序執(zhí)行。
?一般來說處理器為了提高程序運行效率,可能會對輸入代碼進行優(yōu)化,進行重新排序(重排序),
它不保證程序中各個語句的執(zhí)行先后順序同代碼中的W頁序一致,但是它會保證程序最終執(zhí)行結(jié)果和
代碼順序執(zhí)行的結(jié)果是一致的。
inta=5//語句1
intr=3//語句2
a=a+2//語句3
r=a*a;//語句4
?則因為重排序,他還可能執(zhí)行順序為(這里標注的是語句的執(zhí)行順序)2-1-3-4,1-3-2-4但絕不
可能2-1-4-3,因為這打破了依賴關系。
?顯然重排序?qū)尉€程運行是不會有任何問題,但是多線程就不一定了,所以我們在多線程編程時就
得考慮這個問題了。
7.重排序?qū)嶋H執(zhí)行的指令步驟
1.編譯器優(yōu)化的重排序。編譯器在不改變單線程程序語義的前提下,可以重新安排語句的執(zhí)行順序。
2.指令級并行的重排序?,F(xiàn)代處理器采用了指令級并行技術(shù)(ILP)來將多條指令重疊執(zhí)行。如果不
存在數(shù)據(jù)依賴性,處理器可以改變語句對應機器指令的執(zhí)行質(zhì)序.
3.內(nèi)存系統(tǒng)的重排序。由于處理器使用緩存和讀/寫緩沖區(qū),這使得加載和存儲操作看上去可能是在
亂序執(zhí)行.
?這些重排序?qū)τ趩尉€程沒問題,但是多線程都可能會導致多線程程序出現(xiàn)內(nèi)存可見性問題。
8.重排序遵守的規(guī)則
?as-if-serial:
1.不管怎么排序,結(jié)果不能改變
2.不存在數(shù)據(jù)依賴的可以被編譯器和處理器重排序
3.一個操作依賴兩個操作,這兩個操作如果不存在依賴可以重排序
4.單線程根據(jù)此規(guī)則不會有問題,但是重排序后多線程會有問題
9.as-if-serial規(guī)則和happens-before規(guī)則的區(qū)別
?as-if-serial語義保證單線程內(nèi)程序的執(zhí)行結(jié)果不被改變,h叩pens-before關系保證正確同步的多
線程程序的執(zhí)行結(jié)果不被改變。
?as-if-serial語義給編寫單線程程序的程序員創(chuàng)造了一個幻境:單線程程序是按程序的J1I頁序來執(zhí)行
的。happens-before關系給編寫正確同步的多線程程序的程序員創(chuàng)造了一個幻境:正確同步的多
線程程序是按happens-before指定的順序來執(zhí)行的.
?as-if-serial語義和happens-before這么做的目的,都是為了在不改變程序執(zhí)行結(jié)果的前提下,盡
可能地提高程序執(zhí)行的并行度。
10.并發(fā)關鍵字synchronized?
?在Java中,synchronized關鍵字是用來控制線程同步的,就是在多線程的環(huán)境下,控制
synchronized代碼段不被多個線程同時執(zhí)行。synchronized可以修飾類、方法、變量。
?另外,在Java早期版本中,synchronized屬于重量級鎖,效率低下,因為監(jiān)視器鎖(monitor)
是依賴于底層的操作系統(tǒng)的MutexLock來實現(xiàn)的,Java的線程是映射到操作系統(tǒng)的原生線程之上
的。如果要掛起或者喚醒一個線程,都需要操作系統(tǒng)幫忙完成,而操作系統(tǒng)實現(xiàn)線程之間的切換時
需要從用戶態(tài)轉(zhuǎn)換到內(nèi)核態(tài),這個狀態(tài)之間的轉(zhuǎn)換需要相對比較長的時間,時間成本相對較高,這
也是為什么早期的synchronized效率低的原因。慶幸的是在Java6之后Java官方對從JVM層面
對synchronized較大優(yōu)化,所以現(xiàn)在的synchronized鎖效率也優(yōu)化得很不錯了。JDK1.6對鎖的
實現(xiàn)引入了大量的優(yōu)化,如自旋鎖、適應性自旋鎖、鎖消除、鎖粗化、偏向鎖、輕量級鎖等技術(shù)來
減少鎖操作的開銷。
11.說說自己是怎么使用synchronized關鍵字,在項目中用到了嗎
synchronized關鍵字最主要的三種使用方式:
?修飾實例方法:作用于當前對象實例加鎖,進入同步代碼前要獲得當前對象實例的鎖
?修飾靜態(tài)方法:也就是給當前類加鎖,會作用于類的所有對象實例,因為靜態(tài)成員不屬于任何一個
實例對象,是類成員(static表明這是該類的一個靜態(tài)資源,不管new了多少個對象,只有一
份)。所以如果f線程A調(diào)用一個實例對象的非靜態(tài)synchronized方法,而線程B需要調(diào)用這個
實例對象所屬類的靜態(tài)synchronized方法,是允許的,不會發(fā)生互斥現(xiàn)象,因為訪問靜態(tài)
synchronized方法占用的鎖是當前類的鎖,而訪問非靜態(tài)synchronized方法占用的鎖是當前實
例對象鎖。
?修飾代碼塊:指定加鎖對象,對給定對象加鎖,進入同步代碼庫前要獲得給定對象的鎖。
總結(jié):synchronized關鍵字加到static靜態(tài)方法和synchronized(class)代碼塊上都是是給Class
類上鎖。synchronized關鍵字加到實例方法上是給對象實例上鎖。盡量不要使用synchronized(String
a)因為JVM中,字符串常量池具有緩存功能!
12.單例模式了解嗎?給我解釋一下雙重檢驗鎖方式實現(xiàn)單例模式!
雙重校驗鎖實現(xiàn)對象單例(線程安全)
說明:
?雙鎖機制的出現(xiàn)是為了解決前面同步問題和性能問題,看下面的代碼,簡單分析下確實是解決了多
線程并行進來不會出現(xiàn)重復new對象,而且也實現(xiàn)了懶加載
publicclassSingleton{
privatevolatilestaticSingletonuniqueinstance;
privateSingleton(){}
publicstaticSingletongetuniquelnstance(){
//先判斷對象是否已經(jīng)實例過,沒有實例化過才進入加鎖代碼
if(uniqueinstance==null){
//類對象加鎖
synchronized(Singleton.class){
if(uniqueinstance==null){
uniqueinstance=newSingleton。;
)
)
)
returnuniqueinstance;
)
另外,需要注意uniqueinstance采用volatile關鍵字修飾也是很有必要。
?uniqueinstance采用volatile關鍵字修飾也是很有必要的,uniqueinstance=newSingleton();
這段代碼其實是分為三步執(zhí)行:
1.為uniquelnstance分配內(nèi)存空間
2.初始化uniqueinstance
3.將uniqueinstance指向分配的內(nèi)存地址
但是由于具有指令重排的特性,執(zhí)行順序有可能變成指令重排在單線程環(huán)境下不會出現(xiàn)問題,
JVM1->3->20
但是在多線程環(huán)境下會導致一個線程獲得還沒有初始化的實例。例如,線程T1執(zhí)行J'1和3,此時丁2調(diào)用
getuniquelnstancef)后發(fā)現(xiàn)uniqueinstance不為空,因此返回uniqueinstance,但此時
uniqueinstance還未被初始化。
使用volatile可以禁止JVM的指令重排,保證在多線程環(huán)境下也能正常運行。
13.說一下synchronized底層實現(xiàn)原理?
?Synchronized的語義底層是通過一個monitor(監(jiān)視器鎖)的對象來完成,
?每個對象有一個監(jiān)視器鎖(monitor)。每個Synchronized修飾過的代碼當它的monitor被占用時就
會處于鎖定狀態(tài)并且嘗試獲取monitor的所有權(quán),過程:
1、如果monitor的進入數(shù)為0,貝舷線程進入monitor,然后將進入數(shù)設置為1,該線程即為
monitor的所有者。
2、如果線程已經(jīng)占有該monitor,只是重新進入,則進入monitor的進入數(shù)加1.
3、如果其他線程已經(jīng)占用了monitor,則該線程進入阻塞狀態(tài),直到monitor的進入數(shù)為0,再
重新嘗試獲取monitor的所有權(quán)。
synchronized是可以通過反匯編指令javap命令,杏看相應的字節(jié)碼文件。
14.synchronized可重入的原理
?重入鎖是指一個線程獲取到該鎖之后,該線程可以繼續(xù)獲得該鎖。底層原理維護一個計數(shù)器,當線
程獲取該鎖時,計數(shù)器加一,再次獲得該鎖時繼續(xù)加一,釋放鎖時,計數(shù)器減一,當計數(shù)器值為o
時,表明該鎖未被任何線程所持有,其它線程可以競爭獲取鎖。
15.什么是
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025-2030年中國產(chǎn)業(yè)園區(qū)物業(yè)管理行業(yè)全國市場開拓戰(zhàn)略制定與實施研究報告
- 2025-2030年中國宴會用餐行業(yè)開拓第二增長曲線戰(zhàn)略制定與實施研究報告
- 2025-2030年中國玩具行業(yè)商業(yè)模式創(chuàng)新戰(zhàn)略制定與實施研究報告
- 自動噴水滅火系統(tǒng)設計規(guī)范
- 服裝個性訂制消費愿望調(diào)查
- 2025-2030年中國電力物聯(lián)網(wǎng)行業(yè)市場全景評估及發(fā)展趨向研判報告
- 2025年中國野牡丹行業(yè)市場深度分析及未來發(fā)展趨勢預測報告
- 江蘇省南京市玄武區(qū)2023-2024學年九年級上學期期末化學試題
- 產(chǎn)品檢驗知識培訓課件
- 寧夏銀川一中、昆明一中2023屆高三聯(lián)合二模考試數(shù)學(理)試題 附答案
- 0的認識和加、減法(說課稿)-2024-2025學年一年級上冊數(shù)學人教版(2024)001
- 2025年廣西旅發(fā)南國體育投資集團限公司招聘高頻重點提升(共500題)附帶答案詳解
- 2024-2025學年銅官山區(qū)數(shù)學三年級第一學期期末調(diào)研試題含解析
- 江西省2023-2024學年高二上學期期末教學檢測數(shù)學試題 附答案
- 碳匯計量與監(jiān)測技術(shù)智慧樹知到期末考試答案章節(jié)答案2024年浙江農(nóng)林大學
- 可用性控制程序
- GB/T 17554.1-2006識別卡測試方法第1部分:一般特性測試
- 說明書hid500系列變頻調(diào)速器使用說明書s1.1(1)
- 橫版榮譽證書模板可修改打印 (9)
- 建設銀行股份關聯(lián)交易申報及信息披露系統(tǒng)操作手冊新一代
- 建筑工程施工勞務清包工合同
評論
0/150
提交評論