1. 程式人生 > >java高階特性之多執行緒

java高階特性之多執行緒

java多執行緒知識點:

1、建立分執行緒的方式

2、單例模式懶漢式執行緒安全問題

3、java執行緒同步

4、java執行緒通訊

5、java的記憶體模型

認識執行緒:

每一個java程式都有一個隱含的主執行緒,即main()方法。

程式–>程序 —>執行緒 理解

何時需要多執行緒操作:

1,程式需要執行多個任務的時候。

2,程式需要實現一個等待的任務時,如等待使用者輸入,檔案讀寫,網路操作,搜尋等。

3,程式需要後臺執行的程式時。

建立分執行緒的方式:

1,繼承Thread類,其子類重寫Thread類的run()方法即可。

    每一個執行緒都是通過Thread類的run()
方法來完成相應的功能,經常把run()方法的主體稱為 執行緒體。 通過子類物件的start()方法來執行當前執行緒。start()方法的兩個作用:①啟動當前執行緒 ②執行執行緒的run()方法。 2,建立實現Runnable介面的類,並且實現介面中的抽象run()方法。 例項化一個Rundnable介面實現類的物件,並將此物件作為引數傳遞給Thread類的構造器。 通過Thread類物件呼叫strar()方法執行當前執行緒。
多執行緒認識:JVM負責管理這些執行緒,這些執行緒將被輪流執行。使得每一個執行緒都有機會使用CPU資源。

兩種分執行緒建立的聯絡和區別:

1public
static Thread implements Runnable {Thread 類的本質如上實現了Runnable 介面} 2,第二種分執行緒建立的方式如下優點: ①沒有單繼承的侷限 ②若多執行緒有共享資料的話,實現更加方便。

使用Thread子類建立執行緒的優點:
可以在子類中增加新的成員變數,使得執行緒具有某種屬性,也可以在子類中新增加方法,使執行緒具有某種功能。但是java不支援多繼承,Thread類的子類不能再拓展其他類。

執行緒中的常用方法:

 * 1.start():開啟執行緒;執行相應的run()

 * 2.run():分執行緒要執行的功能封裝在run()中

 * 3.
currentThread():獲取當前正在執行的執行緒 * 4.getName():獲取當前執行緒的名字 * 5.setName():設定當前執行緒的名字 * 6.yield():暫時釋放執行緒對當前cpu的佔用 * 7.join():線上程a中呼叫執行緒b.join()表示:當前執行緒a進入阻塞狀態,執行緒b開始執行,直到執行緒b執行結束,執行緒a才繼續執行。 * 8.sleep(long millitimes):顯示的使得當前執行緒睡眠指定的毫秒數。這個過程中,當前執行緒處於阻塞狀態 * 9.isAlive():當前執行緒是否還存活 * * 10.執行緒的優先順序:getPriority() / setPriority(int i) * MIN_PRIORITY:1 * NORM_PRIORITY:5 * MAX_PRIORITY:10 * 優先順序高,並不是當前執行緒被首先執行完,而是被執行的概率大 * 11.執行緒的通訊: wait() / notify() / notifyAll()

單例模式-懶漢式執行緒安全及高效率的問題


public Bank getInstance() {

if (bank == null) {

     synchronized (this) {

          if (bank == null) {

               bank = new Bank();

                                        }
               }
         }

 return bank;

}

執行緒的生命週期:

執行緒的生命週期圖

執行緒的同步機制:解決執行緒的安全問題

出現執行緒安全問題的原因:

當一個執行緒在操作共享資料的過程中,還沒有執行結束,另外的執行緒就參與進來,同樣的去操作共享資料,就導致了出現了執行緒安全的問題

如何解決:

必須讓一個執行緒完整的操作完共享資料之後,其他的執行緒才可以參與進來,繼續操作共享資料。

java同步機制

同步程式碼塊:

synchronized(同步監視器){

 //需要被同步的程式碼

   }

同步方法:

public synchronized void show(){

//方法體

}

除了synchronized關鍵字之外,還可以定義一個可重入鎖的變數

private ReentrantLock lock = new ReentrantLock();

lock.clock()

try{

//需要被同步的程式碼塊

}finally{

lock.unlock()}

從Java 5開始,Java提供了更強大的執行緒同步機制——通過顯式定義同步鎖物件來實現同步。同步鎖使用Lock物件充當。 Lock是控制多個執行緒對共享資源進行訪問的工具。鎖提供了對共享資源的獨佔訪問,每次只能有一個執行緒對Lock物件加鎖,執行緒開始訪問共享資源之前應先獲得Lock物件。 在實現執行緒安全的控制中,比較常用的是ReentrantLock(可重入鎖),可以顯式加鎖、釋放鎖。

說明:

     1.需要被同步的程式碼,即為操作共享資料的程式碼

     2.共享資料:多個執行緒共同操作的變數。

     3.同步監視器,俗稱鎖。哪個執行緒獲取了鎖,哪個執行緒就執行大括號中需要被執行的程式碼。其它的執行緒在外面等待。

共享資料的訪問許可權必須是private,以保證當前執行緒訪問資料的時候,工作主記憶體空間的執行緒不能訪問和操作資料。

 >任何一個類的物件都能充當鎖

 >保證執行緒的安全,需要所有的執行緒共用同一把鎖!,(優先考慮this)

釋放鎖的操作:

1、當前執行緒的同步方法、同步程式碼塊執行結束
2、當前執行緒在同步程式碼塊、同步方法中遇到break、return終止了該程式碼塊、該方法的繼續執行。
3、當前執行緒在同步程式碼塊、同步方法中出現了未處理的Error或Exception,導致異常結束
4、當前執行緒在同步程式碼塊、同步方法中執行了執行緒物件的wait()方法,當前執行緒暫停,並釋放鎖。

不會釋放鎖的操作:

1、執行緒執行同步程式碼塊或同步方法時,程式呼叫Thread.sleep()、Thread.yield()方法暫停當前執行緒的執行。
2、執行緒執行同步程式碼塊時,其他執行緒呼叫了該執行緒的suspend()方法將該執行緒掛起,該執行緒不會釋放鎖(同步監視器)。

應儘量避免使用suspend()和resume()來控制執行緒

執行緒通訊

  • wait():一旦執行到此方法,就使得當前執行緒進入阻塞狀態。直到其他執行緒喚醒為止。

  • notify():一旦執行到此方法,就會喚醒其它被wait()的執行緒中優先順序最高的一個。

  • notifyAll():一旦執行到此方法,就會喚醒其它所有被wait()的執行緒

  • 要求:
    1.如上的三個方法必須使用在同步方法或者同步程式碼塊中。

  • 2.如上的三個方法的呼叫者必須是同步方法或者同步程式碼塊的同步監視器!

Java.lang.Object提供的這三個方法只有在synchronized方法或synchronized程式碼塊中才能使用,否則會報如下異常:

java.lang.IllegalMonitorStateException

在當前執行緒中呼叫方法:物件.wait()/wait() 功能,使當前執行緒進入等待(某物件)狀態 ,直到另一執行緒對該物件發出 notify (或notifyAll) 為止。
呼叫方法的必要條件:當前執行緒必須具有對該物件的監控權(加鎖) 呼叫此方法後,當前執行緒將釋放物件監控權 ,然後進入等待 在當前執行緒被notify後,要重新獲得監控權,然後從斷點處繼續程式碼的執行。

在當前執行緒中呼叫方法:物件名.notify() 功能,喚醒等待該物件監控權的一個執行緒。
呼叫方法的必要條件:當前執行緒必須具有對該物件的監控權(加鎖)

死鎖:不同的執行緒分別佔用對方需要的同步資源不放棄,都在等待對方放棄自己需要的同步資源,就形成了執行緒的死鎖