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