java多进程、多线程讲解
一、 什么是進程、線程?線程和進程的區別?
1. 進程?當一個程序進入內存運行時,即變成一個進程。進程是處于運行過程中的程序。 進程是操作系統進行資源分配和調度的一個獨立單位。?進程的三個特征:
- 獨立性 獨立存在的實體,每個進程都有自己獨立私有的一塊內存空間。
- 動態性 程序只是一個靜態的指令集合,而進程是一個正在系統中活動的指令集合。
- 并發性 多個進程可在單處理器上并發執行。
2. 線程?線程是操作系統能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運作單位。線程也被稱作輕量級進程。線程在進程中是獨立,并發的執行流。
3.線程和進程的區別
二、 多線程的優勢
三、 Java中創建線程方法
1. 繼承Thread類創建線程類
2. 實現Runnable接口創建線程類
- 定義Runnable接口的實現類,重寫該接口的run()方法。該方法為線程執行體。
- 創建Runnable實現類的實例。并以此實例作為Thread的target來創建Thread對象。該Thread對象才是真正的線程對象。
- 調用線程對象(該Thread對象)的start()方法啟動該線程。
3. 使用Callable和Future創建線程http://blog.csdn.net/ghsau/article/details/7451464
四、 用Runnable還是ThreadJava以及創建線程兩種方法對比?
在java多線程中,一般推薦采用實現Runnable接口來創建多線程,因為實現Runnable接口相比繼承Thread類有如下優劣勢:
- 實現Runnable接口,線程類只是實現了接口,還可以繼承其他類;繼承Thread類的話,不能再繼承其他父類。
- 實現Runnable接口,多個線程可以共享同一個target對象,所以適合多個相同程序代碼的線程區處理同一資源的情況。分離數據和代碼,體現面向對象的思想。
- 實現Runnable接口,訪問當前線程,必須使用Thread.currentThread()方法;繼承Thread類的話,使用this獲得當前線程。 與http://blog.csdn.net/ns_code/article/details/17161237互補。
五、 Thread 類中的start() 和 run() 方法有什么區別?
六、 線程的生命周期
Java線程五種狀態:
七、 java控制線程方法
1. join線程?join方法用線程對象調用,如果在一個線程A中調用另一個線程B的join方法,線程A將會等待線程B執行完畢后再執行。
2. 守護線程(Daemon Thread)?Java中有兩類線程:User Thread(用戶線程)、Daemon Thread(守護線程) 。 用戶線程即運行在前臺的線程,而守護線程是運行在后臺的線程。 守護線程作用是為其他前臺線程的運行提供便利服務,而且僅在普通、非守護線程仍然運行時才需要,比如垃圾回收線程就是一個守護線程。當VM檢測僅剩一個守護線程,而用戶線程都已經退出運行時,VM就會退出,因為沒有如果沒有了被守護這,也就沒有繼續運行程序的必要了。如果有非守護線程仍然存活,VM就不會退出。?守護線程的特征:如果所有前臺線程都死亡,后臺線程會自動死亡。?守護線程并非只有虛擬機內部提供,用戶在編寫程序時也可以自己設置守護線程。用戶可以用Thread的setDaemon(true)方法設置當前線程為守護線程。 雖然守護線程可能非常有用,但必須小心確保其他所有非守護線程消亡時,不會由于它的終止而產生任何危害。因為你不可能知道在所有的用戶線程退出運行前,守護線程是否已經完成了預期的服務任務。一旦所有的用戶線程退出了,虛擬機也就退出運行了。 因此,不要在守護線程中執行業務邏輯操作(比如對數據的讀寫等)。?另外有幾點需要注意:
1、setDaemon(true)必須在調用線程的start()方法之前設置,否則會跑出IllegalThreadStateException異常。 2、在守護線程中產生的新線程也是守護線程。 3、 不要認為所有的應用都可以分配給守護線程來進行服務,比如讀寫操作或者計算邏輯。參考http://blog.csdn.net/ns_code/article/details/17099981
3. 線程讓步(yield )?yield可以直接用Thread類調用,可以讓當前正在執行的線程暫停,不會阻塞該線程,只是將該線程轉入就緒狀態。yield讓出CPU執行權給同等級的線程,如果沒有相同級別的線程在等待CPU的執行權,則該線程繼續執行。
八、 sleep()方法和yield()方法的區別
九、 為什么Thread類的sleep()和yield()方法是靜態的?
Thread類的sleep()和yield()方法將在當前正在執行的線程上運行。所以在其他處于等待狀態的線程上調用這些方法是沒有意義的。它們可以在當前正在執行的線程中工作,并避免程序員錯誤的認為可以在其他非運行線程調用這些方法。 現在的實現, 是只能sleep當前的線程.當前線程是自愿的.讓sleep()成為實例方法, 當前線程可以直接sleep別的線程, 會引入很多 多線程問題,例如死鎖。 destroy(), suspend(), stop(),resume()這些實例方法都已經被deprecated(棄用)。活下來的是哪些? 只有static方法(只對當前線程操作和一些比較溫和的實例方法, 如getXXX(), isXXX(), join(), yield()等.
十、 sleep方法與wait方法的區別?
十一、 線程安全問題
線程安全問題,其實是指多線程環境下對共享資源的訪問可能會引起此共享資源的不一致性。因此,為避免線程安全問題,應該避免多線程環境下對此共享資源的并發訪問。
十二、 同步代碼塊
同步代碼塊的格式為:
synchronized (obj) { //...}其中,obj為鎖對象,因此,選擇哪一個對象作為鎖是至關重要的。一般情況下,都是選擇此共享資源對象作為鎖對象。?任何時刻只能有一個線程可以獲得對鎖對象的鎖定,其他線程無法獲得鎖,也無法修改它。當同步代碼塊執行完成后,該線程會釋放對鎖對象的鎖定。 通過這種方式可以保證并發線程在任一時刻只有一個線程可以進入修改共享資源的代碼區(臨界區),從而保證線程的安全性。
十三、 同步方法
對共享資源進行訪問的方法定義中加上synchronized關鍵字修飾,使得此方法稱為同步方法。可以簡單理解成對此方法進行了加鎖,其鎖對象為當前方法所在的對象自身。多線程環境下,當執行此方法時,首先都要獲得此同步鎖(且同時最多只有一個線程能夠獲得),只有當線程執行完此同步方法后,才會釋放鎖對象,其他的線程才有可能獲取此同步鎖,以此類推…
public synchronized void a() { // ....}可變類的線程安全是以降低程序的運行效率為代價的,為了減少程序安全所帶來的負面影響,程序可以采用如下策略: – 不要對線程安全類的所有方法都進行同步,只對那些會改變競爭資源的方法進行同步。 – 如果可變類有兩種運行環境:單線程和多線程環境,則應該為該可變類提供兩種版本:線程不安全版本和線程安全版本。在單線程環境中使用線程不安全版本以保證性能,在多線程環境中使用線程安全版本。
十四、 何時會釋放對同步監視器鎖定?
程序無法顯式的釋放對同步監視器的鎖定,線程可以通過以下方式釋放鎖定: A、當線程的同步方法、同步代碼庫執行結束,就可以釋放同步監視器 B、當線程在同步代碼庫、方法中遇到break、return終止代碼的運行,也可釋放 C、當線程在同步代碼庫、同步方法中遇到未處理的Error、Exception,導致該代碼結束也可釋放同步監視器 D、當線程在同步代碼庫、同步方法中,程序執行了同步監視器對象的wait方法,導致方法暫停,釋放同步監視器
下面情況不會釋放同步監視器: A、當線程在執行同步代碼庫、同步方法時,程序調用了Thread.sleep()/Thread.yield()方法來暫停當前程序,當前程序不會釋放同步監視器 B、當線程在執行同步代碼庫、同步方法時,其他線程調用了該線程的suspend方法將該線程掛起,該線程不會釋放同步監視器。注意盡量避免使用suspend、resume十五、同步鎖(Lock)
通常認為:Lock提供了比synchronized方法和synchronized代碼塊更廣泛的鎖定操作,Lock更靈活的結構,有很大的差別,并且可以支持多個Condition對象 Lock是控制多個線程對共享資源進行訪問的工具。通常,鎖提供了對共享資源的獨占訪問,每次只能有一個線程對Lock對象加鎖, 線程開始訪問共享資源之前應先獲得Lock對象。不過某些鎖支持共享資源的并發訪問,如:ReadWriteLock(讀寫鎖),在線程安全控制中, 通常使用ReentrantLock(可重入鎖)。使用該Lock對象可以顯示加鎖、釋放鎖。
class C {//鎖對象private final ReentrantLock lock = new ReentrantLock();......//保證線程安全方法public void method() {//上鎖lock.lock();try {//保證線程安全操作代碼} catch() {} finally {lock.unlock();//釋放鎖}}}使用Lock對象進行同步時,鎖定和釋放鎖時注意把釋放鎖放在finally中保證一定能夠執行。使用鎖和使用同步很類似,只是使用Lock時顯示的調用lock方法來同步。而使用同步方法synchronized時系統會隱式使用當前對象作為同步監視器,同樣都是“加鎖->訪問->釋放鎖”的操作模式,都可以保證只能有一個線程操作資源。 同步方法和同步代碼塊使用與競爭資源相關的、隱式的同步監視器,并且強制要求加鎖和釋放鎖要出現在一個塊結構中,而且獲得多個鎖時,它們必須以相反的順序釋放,且必須在與所有鎖被獲取時相同的范圍內釋放所有資源。 Lock提供了同步方法和同步代碼庫沒有的其他功能,包括用于非塊結構的tryLock方法,已經試圖獲取可中斷鎖lockInterruptibly()方法, 還有獲取超時失效鎖的tryLock(long, timeUnit)方法。 ReentrantLock具有重入性,也就是說線程可以對它已經加鎖的ReentrantLock再次加鎖,ReentrantLock對象會維持一個計數器來追蹤lock方法的嵌套調用,線程在每次調用lock()加鎖后,必須顯示的調用unlock()來釋放鎖,所以一段被保護的代碼可以調用另一個被相同鎖保護的方法。
十六、死鎖
當2個線程相互等待對方是否同步監視器時就會發生死鎖,JVM沒有采取處理死鎖的措施,這需要我們自己處理或避免死鎖。 一旦死鎖,整個程序既不會出現異常,也不會出現錯誤和提示,只是線程將處于阻塞狀態,無法繼續。 由于Thread類的suspend也很容易導致死鎖,所以Java不推薦使用此方法暫停線程。 參考http://ifeve.com/deadlock/了解更多死鎖情況。 大部分代碼并不容易產生死鎖,死鎖可能在代碼中隱藏相當長的時間,等待不常見的條件地發生,但即使是很小的概率,一旦發生,便可能造成毀滅性的破壞。避免死鎖是一件困難的事,遵循以下原則有助于規避死鎖:
1、只在必要的最短時間內持有鎖,考慮使用同步語句塊代替整個同步方法;2、盡量編寫不在同一時刻需要持有多個鎖的代碼,如果不可避免,則確保線程持有第二個鎖的時間盡量短暫;3、創建和使用一個大鎖來代替若干小鎖,并把這個鎖用于互斥,而不是用作單個對象的對象級別鎖;參考:http://blog.csdn.net/ns_code/article/details/17200937
這些我都是看書,以及參考網絡資料總結的。接下來還會總結線程通信,線程池和線程安全集合類相關知識點。我會在本博文更新~ 參考:http://ifeve.com/java-multi-threading-concurrency-interview-questions-with-answers/?http://ifeve.com/java-concurrency-thread-directory/?http://www.importnew.com/12773.html?http://www.cnblogs.com/lwbqqyumidi/p/3804883.html?java編程思想 java瘋狂講義 http://blog.csdn.net/zhoubin1992/article/details/46861397
轉載請注明:Android開發中文站???Java多線程和并發性知識點總結
總結
以上是生活随笔為你收集整理的java多进程、多线程讲解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android之ActivityMana
- 下一篇: Activity之launchMode: