摘要:輔助線程執(zhí)行主線程正在執(zhí)行函數(shù)函數(shù)如果對(duì)象調(diào)用了方法就會(huì)使持有該對(duì)象的線程把該對(duì)象的控制權(quán)交出去,然后處于等待狀態(tài)。當(dāng)同步方法執(zhí)行完畢或者執(zhí)行時(shí),其他某個(gè)線程將獲得對(duì)象的訪問權(quán)。
join()函數(shù)
Join的含義是:將某一線程加入成為另一個(gè)線程的流程之一,換言之就是等待另一個(gè)線程執(zhí)行完畢。
public class JoinTest { public static void main(String[] args) throws InterruptedException { Thread otherThread = new Thread( new Runnable() { public void run() { try { for ( int i = 1; i <= 5; i++) { Thread. sleep(1000); System. out.println(i + ":輔助線程執(zhí)行.." ); } } catch (InterruptedException e) { e.printStackTrace(); } } }); otherThread.start(); try { otherThread.join(); } catch (InterruptedException e) { e.printStackTrace(); } for ( int i = 1; i <= 5; i++) { Thread. sleep(500); System. out.println(i + ": 主線程正在執(zhí)行..." ); } } }
wait()函數(shù)notify()函數(shù)
如果對(duì)象調(diào)用了wait方法就會(huì)使持有該對(duì)象的線程把該對(duì)象的控制權(quán)交出去,然后處于等待狀態(tài)。
如果對(duì)象調(diào)用了notify方法就會(huì)通知某個(gè)正在等待這個(gè)對(duì)象的控制權(quán)的線程可以繼續(xù)運(yùn)行。
wait方法阻塞本線程,等待其他線程調(diào)用notify方法通知自己可以繼續(xù)執(zhí)行,也就是說這一對(duì)方法應(yīng)該結(jié)合在一起使用,只有當(dāng)A線程在wait之后出讓資源是其他線程有機(jī)會(huì)前進(jìn),另外的B線程notifyA才能使A線程恢復(fù)執(zhí)行。在Java多線程任務(wù)里經(jīng)常會(huì)出現(xiàn)多個(gè)線程爭(zhēng)奪同一個(gè)資源,如果任由其爭(zhēng)奪可能會(huì)造成問題,所以有序的爭(zhēng)奪離不開阻塞和喚醒線程,可以先對(duì)線程已經(jīng)爭(zhēng)得的資源加鎖,這時(shí)其他資源將無法爭(zhēng)奪這個(gè)加鎖的資源,在試用完資源后對(duì)資源進(jìn)行解鎖,使得其他線程能夠重新獲得這個(gè)資源的爭(zhēng)奪權(quán)。(其實(shí)這個(gè)過程類似于進(jìn)程的信號(hào)量加鎖解鎖)。闡明這個(gè)問題的最好例子莫過于生產(chǎn)者消費(fèi)者的模擬:
在這個(gè)過程中,生產(chǎn)產(chǎn)品、消費(fèi)產(chǎn)品時(shí)所需要的容器是爭(zhēng)奪的資源,對(duì)這個(gè)這多資源在訪問時(shí)需要加解鎖:
synchronized(container):對(duì)容器加鎖以阻塞其他線程同時(shí)訪問,亦即使得其他線程處于等待狀態(tài);
container.wait():在容器滿時(shí)阻塞本線程把容器解鎖將容器的控制權(quán)交出去,本線程處于等待狀態(tài);
container.notify():在容器空時(shí)通知正在等待容器控制權(quán)的線程恢復(fù)運(yùn)行,亦即解鎖容器;
public class ThreadTest { private List
線程死鎖的問題
線程和線程如果在運(yùn)行的過程中保有同樣的資源,如果這些資源的占用在某一時(shí)刻無法良好分配,那么就有可能出現(xiàn)死鎖:
class MyRunnable implements Runnable{ Object a; Object b; public MyRunnable(Object a, Object b) { this.a = a; this.b = b; } @Override public void run() { while(true){ synchronized (a) { synchronized (b) { System.out.println(Thread.currentThread().getName()+" is running"); } } } } } class ThreadTest{ public static void main(String[] args) { Object a = new Object(); Object b = new Object(); MyRunnable myRunnable1 = new MyRunnable(a, b); MyRunnable myRunnable2 = new MyRunnable(b, a); Thread threadA = new Thread(myRunnable1,"t1"); Thread threadB = new Thread(myRunnable2,"t2"); threadA.start(); threadB.start(); } }
在這個(gè)例子中兩個(gè)線程在運(yùn)行的過程中必須同時(shí)保有兩個(gè)對(duì)象,那么當(dāng)對(duì)象A被一個(gè)線程鎖定而被另一個(gè)線程需要,同時(shí)對(duì)象B被一個(gè)線程鎖定而被另一個(gè)線程需要的時(shí)候就會(huì)出現(xiàn)死鎖。比如t1拿到A和B后鎖定它們運(yùn)行,t2因?yàn)闆]有A和B處于等待狀態(tài),t1運(yùn)行后解鎖先解鎖B還沒有解鎖A,t2拿到這個(gè)B后鎖定B繼而需要A,t1解鎖A后t2沒有拿到A,t1的下一次循環(huán)拿到了這個(gè)A并鎖定A,這個(gè)時(shí)候t2需要的A被t1鎖定,t1需要的B被t2鎖定,最終A和B產(chǎn)生死鎖。
附上Java線程的同步原理
線程同步的基本原理
java會(huì)為每個(gè)object對(duì)象分配一個(gè)monitor,當(dāng)某個(gè)對(duì)象的同步方法(synchronized methods )或同步塊被多個(gè)線程調(diào)用時(shí),該對(duì)象的monitor將負(fù)責(zé)處理這些訪問的并發(fā)獨(dú)占要求。
當(dāng)一個(gè)線程調(diào)用一個(gè)對(duì)象的同步方法時(shí),JVM會(huì)檢查該對(duì)象的monitor。如果monitor沒有被占用,那么這個(gè)線程就得到了monitor的占有權(quán),可以繼續(xù)執(zhí)行該對(duì)象的同步方法;如果monitor被其他線程所占用,那么該線程將被掛起,直到monitor被釋放。
當(dāng)線程退出同步方法調(diào)用時(shí),該線程會(huì)釋放monitor,這將允許其他等待的線程獲得monitor以使對(duì)同步方法的調(diào)用執(zhí)行下去。
注意:java對(duì)象的monitor機(jī)制和傳統(tǒng)的臨界檢查代碼區(qū)技術(shù)不一樣。java的一個(gè)類一個(gè)同步方法并不意味著同時(shí)只有一個(gè)線程獨(dú)占執(zhí)行(不同對(duì)象的同步方法可以同時(shí)執(zhí)行),但臨界檢查代碼區(qū)技術(shù)確會(huì)保證同步方法在一個(gè)時(shí)刻只被一個(gè)線程獨(dú)占執(zhí)行。
java的monitor機(jī)制的準(zhǔn)確含義是:任何時(shí)刻,對(duì)一個(gè)指定object對(duì)象的某同步方法只能由一個(gè)線程來調(diào)用。
java對(duì)象的monitor是跟隨object實(shí)例來使用的,而不是跟隨程序代碼。兩個(gè)線程可以同時(shí)執(zhí)行相同的同步方法,比如:一個(gè)類的同步方法是xMethod(),有a,b兩個(gè)對(duì)象實(shí)例,一個(gè)線程執(zhí)行a.xMethod(),另一個(gè)線程執(zhí)行b.xMethod(). 互不沖突。
wait()、notify(),notifyAll()的使用
obj.wait()方法使本線程掛起,并釋放obj對(duì)象的monitor,只有其他線程調(diào)用obj對(duì)象的notify()或notifyAll()時(shí),才可以被喚醒。
obj.notifyAll()方法喚醒所有阻塞在obj對(duì)象上的沉睡線程,然后被喚醒的眾多線程競(jìng)爭(zhēng)obj對(duì)象的monitor占有權(quán),最終得到的那個(gè)線程會(huì)繼續(xù)執(zhí)行下去,但其他線程繼續(xù)等待。
obj.notify()方法是隨機(jī)喚醒一個(gè)沉睡線程,過程更obj.notifyAll()方法類似。
wait,notify和notifyAll只能在同步控制方法或者同步控制塊里面使用,
如:
synchronized(x){ x.notify() //或者wait() }
以上內(nèi)容說明了為什么調(diào)用wait(),notify(),notifyAll()的線程必須要擁有obj實(shí)例對(duì)象的monitor占有權(quán)。
每個(gè)對(duì)象實(shí)例都有一個(gè)等待線程隊(duì)列。這些線程都是等待對(duì)該對(duì)象的同步方法的調(diào)用許可。對(duì)一個(gè)線程來說,有兩種方法可以進(jìn)入這個(gè)等待線程隊(duì)列。一個(gè)是當(dāng)其他線程執(zhí)行同步方法時(shí),自身同時(shí)也要執(zhí)行該同步方法;另一個(gè)是調(diào)用obj.wait()方法。
當(dāng)同步方法執(zhí)行完畢或者執(zhí)行wait()時(shí),其他某個(gè)線程將獲得對(duì)象的訪問權(quán)。當(dāng)一個(gè)線程被放入等待隊(duì)列時(shí),必須要確保可以通過notify()的調(diào)用來解凍該線程,以使其能夠繼續(xù)執(zhí)行下去。
wait()與sleep()的區(qū)別
sleep()方法是Thread類的靜態(tài)方法,不涉及到線程間同步概念,僅僅為了讓一個(gè)線程自身獲得一段沉睡時(shí)間。sleep可以在任何地方使用。(所以sleep只跟當(dāng)前線程自己有關(guān))
wait()方法是object類的方法,解決的問題是線程間的同步,該過程包含了同步鎖的獲取和釋放,調(diào)用wait方法將會(huì)將調(diào)用者的線程掛起,直到其他線程調(diào)用同一個(gè)對(duì)象的notify()方法才會(huì)重新激活調(diào)用者。(所以wait適用于多個(gè)線程同步協(xié)調(diào)時(shí)才使用的)
注意:線程調(diào)用notify()之后,只有該線程完全從 synchronized代碼里面執(zhí)行完畢后,monitor才會(huì)被釋放,被喚醒線程才可以真正得到執(zhí)行權(quán)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/64614.html
摘要:進(jìn)程一般由程序數(shù)據(jù)集進(jìn)程控制塊三部分組成。線程概述線程的出現(xiàn)是為了降低上下文切換的消耗,提高系統(tǒng)的并發(fā)性。線程突破了一個(gè)進(jìn)程只能干一件事的缺陷,使到進(jìn)程內(nèi)并發(fā)成為可能。進(jìn)程與線程的關(guān)系進(jìn)程是計(jì)算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運(yùn)行活動(dòng)。 進(jìn)程概述 進(jìn)程:正在運(yùn)行的程序,是系統(tǒng)進(jìn)行資源分配和調(diào)用的獨(dú)立單位。 進(jìn)程就是一個(gè)程序在一個(gè)數(shù)據(jù)集上的一次動(dòng)態(tài)執(zhí)行過程。 進(jìn)程一般由程序、數(shù)據(jù)集、進(jìn)...
摘要:但是單核我們還是要應(yīng)用多線程,就是為了防止阻塞。多線程可以防止這個(gè)問題,多條線程同時(shí)運(yùn)行,哪怕一條線程的代碼執(zhí)行讀取數(shù)據(jù)阻塞,也不會(huì)影響其它任務(wù)的執(zhí)行。 1、多線程有什么用?一個(gè)可能在很多人看來很扯淡的一個(gè)問題:我會(huì)用多線程就好了,還管它有什么用?在我看來,這個(gè)回答更扯淡。所謂知其然知其所以然,會(huì)用只是知其然,為什么用才是知其所以然,只有達(dá)到知其然知其所以然的程度才可以說是把一個(gè)知識(shí)點(diǎn)...
摘要:下面是線程相關(guān)的熱門面試題,你可以用它來好好準(zhǔn)備面試。線程安全問題都是由全局變量及靜態(tài)變量引起的。持有自旋鎖的線程在之前應(yīng)該釋放自旋鎖以便其它線程可以獲得自旋鎖。 最近看到網(wǎng)上流傳著,各種面試經(jīng)驗(yàn)及面試題,往往都是一大堆技術(shù)題目貼上去,而沒有答案。 不管你是新程序員還是老手,你一定在面試中遇到過有關(guān)線程的問題。Java語言一個(gè)重要的特點(diǎn)就是內(nèi)置了對(duì)并發(fā)的支持,讓Java大受企業(yè)和程序員...
摘要:線程可以被稱為輕量級(jí)進(jìn)程。一個(gè)守護(hù)線程是在后臺(tái)執(zhí)行并且不會(huì)阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務(wù)操作系統(tǒng)和多線程環(huán)境的基本特征。在的線程中并沒有可供任何對(duì)象使用的鎖和同步器。 原文:Java Multi-Threading and Concurrency Interview Questions with Answers 翻譯:并發(fā)編程網(wǎng) - 鄭旭東 校對(duì):方騰飛 多...
摘要:多線程和并發(fā)問題是技術(shù)面試中面試官比較喜歡問的問題之一。線程可以被稱為輕量級(jí)進(jìn)程。一個(gè)守護(hù)線程是在后臺(tái)執(zhí)行并且不會(huì)阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務(wù)操作系統(tǒng)和多線程環(huán)境的基本特征。 多線程和并發(fā)問題是 Java 技術(shù)面試中面試官比較喜歡問的問題之一。在這里,從面試的角度列出了大部分重要的問題,但是你仍然應(yīng)該牢固的掌握J(rèn)ava多線程基礎(chǔ)知識(shí)來對(duì)應(yīng)日后碰到的問題。(...
閱讀 1836·2021-11-24 09:39
閱讀 1632·2021-11-16 11:54
閱讀 3586·2021-11-11 16:55
閱讀 1824·2021-10-14 09:43
閱讀 1506·2019-08-30 15:55
閱讀 1295·2019-08-30 15:54
閱讀 3482·2019-08-30 15:53
閱讀 1433·2019-08-30 14:18