日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java多进程、多线程讲解

發布時間:2023/12/4 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java多进程、多线程讲解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、 什么是進程、線程?線程和進程的區別?

1. 進程?當一個程序進入內存運行時,即變成一個進程。進程是處于運行過程中的程序。 進程是操作系統進行資源分配和調度的一個獨立單位。?進程的三個特征:

  • 獨立性 獨立存在的實體,每個進程都有自己獨立私有的一塊內存空間。
  • 動態性 程序只是一個靜態的指令集合,而進程是一個正在系統中活動的指令集合。
  • 并發性 多個進程可在單處理器上并發執行。
并發性和并行性并發是指在同一時間點只能有一條指令執行,但多個進程指令被快速輪換執行,使得在宏觀上具有多個進程同時執行的效果。并行指在同一時間點,有多條指令在多個處理器上同時執行。

2. 線程?線程是操作系統能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運作單位。線程也被稱作輕量級進程。線程在進程中是獨立,并發的執行流。

3.線程和進程的區別

  • 線程是進程的組成部分,一個進程可以有很多線程,每條線程并行執行不同的任務。
  • 不同的進程使用不同的內存空間,而線程與父進程的其他線程共享父進程的所擁有的全部資源。這樣編程方便了,但是要更加小心。
  • 別把內存空間和棧內存搞混,每個線程都擁有單獨的棧內存用來存儲本地數據。線程擁有自己的堆棧、自己的程序計數器和自己的局部變量,但不擁有系統資源。
  • 線程的調度和管理由進程本身負責完成。操作系統對進程進行調度,管理和資源分配。

  • 二、 多線程的優勢

  • 進程之間不能共享內存,但線程之間共享內存。
  • 系統創建進程時需要為該進程重新分配系統資源,但創建線程則代價小很多,效率高。
  • 資源利用率更好
  • 程序設計更簡單
  • 程序響應更快 后三條詳細見http://ifeve.com/benefits/

  • 三、 Java中創建線程方法

    1. 繼承Thread類創建線程類

  • 定義Thread類的子類,重寫該類的run()方法。該方法為線程執行體。
  • 創建Thread子類的實例。即線程對象。
  • 調用線程對象的start()方法啟動該線程
  • 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() 方法有什么區別?

  • start()方法被用來啟動新創建的線程,而且start()內部調用了run()方法,這和直接調用run()方法的效果不一樣。
  • 當你調用run()方法的時候,只會是在原來的線程中調用,沒有新的線程啟動,start()方法才會啟動新線程。?需要特別注意的是:不能對同一線程對象兩次調用start()方法。

  • 六、 線程的生命周期

    Java線程五種狀態:

  • 新建狀態(New):當線程對象創建后,即進入了新建狀態。僅僅由java虛擬機分配內存,并初始化。如:Thread t = new MyThread();
  • 就緒狀態(Runnable):當調用線程對象的start()方法(t.start();),線程即進入就緒狀態。處于就緒狀態的線程,java虛擬機創建方法調用棧和程序計數器,只是說明此線程已經做好了準備,隨時等待CPU調度執行,此線程并 沒有執行。
  • 運行狀態(Running):當CPU開始調度處于就緒狀態的線程時,執行run()方法,此時線程才得以真正執行,即進入到運行狀態。注:緒狀態是進入到運行狀態的唯一入口,也就是說,線程要想進入運行狀態執行,首先必須處于就緒狀態中;
  • 阻塞狀態(Blocked):處于運行狀態中的線程由于某種原因,暫時放棄對CPU的使用權,停止執行,此時進入阻塞狀態,直到其進入到就緒狀態,才 有機會再次被CPU調用以進入到運行狀態。根據阻塞產生的原因不同,阻塞狀態又可以分為三種:
  • 等待阻塞 – 運行狀態中的線程執行wait()方法,使本線程進入到等待阻塞狀態,JVM會把該線程放入等待池中;
  • 同步阻塞 – 線程在獲取synchronized同步鎖失敗(因為鎖被其它線程所占用),它會進入同步阻塞狀態;
  • 其他阻塞 – 通過調用線程的sleep()或join()或發出了I/O請求時,線程會進入到阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程重新轉入就緒狀態。
  • 死亡狀態(Dead):線程run()方法執行完了或者因異常退出了run()方法,該線程結束生命周期。?當主線程結束時,其他線程不受任何影響。

  • 七、 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()方法的區別

  • sleep()方法暫停當前線程后,會給其他線程執行機會,不會理會其他線程的優先級;但yield()方法只會給優先級相同,或優先級更高的線程執行機會。
  • sleep()方法會將線程轉入阻塞狀態(block狀態),直到經過阻塞時間才會轉入就緒狀態;而yield()方法不會將線程轉入阻塞狀態,它只是強制當前線程進入就緒狀態。?因此完全有可能某個線程調用yield()方法暫停之后,立即再次獲得處理器資源被執行。
  • sleep()方法聲明拋出了InterruptedException異常,所以調用sleep()方法時要么捕捉該異常,要么顯式聲明拋出該異常;而yield()方法則沒有聲明拋出任何異常。
  • sleep()方法比yield()方法有更好的可移植性,通常不建議使用yield()方法來控制并發線程的執行。

  • 九、 為什么Thread類的sleep()和yield()方法是靜態的?

    Thread類的sleep()和yield()方法將在當前正在執行的線程上運行。所以在其他處于等待狀態的線程上調用這些方法是沒有意義的。它們可以在當前正在執行的線程中工作,并避免程序員錯誤的認為可以在其他非運行線程調用這些方法。 現在的實現, 是只能sleep當前的線程.當前線程是自愿的.讓sleep()成為實例方法, 當前線程可以直接sleep別的線程, 會引入很多 多線程問題,例如死鎖。 destroy(), suspend(), stop(),resume()這些實例方法都已經被deprecated(棄用)。活下來的是哪些? 只有static方法(只對當前線程操作和一些比較溫和的實例方法, 如getXXX(), isXXX(), join(), yield()等.


    十、 sleep方法與wait方法的區別?

  • sleep方法是靜態方法,wait方法是非靜態方法。
  • sleep方法在時間到后會自己“醒來”,但wait不能,必須由其它線程通過notify(All)方法讓它“醒來”。
  • 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多进程、多线程讲解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。