Java線程學習

Java創(chuàng)建一個線程,最簡單的方法就是從Thread類繼承。這個類包含了創(chuàng)建和運行線程所需的一切東西。Tread最重要的方法是run()。但為了使用run(),必須對其進行重載或者覆蓋,使其能充分按自己的吩咐形式。因此,run()屬于那些會與程序中的其他線程“并發(fā)”或“同時”執(zhí)行代碼。

//simpleThread.java
public class SimpleThread extends Thread {
    ......
    public void run(){
        // do something ......
    }
}

Thread包含一個特殊的方法 start(),它的作用是對線程進行特殊的初始化,然后調用 run() 。所以整個步驟包括:調用構建器來構建對象,然后用 start() 配置線程,再調用 run() 。如果不調用 start(),線程便永遠不會啟動。

Java操作共享資源時,為了保證共享資源信息數據一致性,在調用共享資源的方法使用,需要采用“同步”方式操作,即調用"synchronized"方法。調用任何synchronized方法時,對象就會被鎖定,不可再調用那個對象的其它任何synchronized方法,除非第一個方法完成了自己的工作,并解除鎖定。下面列出簡單的synchronized的方法:

    synchronized void f(){
        // do something ......
     }

     synchronized void g(){
        // do something ......
     }

重要規(guī)則:對于訪問某個關鍵共享資源的所有方法,都必須把它們設為synchronized,否則就不能正常地工作。

一個線程的四個狀態(tài):

  • 新(New):線程對象已經創(chuàng)建,但尚未啟動,所以不可運行。
  • 可運行(Runnable):意味著一旦時機分片機制有空閑的CPU周期提供給一個線程,那個線程便立即開始運行。因此,線程可能在、也可能不在運行當中,但一旦條件許可,沒有什么能阻止他的運行——它既沒有“死”掉,也未被“堵塞”。
  • 死(Dead):從自己的run()方法中返回后,一個線程便已“死”掉。亦可調用stop()令其死掉,但會產生一個違例——屬于Error的一個子類(也就是說,我們通常不捕獲它)。記住一個違例的“擲”出應當是一個特殊事件,而不是正常程序運行的一部分。所以不建議你使用stop()(在Java 1.2 則是堅決反對)。另外還有一個destroy()方法(它永遠不會實現),應該盡可能地避免調用它,因為它非常武斷,根本不會解除對象的鎖定。
  • 堵塞(Blocked):線程可以運行,但有某種東西阻礙了它。若線程處于堵塞狀態(tài),調度機制可以簡單地跳過它,不給它分配任何CPU 時間。除非線程再次進入“可運行”狀態(tài),否則不會采取任何操作。

線程為何會堵塞?
堵塞狀態(tài)是前述四種狀態(tài)中最有趣的,值得我們作進一步的探討。線程被堵塞可能是由下述五方面的原因造成的:
1.調用sleep(毫秒數),使線程進入“睡眠”狀態(tài)。在規(guī)定的時間內,這個線程是不會運行的。
2.用suspend()暫停了線程的執(zhí)行。除非線程收到resume()消息,否則不會返回“可運行”狀態(tài)。
3.用wait()暫停了線程的執(zhí)行。除非線程收到nofify()或者notifyAll()消息,否則不會變成“可運行”(是的,這看起來同原因2 非常相象,但有一個明顯的區(qū)別是我們馬上要揭示的)。
4.線程正在等候一些IO(輸入輸出)操作完成。
5.線程試圖調用另一個對象的“同步”方法,但那個對象處于鎖定狀態(tài),暫時無法使用。

亦可調用yield()(Thread 類的一個方法)自動放棄CPU,以便其他線程能夠運行。

死鎖
由于線程可能進入堵塞狀態(tài),而且由于對象可能擁有“同步”方法——除非同步鎖定被解除,否則線程不能訪問那個對象——所以一個線程完全可能等候另一個對象,而另一個對象又在等候下一個對象,以此類推。這個“等候”鏈最可怕的情形就是進入封閉狀態(tài)——最后那個對象等候的是第一個對象!此時,所有線程都會陷入無休止的相互等待狀態(tài),大家都動彈不得。我們將這種情況稱為“死鎖”。

為減少出現死鎖的可能,Java 1.2 作出的一項貢獻是“反對”使用Thread 的stop(),suspend(),resume() 以及destroy()方法。
suspend()和resume() 方法天生容易發(fā)生死鎖。調用suspend()的時候,目標線程會停下來,但卻仍然持有在這之前獲得的鎖定。此時,其他任何線程都不能訪問鎖定的資源,除非被“掛起”的線程恢復運行。

推薦:使用wait()命其進入等待狀態(tài)。若標志指出線程應當恢復,則用一個
notify()重新啟動線程。

線程安全性:當多個線程訪問一個類時,如果不用考慮這些線程在運行時環(huán)境下的調度和交替執(zhí)行,并且不需要額外的同步及在調用方代碼不必做其他的協(xié)調,這個類的行為仍然是正確的,那么稱這個類是線程安全的。對于線程安全類的實例進行順序或并發(fā)的一系列操作,都不會導致實例處于無效狀態(tài)。

無狀態(tài)對象永遠是現場安全的。

原子變量
線程安全性定義要求無論是多線程中的時序或交替操作,都要保證不破壞那些不變約束。當一個不變約束涉及多個變量時,變量間不是彼此獨立的:某個變量的值會制約其他幾個變量的值。因此,更新一個變量的時候,要在同一原子操作中更新其他幾個。

為了保護狀態(tài)的一致性,要在單一的原子操作中更新相互關聯的狀態(tài)變量。

加鎖

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Java多線程學習 [-] 一擴展javalangThread類 二實現javalangRunnable接口 三T...
    影馳閱讀 3,115評論 1 18
  • 本文主要講了java中多線程的使用方法、線程同步、線程數據傳遞、線程狀態(tài)及相應的一些線程函數用法、概述等。 首先講...
    李欣陽閱讀 2,602評論 1 15
  • 一. 概述 使用的線程的目的有如下幾點: 異步。所謂異步,字義上來講就是同時做多個不同的事。例如,你正在和戀人聊Q...
    DCRain閱讀 351評論 0 2
  • 林炳文Evankaka原創(chuàng)作品。轉載自http://blog.csdn.net/evankaka 本文主要講了ja...
    ccq_inori閱讀 741評論 0 4
  • 文章來源:http://www.54tianzhisheng.cn/2017/06/04/Java-Thread/...
    beneke閱讀 1,930評論 0 1

友情鏈接更多精彩內容