天天看點

java筆記六:線程間的協調

  比如說在銀行開個賬戶會有一個存折和一張卡,如果某一天同一時間丈夫拿着存折去

櫃台取錢,而妻子拿着銀行卡去atm取錢。當丈夫查詢餘額裡面有3000元,正準備取2000元,這時候妻子也到atm裡面查詢也有3000,也取

2000元。其實銀行不可能讓我們這麼做,如果這樣的話那我們天天取錢去了,還搞什麼工作啊。其實在丈夫查詢的時候已經對該賬号上了鎖,另外的銀行卡要取

錢的話必須等待該鎖被釋放。下面用一個程式模拟這個例子:

  上面的例子如果在getmoney()方法上面不加synchronized關鍵字的話,輸出結果為:

wife取走了2000元

husband取走了2000元

  而加上synchronized後,輸出結果為:

對不起,您的餘額不足!

  上面兩種情況說明,如果多個線程同時通路某個資源,而不給該資源枷鎖的話,就會出現問題。而加上synchronized關鍵字後就可以避免這種錯誤發生了。它能夠保證隻有一個線程能夠通路getmoney()這個方法,其他藥通路該方法的線程必須等待。

鎖住某個資源可以用synchronized關鍵字來修飾一個方法或者同步代碼塊,這樣能保證同一時間隻能由一個線程通路該資源。

    ①、當兩個并發線程通路同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間内隻能有一個線程得到執行。另一個線程必須等待目前線程執行完這個代碼塊以後才能執行該代碼塊。

      ②、然而,當一個線程通路object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以通路該object中的非synchronized(this)同步代碼塊。

        ③、尤其關鍵的是,當一個線程通路object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的通路将被阻塞。

  我們都知道,作業系統中多個程序之間如果不進行協調就很容易出現死鎖的情況,死鎖的四個條件:互斥、占有等待、非剝奪、循環等待。我們隻要破壞其中一個條件就能避免死鎖發生。線程之間也容易出現死鎖,下面這個例子就示範了死鎖的情況:

  運作程式輸出1    0後就進入死鎖狀态,該程式永遠也不會停止,因為兩個線程同時處于等待狀态。線程t1鎖住了o1對象,等待o2對象,而線程t2鎖住o2等待o2對象,誰也不讓誰,這就進入了一個循環占有等待的情況了,死鎖也就出現了。

  是以,如果多個線程如果不進行協調的話很容易出現死鎖的問題。作業系統中使用程序排程來協調各個程序,那麼java重如何對各個線程進行協調呢?

  java中主要使用object類中的wait()、notify()、notifyall()方法來協調各個線程。典型的例子有哲學家吃飯問題、生産者和消費者問題、理發師問題。下面一個用一個例子來示範生産者和消費者問題。

  問題描述:生産者負責做饅頭,做好饅頭後放進指定的簍子裡面,消費者消費該簍子裡面的饅頭。簍子裡隻能裝一定量的饅頭,滿了以後生産者必須進入等待狀态,消費者吃完饅頭後也必須進入等待狀态。

  wait()、notify()、notifyall()方法的作用:

    notify():喚醒在此對象螢幕上等待的單個線程。

    notifyall():喚醒在此對象螢幕上等待的所有線程。

  wait()與sleep()的差別:

    兩個方法的共同點就是讓目前線程進入等待狀态。

    不同點:

    wait()之後,鎖就不歸我所有了,必須等醒過來後才能擁有該鎖,并且必須要有人喚醒它才會醒過來

sleep()不同,鎖還是歸我所有,一段時間後會自動醒過來