1. 程式人生 > >API-執行緒程序

API-執行緒程序

執行緒:還會涉及到一些名詞概念:
          程式,程序,執行緒,多程序,多執行緒
 程序中所包含的一個或多個執行單元稱為執行緒,一個執行緒就是程序中的一個順序執行流。
程序擁有一個私有的虛擬地址空間,該空間僅能被它所包含的執行緒訪問。即同一個程序
中的多個執行緒共享一塊記憶體空間和一組系統資源。
執行緒只能歸屬於一個程序並且它只能訪問該程序所擁有的資源。
執行緒本身也有一個供程式執行時的堆疊,線上程切換時,負荷小,因此執行緒也被稱之為輕
負荷程序。
併發原理
       多個執行緒"同時執行"只是我們感官上的一種表現。其實,執行緒是併發執行的。
       作業系統將時間劃分成很多時間片段,儘可能的均勻分配給每一個執行緒,獲取時間片段
       的執行緒被CPU執行,而其他執行緒處於等待狀態。所以這種微觀上是走走停停,斷斷續續
       的,巨集觀上都在執行的現象叫併發。
       但不是絕對意義上的"同時發生"。 
 
程序:是一個執行中的程式的例項。          
程序的兩個特點:
    (1)是一個實體,都有自己獨立的地址空間,分為文字區域,資料區域和堆疊。
              文字區域用來儲存編寫的程式的程式碼,資料區域用來儲存執行時所需要的
              資料(動態分配的記憶體),堆疊用來儲存執行時涉及到的指令和本地變數
    (2)是一個"執行中的程式",程式本身是一個沒有生命的實體,只有當處理器
             賦予它生命時,它才能稱之為一個活動的實體,即程序。
程序是作業系統級別的基本單元。
通俗點說:程序就是作業系統執行的一個任務(一個應用程式執行時,就對應一個程序) 
程式,程序,執行緒,多程序,多執行緒
(1)程式:可以實現多個功能的程式碼體。也叫軟體。
(2)程序:有兩個特點
       -- 是一個實體:有自己的地址空間,如文字區域,資料區域,堆疊區域
       -- 是一個執行中的程式,cpu賦予程式生命時,就是一個程序。
      程序是作業系統的一個任務
(3)執行緒:是程序裡的一個任務,是一個順序執行流。
                有自己獨立的堆疊,與其他執行緒共享程序的地址空間
(4)多程序:針對於古老的作業系統來說,現在的作業系統都是多程序的。
                 可以同時執行多個程式
(5)多執行緒:一個程序中的多個任務,可以同時進行多個順序執行流。
               好處:  
               1)提高cpu的資源利用率
               2)可以共享同一個資源(靜態資源,同一個物件例項)

執行緒的狀態圖解析:
(1) 新建狀態: 即新建一個執行緒物件,設定好需要執行的任務
(2) 就緒狀態: 呼叫執行緒的start方法,進入準備狀態,等待cpu分配時間片段
(3) 執行狀態: 當cpu將時間片段給了執行緒物件後,執行緒開始執行任務。
(4) 阻塞狀態:正在執行中的執行緒由於某種原因,放棄了cpu的使用權
                            即該執行緒放棄時間片段,進入阻塞狀態。
         阻塞狀態分為三種:
         等待阻塞: 執行中的執行緒呼叫wait方法時,jvm將
              此執行緒放入等待池中   
         同步阻塞:執行中的執行緒想要獲取同步的鎖物件時,如果鎖物件被其他佔用,
                         則,jvm將此執行緒放入鎖池中
         其他阻塞: 當執行緒中執行到阻塞方法或者是Thread.sleep()或者是其他執行緒的join
                          時,該執行緒進行阻塞狀態
(5) 當執行緒執行完任務後,表示結束。

執行緒的建立方式(3種)
   (1)繼承Thread類,重寫run方法,定義任務內容。然後呼叫
       start方法,用於啟動執行緒。(切記,不是呼叫run方法)
   (2)實現介面Runnable,重寫run方法,定義任務內容,然後將任務
            傳給Thread物件,然後由Thread呼叫start方法,執行任務
   (3)使用FutureTask建立物件,再使用Callable建立子類物件,
            重寫call方法(相當於run方法),再將Callable物件傳給
      FutureTask,再將FutureTask物件傳給Thread物件,呼叫
      start方法,啟動執行緒  
      
 第二種方式與第一種比較,
 (1)將執行緒物件和任務物件分開,降低了耦合度,便於維護     
 (2)避免了java中單繼承的限制
 (3)適合相同的任務程式碼塊處理同一個資源
 第三種方式:call方法帶有返回值。
 
執行緒API:
  常用構造器:
     Thread(Runnable r):
           建立一個指定任務的執行緒物件 
     Thread(Runnable r,String name)
          建立一個指定任務,並且指定名稱的執行緒物件      
     Thread(String name)
          建立一個指定名稱的執行緒物件
 常用方法:
     long getId() 返回此執行緒的ID
     String getName()返回此執行緒的名稱
     int getPriority()返回此執行緒的優先順序
     Thread.State getState() 返回此執行緒的狀態
     boolean isAlive() 測試這個執行緒是否活著
     boolean isDaemon()測試這個執行緒是否是守護執行緒
     void setDaemon(boolen on) 形參填true的話,表示設定為守護執行緒
     void setPriority(int newPriority)更改此執行緒的優先順序
     

練習:
    桌子上總共有20個豆子,有兩個人來取豆子,每個人每次只
    能取一個豆子。並輸出桌子上剩餘的豆子數。
    
執行緒排程:
     多執行緒時,誰先執行是不可控的,是由cpu的執行緒排程來分配的。
    但是我們可以通過執行緒的優先順序來儘可能的讓執行緒排程來調控執行緒
    所需要的時間片段
執行緒的優先順序:
1-10,10為最高級別,1為最低級別,5為預設級別
Thread.MIN_PRIORITY--最小優先順序
Thread.MAX_PRIORITY--最高優先順序
Thread.NORM_PRIORITY--預設優先順序

守護執行緒:執行緒分兩類,一類是普通執行緒(前臺執行緒),
                  一類是守護執行緒(後臺執行緒)。
            當執行緒只剩下守護執行緒後,所有執行緒都結束。  
            
            
static sleep(long time):
  執行緒的靜態方法,用於使當前執行緒進入阻塞狀態,時間為time毫秒。
 time毫秒後,會進入就緒狀態。如果期間被打斷,會出現異常
 InterruptException            
   
void interrupt()
      打斷阻塞狀態下的執行緒物件。
join():
    作用是將當前執行緒插入到某一個執行緒中,使某一個執行緒進入阻塞狀態。
    當前執行緒執行完後,另一個執行緒進入就緒狀態。
static void yield()
     執行緒物件讓步的功能:讓出時間片段,此執行緒進入就緒狀態。
 
同步鎖:
   當多個執行緒操作臨界資源時,可能會出現執行緒安全隱患問題。
   臨界資源可能是:
  (1)某一個靜態變數
  (2)某一個例項變數
  如果想解決這樣的問題,需要使用同步操作。
  
  非同步操作:多執行緒的併發操作,相當於各幹各的
  同步操作:相當於一個做完,另一個再做。
  
 執行緒在內部提供了一個內建的鎖機制保證原子性,用於執行緒進行同步操作。
 鎖需要兩點:
 (1) 鎖是一個物件,
 (2) 如果想進行同步,多個現象操作的必須是同一個鎖
     synchronized(鎖物件的引用){
            需要同步的程式碼塊
     }
鎖機制:當一個執行緒進入同步的程式碼塊後,就會獲得鎖物件的使用權。其他線
         程如果執行到此處,會發現鎖物件被佔用,只能處於等待狀態(鎖池),
         當執行緒執行完同步的程式碼後或者出現異常,都會自動釋放鎖。
        
合適的鎖物件:
    必須是一個引用型別,而且必須使多個執行緒都可以使用這個鎖物件,
    因此this物件比較適合

同步程式碼塊的範圍:
    (1)可以是方法內的一部分程式碼,可以也是全部程式碼(相當於給方法上了鎖)
    (2)成員方法上新增修飾詞synchronized,鎖物件為this
             如果一個類的所有成員方法都使用了同步關鍵字,當某一個執行緒
            操作了其中一個方法,另外的執行緒即使操作的不是這個方法,
            也會進入鎖池狀態 
        
    (3)靜態方法上也可以新增synchronized,鎖物件為類物件,
              呼叫方法:類名.class,每一種類都有一個唯一的類物件            
     

wait()/notify()notifyAll():
上述的方法都是Object型別提供的,用來調控執行緒的狀態的。
使用位置必須是同步塊中,如果不是同步塊中,會報異常

wait():
     當前獲取鎖物件的執行緒準備釋放鎖,給其他執行緒獲取鎖的機會。
wait(long time):
     當前獲取鎖物件的執行緒如果沒有被通知,在延遲time毫秒後,自動釋放鎖物件
wait(long time,int naons):
     功能一樣,只不過比上一個方法延遲的時間更加精確。

notify()/notifyAll():
  當前獲取鎖物件的執行緒準備釋放鎖,使用此方法通知處於使用wait方法等待的執行緒,
 natify():只會隨機通知等待執行緒中的其中一個。
 notifyAll():通過所有等待的執行緒來競爭鎖。
 
 
生產者--消費者--倉庫模式:此模式脫離了倉庫沒有任何意義。
(1)倉庫用來儲存資料。
(2)倉庫不滿的情況下,生產者可以生產
(3)倉庫中滿足消費者的需求時,消費者就可以消費

/*作業1:
   第一個執行緒輸出1,2,3,4,5
   第二個執行緒輸出6,7,8,9,10
   第三個執行緒輸出11,12,13,14,15
   第一個執行緒輸出16,17,18,19,20
   第二個執行緒輸出..........
   第三個執行緒輸出........
   直到輸入75停止。
   作業2:
         模擬小張一家四口(小張,小張媳婦,小張他爸,小張他媽)
        分別拿著小張的銀行卡去銀行存取錢。  
*/
 前提:有多個執行緒時
 非同步操作:多個執行緒同時開啟,微觀上斷斷續續,巨集觀上同時發生
                斷斷續續:同一個方法內的兩行程式碼不一定是兩個挨
                                 著的時間片段
 同步操作:在併發的基礎上,同一個方法內的兩行程式碼執行時間片段
               可以不挨著,但是其他執行緒不能對這兩行程式碼的執行權 ,
              保證了程式碼的原子性。即這兩行程式碼是同步的,當前執行緒執行完後,
              其他執行緒才有執行權。
想實現同步操作,提供了一個鎖機制。
        我們將需要同步的程式碼加上一個內建鎖物件,當某一個執行緒
      執行到此程式碼時,會獲取鎖物件,其他執行緒需要等待。當獲取鎖物件的
      執行緒執行完同步塊(或者是因為異常)都會釋放鎖物件。其他執行緒
      通過cpu的執行緒呼叫才有機會獲取鎖物件的使用權

    synchronized(鎖物件){
    }  
    
     鎖物件:多個執行緒一定要使用同一個鎖,否則沒有記性同步操作
=====================================
執行緒池:
   (1)如果每個任務都需要建立執行緒物件,記憶體開銷大
   (2)方便管理執行緒物件。
執行緒池的原理: 就是一些執行緒的集合,執行緒的狀態不
                    是死亡狀態,當執行緒池接收外面的任務時,
                    執行緒池的管理器會檢視是否有空閒執行緒,如果
                    有,就會將任務分配給它,如果沒有,任務處於
                    等待佇列中.
執行緒池的型別:ExecutorService
另外一個類Executors裡提供了多個靜態方法
       來獲取執行緒池物件
       
    方法1:
    newSingleThreadExecutor():
       獲取單個執行緒的執行緒池物件,內部維護了一個無界佇列用於儲存任務 
  方法2:
    newFixedThreadPool(int nThreads) 
       建立一個固定數量執行緒的執行緒池,維護一個為無界佇列
   方法3:
    newCachedThreadPool()
       建立一個可以根據需求來建立新執行緒的執行緒池物件,如果有可
       重用的,會優先使用。
   方法4:   
    newScheduledThreadPool(int corePoolSize)
       建立一個執行緒池,可以進行設定延遲或者是定時來執行任務 
4 24  4 1 4