1印荔、開啟線程的三種方式?
方式一:繼承thread
public class First extends Thread {
public void run(){
System.out.println("first thread ..");
}
}
@Test
public void firstTest(){
new First().start();
}
方式二:實(shí)現(xiàn)Runnable接口
public class RunableTest implements Runnable {
@Override
public void run() {
System.out.println("runable thread ..");
}
}
@Test
public void runableTest(){
new Thread(new RunableTest()).start();
}
方式三:通過Callable和Future創(chuàng)建線程
public class Fucture implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("Fucture thread ..");
return 1;
}
}
@Test
public void runableFucture() {
Fucture fucture = new Fucture();
FutureTask<Integer> futureTask = new FutureTask<>(fucture);
new Thread(futureTask, "有返回").start();
}
2详羡、多線程同步機(jī)制的理解仍律?
在多線程情況下盡量采用系統(tǒng)安全的類,比如Vector
,StringBuffer
,hashTable
,stack
能保證一般情況下同步不會出現(xiàn)問題实柠。
如果沒法用系統(tǒng)類進(jìn)行規(guī)避的情況需要了解深入一點(diǎn)了解同步鎖機(jī)制
首先討論Synchronized關(guān)鍵字水泉,從鎖的本質(zhì)看分為兩類:
??1、鎖類的對象實(shí)例窒盐,針對于某個具體實(shí)例普通方法/語句塊的互斥草则,簡稱對象鎖;
??2蟹漓、鎖類的Class對象炕横,針對于Class類靜態(tài)方法/語句塊的互斥,簡稱類鎖葡粒;
??方法鎖和語句塊鎖只是一種展現(xiàn)形式份殿,最終還是鎖的當(dāng)前的實(shí)例對象或者class對象
ReentrantLock (可重入鎖)
??與Synchronized
的實(shí)現(xiàn)原理類似,采用的都是互斥同步策略嗽交,用法和實(shí)現(xiàn)效果上來說也很相似伯铣,也具備可重入的特性猾浦。
??不同點(diǎn)是动猬,Sychronized
是原生語法層面上同步控制,其顆粒度更大垦页;相比而言掌唾,ReentranLock
是從API
層面來控制鎖(lock()
與unlock()
方法)放前,開發(fā)者的自主權(quán)更強(qiáng),可控制粒度更細(xì)糯彬,優(yōu)化空間更高
CAS指令與原子性
??與上述兩種互斥同步不同凭语,CAS
是一種原子操作,因?yàn)榛コ馔叫枰~外消耗時間撩扒,屬于悲觀策略似扔,對于極高并發(fā)情況并不適合吨些;而CAS
則屬于樂觀鎖,是通過內(nèi)存值比較和替換來實(shí)現(xiàn)的炒辉。
??CAS
操作包含三個操作數(shù) —— 內(nèi)存位置(V)
豪墅、預(yù)期原值(A)
和新值(B)
。 如果內(nèi)存位置的值與預(yù)期原值相匹配黔寇,那么處理器會自動將該位置值更新為新值 偶器。否則,處理器不做任何操作缝裤。這種實(shí)現(xiàn)主要是cpu層的支持屏轰,因?yàn)?code>CAS是一種系統(tǒng)原語,原語屬于操作系統(tǒng)用語范疇憋飞,是由若干條指令組成的霎苗,用于完成某個功能的一個過程,并且原語的執(zhí)行必須是連續(xù)的榛做,在執(zhí)行過程中不允許被中斷叨粘,也就是說CAS
是一條CPU
的原子指令,不會造成所謂的數(shù)據(jù)不一致問題瘤睹。所以利用CPU
的CAS
指令升敲,同時借助JNI
來完成Java
的非阻塞算法。
volatile 關(guān)鍵字
?一旦一個共享變量(類的成員變量轰传、類的靜態(tài)成員變量)被volatile
修飾之后驴党,那么就具備了兩層語義:
1)保證了不同線程對這個變量進(jìn)行操作時的可見性,即一個線程修改了某個變量的值获茬,這新值對其他線程來說是立即可見的港庄。
2)禁止進(jìn)行指令重排序。
摘自《深入理解Java虛擬機(jī)》:
? “觀察加入volatile關(guān)鍵字和沒有加入volatile
關(guān)鍵字時所生成的匯編代碼發(fā)現(xiàn)恕曲,加入volatile
關(guān)鍵字時鹏氧,會多出一個lock前綴指令
”
lock前綴指令實(shí)際上相當(dāng)于一個內(nèi)存屏障(也稱內(nèi)存柵欄),內(nèi)存屏障會提供3個功能:
1)它確保指令重排序時不會把其后面的指令排到內(nèi)存屏障之前的位置佩谣,也不會把前面的指令排到內(nèi)存屏障的后面把还;即在執(zhí)行到內(nèi)存屏障這句指令時,在它前面的操作已經(jīng)全部完成茸俭;
2)它會強(qiáng)制將對緩存的修改操作立即寫入主存吊履;
3)如果是寫操作,它會導(dǎo)致其他CPU中對應(yīng)的緩存行無效调鬓。
3艇炎、為什么要有線程,而不是僅僅用進(jìn)程腾窝?
? 進(jìn)程:系統(tǒng)進(jìn)行資源分配和調(diào)度的一個最小單位
? 線程:CPU進(jìn)行調(diào)度和分派的最小單位缀踪,它和其他線程共享同一進(jìn)程下的所有資源
可以說進(jìn)程的顆粒度更大居砖,而線程顆粒度更小,更適合并發(fā)執(zhí)行多個任務(wù)以及需要共享資源的情況驴娃。
4奏候、run()和start()方法區(qū)別
很明顯,真正啟動線程的方法就是start()
方法,run()
方法只不過是一個普通的方法托慨,如果直接調(diào)用run()
方法鼻由,還是在主線程順序執(zhí)行暇榴。
5厚棵、如何控制某個方法允許并發(fā)訪問線程的個數(shù)?
使用Semaphore
控制蔼紧, Semaphore mSemaphore = new Semaphore(5);
表示生成五個信號量的實(shí)例婆硬,保證只有5個線程可以同時執(zhí)行;
semaphore.acquire()
請求一個信號量奸例,這個時候信號量個數(shù) -1彬犯;
semaphore.release()
釋放一個信號量,此時信號量個數(shù)+1查吊;
6谐区、在Java中wait和seelp方法的不同;
?wait 和 sleep 都能將線程狀態(tài)變成等待狀態(tài)逻卖,除了這點(diǎn)相同點(diǎn)宋列,其它基本都不同。比如:
? ?1评也、wait()是定義在Object 類中的炼杖,是一個final修飾的非靜態(tài)方法;而sleep是被定義在Thread類中的盗迟,是一個static修飾的靜態(tài)方法坤邪;
? ?2、wait()必須用于同步環(huán)境罚缕,如synchronized方法或者同步代碼塊艇纺、生產(chǎn)-消費(fèi)者隊(duì)列,通常配合notify()方法使用邮弹,wait 讓生產(chǎn)者線程等待喂饥,notify喚醒消費(fèi)者線程,通知隊(duì)列非空肠鲫;而sleep()沒有這個限制员帮。
? ?3、調(diào)用wait()時會釋放當(dāng)前持有的鎖导饲,而sleep()不會釋放任何鎖捞高。
7氯材、談?wù)剋ait/notify關(guān)鍵字的理解
? ?如果線程調(diào)用了對象的wait()
方法,那么線程便會處于該對象的等待池中硝岗,等待池中的線程不會去競爭該對象的鎖氢哮。
? ?當(dāng)有線程調(diào)用了對象的notifyAll()
方法(喚醒所有wait線程)或notify()
方法(只隨機(jī)喚醒一個wait線程),被喚醒的的線程便會進(jìn)入該對象的鎖池中型檀,鎖池中的線程會去競爭該對象鎖冗尤。
? ?優(yōu)先級高的線程競爭到對象鎖的概率大,假若某線程沒有競爭到該對象鎖胀溺,它還會留在鎖池中裂七,唯有線程再次調(diào)用wait()
方法,它才會重新回到等待池中仓坞。而競爭到對象鎖的線程則繼續(xù)往下執(zhí)行背零,直到執(zhí)行完了synchronized
代碼塊,它會釋放掉該對象鎖无埃,這時鎖池中的線程會繼續(xù)競爭該對象鎖徙瓶。
8、什么導(dǎo)致線程阻塞嫉称?
? ?線程阻塞特點(diǎn):該線程放棄CPU的使用侦镇,暫停運(yùn)行
? ?A、線程執(zhí)行了Thread.sleep(int millsecond);
方法织阅,當(dāng)前線程放棄CPU壳繁,睡眠一段時間,然后再恢復(fù)執(zhí)行
? ?B蒲稳、線程執(zhí)行一段同步代碼氮趋,但是尚且無法獲得相關(guān)的同步鎖,只能進(jìn)入阻塞狀態(tài)江耀,等到獲取了同步鎖剩胁,才能回復(fù)執(zhí)行。
? ?C祥国、線程執(zhí)行了一個對象的wait()
方法昵观,直接進(jìn)入阻塞狀態(tài),等待其他線程執(zhí)行notify()
或者notifyAll()
方法舌稀。
? ?D啊犬、線程執(zhí)行某些IO操作,因?yàn)榈却嚓P(guān)的資源而進(jìn)入了阻塞狀態(tài)壁查。比如說監(jiān)聽system.in
觉至,但是尚且沒有收到鍵盤的輸入,則進(jìn)入阻塞狀態(tài)睡腿。
9语御、線程如何關(guān)閉峻贮?
1、使用退出標(biāo)志終止線程:
public class ThreadSafe extends Thread {
public volatile boolean exit = false;
public void run() {
while (!exit){
//do something
}
}
}
ThreadSafe.exit=true;
2应闯、使用interrupt()方法中斷當(dāng)前線程
public class ThreadSafe extends Thread {
public void run() {
while (!isInterrupted()){ //非阻塞過程中通過判斷中斷標(biāo)志來退出
try{
Thread.sleep(5*1000);//阻塞過程捕獲中斷異常來退出
}catch(InterruptedException e){
e.printStackTrace();
break;//捕獲到異常之后纤控,執(zhí)行break跳出循環(huán)。
}
}
}
}
//未阻塞調(diào)用如下代碼
ThreadSafe t=new ThreadSafe ();
t.interrupt();
3碉纺、不推薦的方法stop()船万;該方法因?yàn)槠?/p>
10、講一下java中的同步的方法
? ?thread.stop()調(diào)用之后骨田,創(chuàng)建子線程的線程就會拋出ThreadDeatherror的錯誤耿导,并且會釋放子線程所持有的所有鎖。一般任何進(jìn)行加鎖的代碼塊盛撑,都是為了保護(hù)數(shù)據(jù)的一致性碎节,如果在調(diào)用thread.stop()后導(dǎo)致了該線程所持有的所有鎖的突然釋放(不可控制)捧搞,那么被保護(hù)數(shù)據(jù)就有可能呈現(xiàn)不一致性抵卫,其他線程在使用這些被破壞的數(shù)據(jù)時,有可能導(dǎo)致一些很奇怪的應(yīng)用程序錯誤胎撇。因此介粘,并不推薦使用stop方法來終止線程。
11晚树、數(shù)據(jù)一致性如何保證姻采?
? ?解決這個問題要從線程的安全和線程同步方面去考慮,所以也是對后兩個問題的總結(jié)爵憎,
下面是處理數(shù)據(jù)一致性中幾個關(guān)鍵字的區(qū)別:
在第二個問題中已經(jīng)對這幾種進(jìn)行了說明慨亲;對于實(shí)際開發(fā)而言,Synchronized是比較基礎(chǔ)簡單的宝鼓,涉及同步鎖刑棵;volatile 關(guān)鍵字修飾共享變量,一個線程修改愚铡,其他線程立即可見蛉签;
而通過CAS,我們可以實(shí)現(xiàn)一種非阻塞同步策略沥寥,粒度更細(xì)碍舍,涉及CPU層支持,效率更高邑雅,是很多系統(tǒng)并發(fā)SDK的基礎(chǔ)片橡,如下幾個包:
Atomic:
原子數(shù)據(jù)的構(gòu)建。Locks:
基本的鎖的實(shí)現(xiàn)淮野,最重要的AQS框架和lockSupportConcurrent:
構(gòu)建的一些高級的工具捧书,如線程池狂塘,并發(fā)隊(duì)列等。
12鳄厌、如何保證線程安全荞胡?
見上
13、如何實(shí)現(xiàn)線程同步了嚎?
見上
14泪漂、兩個進(jìn)程同時要求寫或者讀,能不能實(shí)現(xiàn)歪泳?如何防止進(jìn)程的同步萝勤?
? ?可以進(jìn)行同時讀寫,但為了保證數(shù)據(jù)的正確呐伞,必須要針對進(jìn)程訪問的共享臨界區(qū)進(jìn)行處理敌卓;兩個進(jìn)程不能同時進(jìn)入臨界區(qū),否則會導(dǎo)致數(shù)據(jù)錯亂伶氢。常見的處理方式有:信號量趟径、管程、會合癣防、分布式系統(tǒng)
信號量
信號量是一個計數(shù)器蜗巧,它只支持2種操作:P操作(進(jìn)入臨界區(qū))和V操作(退出臨界區(qū))。假設(shè)有信號量SV蕾盯,則對它的P幕屹、V操作含義如下:
? ?P(SV),如果SV的值大于0级遭,意味著可以進(jìn)入臨界區(qū)望拖,就將它減1;如果SV的值為0挫鸽,意味著別的進(jìn)程正在訪問臨界區(qū)说敏,則掛起當(dāng)前進(jìn)程的執(zhí)行;
? ?V(SV)掠兄,當(dāng)前進(jìn)程退出臨界區(qū)時像云,如果有其他進(jìn)程因?yàn)榈却齋V而掛起,則喚醒之蚂夕;如果沒有迅诬,則將SV加1,之后再退出臨界區(qū)婿牍。
管程
? ?提出原因:信號量機(jī)制不足侈贷,程序編寫困難、易出錯
? ?方案:在程序設(shè)計語言中引入一種高級維護(hù)機(jī)制
? ?定義:是一個特殊的模塊;有一個名字俏蛮;由關(guān)于共享資源的數(shù)據(jù)結(jié)構(gòu)及在其上操作上的一組過程組成撑蚌。進(jìn)程只能通過調(diào)用管程中的過程間接訪問管程中的數(shù)據(jù)結(jié)構(gòu)
? 1)互斥:管程是互斥進(jìn)入的 為了保證數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)完整性
管程的互斥由編譯器負(fù)責(zé)保證的,是一種語言機(jī)制
? 2)同步:設(shè)置條件變量及等待喚醒操作以解決同步問題
可以讓一個進(jìn)程或者線程在條件變量上等待(先釋放管程的管理權(quán))搏屑,也可以通過發(fā)送信號將等待在條件變量上的進(jìn)程線程喚醒
15争涌、線程間操作List
1、聲明list的地方用Collections.synchronizedList()包一層辣恋,表示可以同步訪問亮垫;
2、使用synchronized(this){}鎖操作List
邏輯代碼塊
3伟骨、使用concurrent同步代碼包中封裝類
16饮潦、Java中對象的生命周期
1、創(chuàng)建階段(Created)
??檢測類是否被加載沒有加載的先加載
→為新生對象分配內(nèi)存
→將分配到的內(nèi)存空間都初始化為零值
→對對象進(jìn)行必要的設(shè)置
→執(zhí)行<init>方法把對象進(jìn)行初始化
對象的加載大小是類加載中就已經(jīng)確定好了的携狭,類加載過程就相當(dāng)復(fù)雜了继蜡,如下圖:
2、應(yīng)用階段(In Use)
??至少有一個強(qiáng)引用使用著
3逛腿、不可見階段(Invisible)
??程序的執(zhí)行已經(jīng)超出了該對象的作用域了
4稀并、不可達(dá)階段(Unreachable)
??程序不再持有該對象的任何強(qiáng)引用,這種情況下鳄逾,該對象仍可能被JVM等系統(tǒng)下的某些已裝載的靜態(tài)變量或線程或JNI等強(qiáng)引用持有著稻轨,這些特殊的強(qiáng)引用被稱為”GC root”
5灵莲、收集階段(Collected)
??垃圾回收器發(fā)現(xiàn)該對象已經(jīng)處于“不可達(dá)階段”并且垃圾回收器已經(jīng)對該對象的內(nèi)存空間重新分配做好準(zhǔn)備時雕凹,則對象進(jìn)入了“收集階段”。如果該對象已經(jīng)重寫了finalize()方法政冻,則會去執(zhí)行該方法的終端操作枚抵。
6、終結(jié)階段(Finalized)
??當(dāng)對象執(zhí)行完finalize()方法后仍然處于不可達(dá)狀態(tài)時明场,則該對象進(jìn)入終結(jié)階段汽摹。在該階段是等待垃圾回收器對該對象空間進(jìn)行回收。
7苦锨、對象空間重分配階段(De-allocated)
??垃圾回收器對該對象的所占用的內(nèi)存空間進(jìn)行回收或者再分配了逼泣,則該對象徹底消失了,稱之為“對象空間重新分配階段”舟舒。
17拉庶、Synchronized用法
18、synchronize的原理
19秃励、談?wù)剬ynchronized關(guān)鍵字氏仗,類鎖,方法鎖夺鲜,重入鎖的理解
20皆尔、static synchronized 方法的多線程訪問和作用
21呐舔、同一個類里面兩個synchronized方法,兩個線程同時訪問的問題
22慷蠕、volatile的原理
??在多線程并發(fā)編程中synchronized
和Volatile
都扮演著重要的角色珊拼,Volatile
是輕量級的synchronized
,它在多處理器開發(fā)中保證了共享變量的“可見性”流炕「唆铮可見性的意思是當(dāng)一個線程修改一個共享變量時,另外一個線程能讀到這個修改的值浪感。
原理特性:
可見性
??1昔头、淺顯的講,不論線程是如何如何的訪問帶volatile
字段的對象影兽,都會訪問到內(nèi)存中最新的一份值揭斧,這就是可見性的大致闡述;
??2峻堰、具體的講讹开,當(dāng)我們在java
代碼中書寫的那行對volatile
對象進(jìn)行寫操作時,JVM
會向處理器發(fā)送一條Lock
指令捐名,
Lock
指令鎖椎┩颉(鎖總線)確保變量對象所在緩存行數(shù)據(jù)會更新到主內(nèi)存中去,確保更新后如果再有其他線程訪問該對象镶蹋,
其他線程一律強(qiáng)制從主內(nèi)存中重新讀取最新的值成艘。
??3、因?yàn)樗袃?nèi)存的傳輸都發(fā)生在一條共享的總線上贺归,并且所有的處理器都能看到這條總線淆两,那么既然所有處理器都能看到這條總線,
總不至于看見了不干點(diǎn)啥吧拂酣?
??4秋冰、沒錯,每個處理器都會通過一種嗅探技術(shù)婶熬,不停的嗅探總線上傳輸?shù)臄?shù)據(jù)剑勾,以便來檢查自己緩存中的數(shù)據(jù)是否過期。
當(dāng)處理器發(fā)現(xiàn)高速緩存中的數(shù)據(jù)對應(yīng)的內(nèi)存地址被修改赵颅,會將該緩存數(shù)據(jù)置為失效虽另,當(dāng)處理器下次訪問該內(nèi)存地址
數(shù)據(jù)時,將強(qiáng)制重新從系統(tǒng)內(nèi)存中讀取性含。
??5洲赵、而且CPU制造商也曾制定了一個這樣的規(guī)則:當(dāng)一個CPU修改緩存中的字節(jié)對象時,服務(wù)器中其他CPU會被通知,它們的緩存將視為無效叠萍。
當(dāng)那些被視為無效變量所在的線程再次訪問字節(jié)對象時芝发,則強(qiáng)制再次從主內(nèi)存中獲取最新值
??6、至于第2點(diǎn)提到Lock鎖總線苛谷,其實(shí)最初采用鎖總線辅鲸,雖說能解決問題,但是效率地下腹殿,一旦鎖總線独悴,其他CPU就得干等著,
光看不干效率不行嘛锣尉。所以后來優(yōu)化成了鎖緩存刻炒,效率也高了,開銷也自然就少了自沧,總之Lock目的很明確坟奥,確保鎖住的那份值最新,
且其他持有該緩存的備份處都得失效拇厢,其實(shí)這種鎖緩存過程的思想也正是緩存一致性協(xié)議的核心思想爱谁。
??7、綜上所述孝偎,所以不論何時不論何地在哪種多線程環(huán)境下访敌,只要你想獲取被volatile修飾過的字段,都能看到最新的一份值衣盾。
有序性
??1寺旺、淺顯的講,A1雨效,A2迅涮,A3
三塊代碼先后執(zhí)行,A2
有一行代碼被volatile
修飾過徽龟,那么在被反編譯成指令進(jìn)行重排序時,A2
必須等到A1
執(zhí)行完了才能開始唉地,但是A1內(nèi)部的指令可以支持重排指令据悔;而A3代碼塊的執(zhí)行必須等到A2執(zhí)行完了才能開始,但是A3內(nèi)部的指令可以支持
重排指令耘沼,這就是有序性极颓,只要A2夾在中間,A2必須等A1執(zhí)行完才能干活群嗤,A2沒干完活菠隆,A3是不允許開工的。
??2、具體的講骇径,Lock
前綴指令實(shí)際上相當(dāng)于一個內(nèi)存屏障(也成內(nèi)存柵欄)躯肌,它確保指令重排序時不會把其后面的指令排到內(nèi)存屏障之前的位置,
也不會把前面的指令排到內(nèi)存屏障的后面破衔;即在執(zhí)行到內(nèi)存屏障這句指令時清女,在它前面的操作已經(jīng)全部完成。
??3晰筛、綜上所述嫡丙,有序不是我們通常說的自然順序,而是在有volatile
修飾時读第,存在類似尊卑等級的先后有序這么一說曙博。
非原子性
??1、本不該拿到臺面上講是不是屬于volatile
的特性怜瞒,因?yàn)槲覀儾荒苷J(rèn)為僅僅只是因?yàn)榭梢娦噪S處都是最新值羊瘩,那么就認(rèn)為是原子性操作。
??2盼砍、對于第1種想法尘吗,簡直是大錯特錯,因?yàn)榭梢娦灾皇菍?code>volatile變量這回主內(nèi)存并使得其他CPU緩存
失效浇坐,但是不帶代表對volatile
變量回寫主內(nèi)存的動作和對volatile
變量的邏輯操作是捆綁在一起的睬捶。因此既要邏輯操作,又要寫回主內(nèi)存近刘,這本來就違背了volatile
特性的本意擒贸,所以volatile
并不是原子操作的。
2觉渴、談?wù)剉olatile關(guān)鍵字的用法
①.狀態(tài)標(biāo)記量
volatile boolean flag = false;
//線程1
while(!flag){
doSomething();
}
//線程2
public void setFlag() {
flag = true;
}
上面功能可以根據(jù)狀態(tài)標(biāo)記結(jié)束線程介劫,根據(jù)volatile關(guān)鍵字的可見性。
②.單例模式中的double check
class Singleton{
private volatile static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if(instance==null) {
synchronized (Singleton.class) {
if(instance==null)
instance = new Singleton();
}
}
return instance;
}
}
3案淋、談?wù)剉olatile關(guān)鍵字的作用
4座韵、談?wù)凬IO的理解
5、synchronized 和volatile 關(guān)鍵字的區(qū)別
??1踢京、volatile
本質(zhì)是在告訴jvm
當(dāng)前變量在寄存器(工作內(nèi)存)中的值是不確定的誉碴,需要從主存中讀取瓣距;
??2黔帕、synchronized
則是鎖定當(dāng)前變量,只有當(dāng)前線程可以訪問該變量蹈丸,其他線程被阻塞住成黄。
??3呐芥、volatile
僅能使用在變量級別;synchronized
則可以使用在變量奋岁、方法思瘟、和類級別的
??4、volatile
僅能實(shí)現(xiàn)變量的修改可見性厦取,不能保證原子性潮太;而synchronized
則可以保證變量的修改可見性和原子性
??5、volatile
不會造成線程的阻塞虾攻;synchronized
可能會造成線程的阻塞铡买。
??6、volatile
標(biāo)記的變量不會被編譯器優(yōu)化霎箍;synchronized
標(biāo)記的變量可以被編譯器優(yōu)化
6奇钞、synchronized與Lock的區(qū)別
7、ReentrantLock 漂坏、synchronized和volatile比較
ReentrantLock
可重入鎖景埃,和同步鎖功能類似,不過需要顯示的創(chuàng)建顶别、銷毀谷徙。特點(diǎn):
??1.ReentrantLock
有tryLock
方法,如果鎖被其他線程持有驯绎,返回false,可避免形成死鎖完慧。
??2.創(chuàng)建時可自定義是否可搶占。
??3.ReentrantReadWriteLock
,用于讀多寫少剩失,且讀不需要互斥的場景屈尼,大大提高性能。
1拴孤、嘗試獲取一次
ReentrantLock lock = new ReentrantLock();
if (lock.tryLock()) { //得到執(zhí)行脾歧,得不到不執(zhí)行,就一次演熟。
try {
//操作
} finally {
lock.unlock();
}
}
2鞭执、同步執(zhí)行,類似synchronized(也是使用最多的)
ReentrantLock lock = new ReentrantLock(); //參數(shù)默認(rèn)false绽媒,不公平鎖:可搶占
ReentrantLock lock = new ReentrantLock(true); //公平鎖:嚴(yán)格按照請求鎖的排隊(duì)順序獲取鎖
lock.lock(); //如果被其它資源鎖定蚕冬,會在此等待鎖釋放,阻塞
try {
//操作
} finally {
lock.unlock();
}
3是辕、嘗試等待固定時間再次獲取
ReentrantLock lock = new ReentrantLock(true); //公平鎖
try {
if (lock.tryLock(5, TimeUnit.SECONDS)) {
//如果已經(jīng)被lock,嘗試等待5s猎提,看是否可以獲得鎖获三,如果5s后仍然無法獲得鎖則返回false
try {
//操作
} finally {
lock.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace(); //當(dāng)前線程被中斷時(interrupt)旁蔼,會拋InterruptedException
}
4、可中斷鎖的同步執(zhí)行
ReentrantLock lock = new ReentrantLock(true); //公平鎖
lock.lockInterruptibly();
try {
//操作
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
8疙教、ReentrantLock的內(nèi)部實(shí)現(xiàn)
9棺聊、lock原理
10、死鎖的四個必要條件贞谓?
11限佩、怎么避免死鎖?
12裸弦、對象鎖和類鎖是否會互相影響祟同?
13、什么是線程池理疙,如何使用?
14晕城、Java的并發(fā)、多線程窖贤、線程模型
15砖顷、談?wù)剬Χ嗑€程的理解
16、多線程有什么要注意的問題赃梧?
17滤蝠、談?wù)勀銓Σl(fā)編程的理解并舉例說明?
18授嘀、談?wù)勀銓Χ嗑€程同步機(jī)制的理解物咳?
19、如何保證多線程讀寫文件的安全粤攒?
20所森、斷點(diǎn)續(xù)傳的實(shí)現(xiàn)
斷點(diǎn)續(xù)傳:文件傳輸過程中需要中途中斷時,我們把已傳輸?shù)奈募蛿帱c(diǎn)指針進(jìn)行保存夯接;等待下次再次開啟傳輸時直接移動指針焕济,從斷點(diǎn)的地方繼續(xù)傳輸?shù)倪@個過程稱為斷點(diǎn)續(xù)傳。
用途:本機(jī)I/O流的讀取或者本機(jī)和服務(wù)器傳輸大文件時采用盔几,java語言提供了一個文件操作類RandomAccessFile晴弃,通過該類我們可以在隨意位置讀取