<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    無線&移動互聯網技術研發

    換位思考·····
    posts - 19, comments - 53, trackbacks - 0, articles - 283
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    線程理論基礎

    Posted on 2009-07-19 21:10 Gavin.lee 閱讀(314) 評論(0)  編輯  收藏 所屬分類: 多線程
    線程:是指進程中的一個執行流程。換言之:一個程序不同的執行路徑
    進程:實際是靜態文件,所以說進程是個靜態概念,實際運行的都是線程。

    多線程:在同一個應用程序中有多個順序流同時執行
    多進程:在操作系統中能同時運行多個任務(程序)

    線程與進程的區別:每個進程都需要操作系統為其分配獨立的內存地址空間,而同一進程中的所有線程在同一塊地址空間中工作,這些線程可以共享同一塊內存和系統資源。

    請先理解下面這句話:一個進程是一個正運行的應用程序的實例 。它由兩個部分組成:一個是操作系統用來管理這個進程的內核對象。另一個是這個進程擁有的地址空間。從執行角度方面看,一個進程由一個或多個線程組成。一個線程是一個執行單元,它控制CPU執行進程中某一段代碼段。一個線程可以訪問這個進程中所有的地址空間和資源。一個進程最少包括一個線程來執行代碼,這個線程又叫做主線程。  線程除了能夠訪問進程的資源外,每個線程還擁有自己的棧


    創建線程有兩種方式,如下:
    1、 擴展java.lang.Thread類,重載run
    2、 實現Runnable接口,重寫run
    Thread類代表線程類,它的兩個最主要的方法是:
    run()——包含線程運行時所執行的代碼(線程體)
    start()——用于啟動線程


    一個線程只能被啟動一次。第二次啟動時將會拋出java.lang.IllegalThreadExcetpion異常

    在同一個時間點,一個CPU只支持一個線程

    真正的多線程只存在與多CPU

    所以說但CPU操作系統只能說支持多線程

                   

    兩種線程模式
    協作式:一個線程保留對處理器的控制直到它自己決定放棄 
                 a.速度快、代價低 
                 b.用戶編程非常麻煩 
    搶先式:系統可以任意的從線程中奪回對CPU的控制權,再把控制權分給其它的線程 。
                 a.兩次切換之間的時間間隔就叫做時間片 
                 b.效率不如協作式高 ,OS核心必須負責管理線程 
                 c.簡化編程,而且使程序更加可靠
    多數線程的調度是搶先式的

    同一個線程類,可new出兩個線程對象




    線程:是指進程中的一個執行流程。
    線程與進程的區別:每個進程都需要操作系統為其分配獨立的內存地址空間,而同一進程中的所有線程在同一塊地址空間中工作,這些線程可以共享同一塊內存和系統資源。


    如何創建一個線程?

    創建線程有兩種方式,如下:
    1、 擴展java.lang.Thread類
    2、 實現Runnable接口
    Thread類代表線程類,它的兩個最主要的方法是:
    run()——包含線程運行時所執行的代碼
    Start()——用于啟動線程

    一個線程只能被啟動一次。第二次啟動時將會拋出java.lang.IllegalThreadExcetpion異常

    線程間狀態的轉換(如圖示)

    新建狀態:用new語句創建的線程對象處于新建狀態,此時它和其它的java對象一樣,僅僅在堆中被分配了內存
    就緒狀態:當一個線程創建了以后,其他的線程調用了它的start()方法,該線程就進入了就緒狀態。處于這個狀態的線程位于可運行池中,等待獲得CPU的使用權
    運行狀態:處于這個狀態的線程占用CPU,執行程序的代碼
    阻塞狀態:當線程處于阻塞狀態時,java虛擬機不會給線程分配CPU,直到線程重新進入就緒狀態,它才有機會轉到運行狀態。
    阻塞狀態分為三種情況:
    1、 位于對象等待池中的阻塞狀態:當線程運行時,如果執行了某個對象的wait()方法,java虛擬機就回把線程放到這個對象的等待池中
    2、 位于對象鎖中的阻塞狀態,當線程處于運行狀態時,試圖獲得某個對象的同步鎖時,如果該對象的同步鎖已經被其他的線程占用,JVM就會把這個線程放到這個對象的瑣池中。
    3、 其它的阻塞狀態:當前線程執行了sleep()方法,或者調用了其它線程的join()方法,或者發出了I/O請求時,就會進入這個狀態中。

    死亡狀態:當線程退出了run()方法,就進入了死亡狀態,該線程結束了生命周期。
    或者正常退出
    或者遇到異常退出
    Thread類的isAlive()方法判斷一個線程是否活著,當線程處于死亡狀態或者新建狀態時,該方法返回false,在其余的狀態下,該方法返回true.

    線程調度
    線程調度模型:分時調度模型和搶占式調度模型
    JVM采用搶占式調度模型。
    所謂的多線程的并發運行,其實是指宏觀上看,各個線程輪流獲得CPU的使用權,分別執行各自的任務。
    (線程的調度不是跨平臺,它不僅取決于java虛擬機,它還依賴于操作系統)

    如果希望明確地讓一個線程給另外一個線程運行的機會,可以采取以下的辦法之一
    1、 調整各個線程的優先級
    2、 讓處于運行狀態的線程調用Thread.sleep()方法
    3、 讓處于運行狀態的線程調用Thread.yield()方法
    4、 讓處于運行狀態的線程調用另一個線程的join()方法

    調整各個線程的優先級
    Thread類的setPriority(int)和getPriority()方法分別用來設置優先級和讀取優先級。
    如果希望程序能夠移值到各個操作系統中,應該確保在設置線程的優先級時,只使用MAX_PRIORITY、NORM_PRIORITY、MIN_PRIORITY這3個優先級。

    線程睡眠:當線程在運行中執行了sleep()方法時,它就會放棄CPU,轉到阻塞狀態。
    線程讓步:當線程在運行中執行了Thread類的yield()靜態方法時,如果此時具有相同優先級的其它線程處于就緒狀態,那么yield()方法將把當前運行的線程放到運行池中并使另一個線程運行。如果沒有相同優先級的可運行線程,則yield()方法什么也不做。
    Sleep()方法和yield()方法都是Thread類的靜態方法,都會使當前處于運行狀態的線程放棄CPU,把運行機會讓給別的線程,兩者的區別在于:
    1、sleep()方法會給其他線程運行的機會,而不考慮其他線程的優先級,因此會給較低線程一個運行的機會;yield()方法只會給相同優先級或者更高優先級的線程一個運行的機會。
    2、當線程執行了sleep(long millis)方法后,將轉到阻塞狀態,參數millis指定睡眠時間;當線程執行了yield()方法后,將轉到就緒狀態。
    3、sleep()方法聲明拋出InterruptedException異常,而yield()方法沒有聲明拋出任何異常
    4、sleep()方法比yield()方法具有更好的移植性

    等待其它線程的結束:join()
    當前運行的線程可以調用另一個線程的 join()方法,當前運行的線程將轉到阻塞狀態,直到另一個線程運行結束,它才恢復運行。

    定時器Timer:在JDK的java.util包中提供了一個實用類Timer, 它能夠定時執行特定的任務。

    線程的同步
    原子操作:根據Java規范,對于基本類型的賦值或者返回值操作,是原子操作。但這里的基本數據類型不包括long和double, 因為JVM看到的基本存儲單位是32位,而long 和double都要用64位來表示。所以無法在一個時鐘周期內完成。

    自增操作(++)不是原子操作,因為它涉及到一次讀和一次寫。

    原子操作:由一組相關的操作完成,這些操作可能會操縱與其它的線程共享的資源,為了保證得到正確的運算結果,一個線程在執行原子操作其間,應該采取其他的措施使得其他的線程不能操縱共享資源。

    同步代碼塊:為了保證每個線程能夠正常執行原子操作,Java引入了同步機制,具體的做法是在代表原子操作的程序代碼前加上synchronized標記,這樣的代碼被稱為同步代碼塊。

    同步鎖:每個JAVA對象都有且只有一個同步鎖,在任何時刻,最多只允許一個線程擁有這把鎖。

    當一個線程試圖訪問帶有synchronized(this)標記的代碼塊時,必須獲得 this關鍵字引用的對象的鎖,在以下的兩種情況下,本線程有著不同的命運。
    1、 假如這個鎖已經被其它的線程占用,JVM就會把這個線程放到本對象的鎖池中。本線程進入阻塞狀態。鎖池中可能有很多的線程,等到其他的線程釋放了鎖,JVM就會從鎖池中隨機取出一個線程,使這個線程擁有鎖,并且轉到就緒狀態。
    2、 假如這個鎖沒有被其他線程占用,本線程會獲得這把鎖,開始執行同步代碼塊。
    (一般情況下在執行同步代碼塊時不會釋放同步鎖,但也有特殊情況會釋放對象鎖
    如在執行同步代碼塊時,遇到異常而導致線程終止,鎖會被釋放;在執行代碼塊時,執行了鎖所屬對象的wait()方法,這個線程會釋放對象鎖,進入對象的等待池中)

    線程同步的特征:
    1、 如果一個同步代碼塊和非同步代碼塊同時操作共享資源,仍然會造成對共享資源的競爭。因為當一個線程執行一個對象的同步代碼塊時,其他的線程仍然可以執行對象的非同步代碼塊。(所謂的線程之間保持同步,是指不同的線程在執行同一個對象的同步代碼塊時,因為要獲得對象的同步鎖而互相牽制)
    2、 每個對象都有唯一的同步鎖
    3、 在靜態方法前面可以使用synchronized修飾符。
    4、 當一個線程開始執行同步代碼塊時,并不意味著必須以不間斷的方式運行,進入同步代碼塊的線程可以執行Thread.sleep()或者執行Thread.yield()方法,此時它并不釋放對象鎖,只是把運行的機會讓給其他的線程。
    5、 Synchronized聲明不會被繼承,如果一個用synchronized修飾的方法被子類覆蓋,那么子類中這個方法不在保持同步,除非用synchronized修飾。

    線程安全的類:
    1、 這個類的對象可以同時被多個線程安全的訪問。
    2、 每個線程都能正常的執行原子操作,得到正確的結果。
    3、 在每個線程的原子操作都完成后,對象處于邏輯上合理的狀態。

    釋放對象的鎖:
    1、 執行完同步代碼塊就會釋放對象的鎖
    2、 在執行同步代碼塊的過程中,遇到異常而導致線程終止,鎖也會被釋放
    3、 在執行同步代碼塊的過程中,執行了鎖所屬對象的wait()方法,這個線程會釋放對象鎖,進入對象的等待池。

    死鎖
    當一個線程等待由另一個線程持有的鎖,而后者正在等待已被第一個線程持有的鎖時,就會發生死鎖。JVM不監測也不試圖避免這種情況,因此保證不發生死鎖就成了程序員的責任。

    如何避免死鎖
    一個通用的經驗法則是:當幾個線程都要訪問共享資源A、B、C 時,保證每個線程都按照同樣的順序去訪問他們。

    線程通信
    Java.lang.Object類中提供了兩個用于線程通信的方法
    1、 wait():執行了該方法的線程釋放對象的鎖,JVM會把該線程放到對象的等待池中。該線程等待其它線程喚醒
    2、 notify():執行該方法的線程喚醒在對象的等待池中等待的一個線程,JVM從對象的等待池中隨機選擇一個線程,把它轉到對象的鎖池中。





    主站蜘蛛池模板: 亚洲国产精品免费观看| 亚洲一区精品视频在线| 美女视频黄频a免费观看| 无码一区二区三区免费视频 | 国产亚洲精品激情都市| 一区免费在线观看| 亚洲五月午夜免费在线视频| 亚洲一级片免费看| 亚洲日韩激情无码一区| 免费无码一区二区三区蜜桃| 国产AV无码专区亚洲AV毛网站 | 337p日本欧洲亚洲大胆艺术| 99久久久国产精品免费蜜臀| 亚洲熟妇无码爱v在线观看| 思思re热免费精品视频66| 亚洲一区二区三区成人网站| 国产极品美女高潮抽搐免费网站| 青娱乐在线视频免费观看| 中文字幕亚洲电影| 日韩免费人妻AV无码专区蜜桃| 亚洲综合色丁香麻豆| 毛片免费在线视频| 青娱乐在线视频免费观看| 亚洲va中文字幕无码久久 | 91嫩草免费国产永久入口| 亚洲AV无码一区二区三区牛牛| 日本高清色本免费现在观看| 一级毛片高清免费播放| 精品国产_亚洲人成在线高清| 亚洲免费二区三区| 粉色视频在线观看www免费| 亚洲日韩国产精品第一页一区| 131美女爱做免费毛片| 国产亚洲综合精品一区二区三区| 国产亚洲精品久久久久秋霞| 老司机在线免费视频| 羞羞漫画小舞被黄漫免费| 久久精品亚洲一区二区| 午夜网站免费版在线观看| 三级黄色在线免费观看| 亚洲欧美黑人猛交群|