多個進程的內部數據和狀態都是完全獨立的,而多線程是共享一塊內存空間和一組系統資源,有可能互相影響. ?線程本身的數據通常只有寄存器數據,以及一個程序執行時使用的堆棧,所以線程的切換比進程切換的負擔要小。多線程編程的目的,就是"最大限度地利用 CPU 資源",當某一線程的處理不需要占用 CPU 而只和 I/O 等資源打交道時,讓需要占用 CPU 資源的其它線程有機會獲得 CPU 資源。從根本上說,這就是多線程編程的最終目的。二、了解一下 java 在多線程中的基礎知識1.Java 中如果我們自己沒有產生線程,那么系統就會給我們產生一個線程(主線程, main 方法就在主線程上運行) , 我們的程序都是由線程來執行的。2. 進程:執行中的程序(程序是靜態的概念,進程是動態的概念)。3. 線程的實現有兩種方式, 第一種方式是繼承 Thread 類 , 然后重寫 run 方法;第二種是實現 Runnable 接口,然后實現其 run 方法。4. 將我們希望線程執行的代碼放到 run 方法中,然后通過 start 方法來啟動線程,start 方法首先為線程的執行準備好系統資源 , 然后再去調用 run 方法 。 。當某個類繼承了 Thread 類之后,該類就叫做一個線程類。5. 一個進程至少要包含一個線程。6. 對于單核 CPU 來說,某一時刻只能有一個線程在執行(微觀串行),從宏觀角度來看,多個線程在同時執行(宏觀并行)。7. 對于雙核或雙核以上的 CPU 來說,可以真正做到微觀并行。三、Thread 源碼研究:1) Thread 類也實現了 Runnable 接口,因此實現了 Runnable 接口中的 run方法;2) 當生成一個線程對象時,如果沒有為其設定名字,那么線程對象的名字將使用如下形式:Thread-number,該 number 將是自動增加的,并被所有的Thread 對象所共享(因為它是 static 的成員變量)。3) 當使用第一種方式來生成線程對象時,我們需要重寫 run 方法,因為Thread 類的 run 方法此時什么事情也不做。4)當使用第二種方式生成線程對象時,我們需要實現 Runnable 接口的 run方法,然后使用 new Thread(new MyThread())(假如 MyThread 已經實現了 Runnable 接口)來生成線程對象,這時的線程對象的 run 方法或調就會 MyThread 類的 run 方法,這樣我們自己編寫的 run 方法就執行了。說明:Public void run(){If(target!=null){Target.run();}}當使用繼承 Thread 生成線程對象時,target 為空,什么也不執行,當使用第二種方式生成時,執行 target.run(),target 為 runnable 的實例對象,即為執行重寫后的方法。總結:兩種生成線程對象的區別:1.兩種方法均需執行線程的 start 方法為線程分配必須的系統資源、 調度線程運行并執行線程的 run 方法。2.在具體應用中,采用哪種方法來構造線程體要視情況而定。通常,當一個線程已繼承了另一個類時,就應該用第二種方法來構造,即實現 Runnable接口。四:線程的生命周期:由上圖可以看出,一個線程由出生到死亡分為五個階段:
1 )創建狀態?當用 new 操作符創建一個新的線程對象時,該線程處于創建狀態。?處于創建狀態的線程只是一個空的線程對象,系統不為它分配資源2 )可運行狀態?執行線程的 start()方法將為線程分配必須的系統資源,安排其運行,并調用線程體—run()方法,這樣就使得該線程處于可運行( Runnable )狀態。?這一狀態并不是運行中狀態(Running ),因為線程也許實際上并未真正運行。3)不可運行狀態.當發生下列事件時,處于運行狀態的線程會轉入到不可運行狀態。調用了 sleep()方法;?線程調用 wait 方法等待特定條件的滿足?線程輸入/輸出阻塞4) 返回可運行狀態:?處于睡眠狀態的線程在指定的時間過去后?如果線程在等待某一條件,另一個對象必須通過 notify()或 notifyAll()方法通知等待線程條件的改變?如果線程是因為輸入/輸出阻塞,等待輸入/輸出完成5)消亡狀態當線程的 run 方法執行結束后,該線程自然消亡。注意:1.停止線程的方式:不能使用 Thread 類的 stop 方法來終止線程的執行。一般要設定一個變量,在 run 方法中是一個循環,循環每次檢查該變量,如果滿足條件則繼續執行,否則跳出循環,線程結束。2.不能依靠線程的優先級來決定線程的執行順序。五:多線程并發 多線程并發是線程同步中比較常見的現象,java 多線程為了避免多線程并發解決多線程共享數據同步問題提供了 synchronized 關鍵字synchronized 關鍵字: 當 synchronized 關鍵字修飾一個方法的時候, 該方法叫做同步方法。1.Java 中的每個對象都有一個鎖(lock)或者叫做監視器(monitor),當訪問某個對象的 synchronized 方法時,表示將該對象上鎖,此時其他任何線程都無法再去訪問該 synchronized 方法了, 直到之前的那個線程執行方法完畢后(或者是拋出了異常),那么將該對象的鎖釋放掉,其他線程才有可能再去訪問該 synchronized 方法。2. 如果一個對象有多個 synchronized 方法, 某一時刻某個線程已經進入到了某個 synchronized 方法,那么在該方法沒有執行完畢前,其他線程是無法訪問該對象的任何 synchronized 方法的。3.如果某個 synchronized 方法是 static 的,那么當線程訪問該方法時,它鎖的并不是 synchronized 方法所在的對象,而是 synchronized 方法所在的對象所對應的 Class 對象,因為 Java 中無論一個類有多少個對象,這些對象會對應唯一一個 Class 對象,因此當線程分別訪問同一個類的兩個對象的兩個 static,synchronized 方法時,他們的執行順序也是順序的,也就是說一個線程先去執行方法,執行完畢后另一個線程才開始執行。4. synchronized 塊,寫法:synchronized(object){}表示線程在執行的時候會對 object 對象上鎖。六: t wait 與 與 notify1.wait 與 notify 方法都是定義在 Object 類中, 而且是 final 的, 因此會被所有的 Java 類所繼承并且無法重寫。這兩個方法要求在調用時線程應該已經獲得了對象的鎖, 因此對這兩個方法的調用需要放在 synchronized 方法或塊當中。當線程執行了 wait 方法時,它會釋放掉對象的鎖。2. 另一個會導致線程暫停的方法就是 Thread 類的 sleep 方法,它會導致線程睡眠指定的毫秒數,但線程在睡眠的過程中是不會釋放掉對象的鎖的。3.notify():喚醒在此對象監視器上等待的單個線程。如果所有線程都在此對象上等待,則會選擇喚醒其中一個線程。選擇是任意性的,并在對實現做出決定時發生。線程通過調用其中一個 wait 方法,在對象的監視器上等待。
新聞熱點
疑難解答