Java多線程(二)

1、線程的七種狀態

一、初始狀態(New):新建立了一個線程對象。
二、就緒狀態(Runnable):線程對象建立後,其餘線程調用了該對象的start()方法。該狀態的線程位於可運行線程池中,變得可運行,等待獲取CPU的使用權。
三、運行狀態(Running):就緒狀態的線程獲取了CPU,執行程序代碼。
四、阻塞狀態(Blocked):阻塞狀態是線程由於某種緣由放棄CPU使用權,暫時中止運行。直到線程進入就緒狀態,纔有機會轉到運行狀態。阻塞的狀況分三種:
     1)等待阻塞:運行的線程執行wait()方法,JVM會把該線程放入等待池中。(wait會釋放持有的鎖)
     2)同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程佔用,則JVM會把該線程放入鎖池中。
     3)其餘阻塞:運行的線程執行sleep()或join()方法,或者發出了I/O請求時,JVM會把該線程置爲阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、或者I/O處理完畢時,線程從新轉入就緒狀態。(注意,sleep是不會釋放持有的鎖)
五、死亡狀態(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命週期。
下面爲線程中的 7 中很是重要的狀態:(有的書上也只有認爲前五種狀態,而將「鎖池」和「等待池」都當作是「阻塞」狀態的特殊狀況,這種認識也是正確的,可是將「鎖池」和「等待池」單獨分離出來有利於對程序的理解)

 

2、線程的優先級

線程的優先級表明該線程的重要程度,當有多個線程同時處於可執行狀態並等待得到 CPU 時間時,線程調度系統根據各個線程的優先級來決定給誰分配 CPU 時間,優先級高的線程有更大的機會得到 CPU 時間,優先級低的線程也不是沒有機會,只是機會要小一些罷了。你能夠調用 Thread 類的方法 getPriority() setPriority()來存取線程的優先級,線程的優先級界於1MIN_PRIORITY)和10MAX_PRIORITY)之間,缺省是5NORM_PRIORITY)。編程

 1 public class ThreadPriority {
 2     public static void main(String[] args) {
 3         Thread t1 = new MyThread1();
 4         Thread t2 = new Thread(new MyThread2());
 5         t1.setPriority(10);
 6         t2.setPriority(1);
 7         t1.start();
 8         t2.start();
 9     }
10 }
11 
12 class MyThread1 extends Thread {
13     @Override
14     public void run() {
15         for (int i = 0; i < 10; i++) {
16             System.out.println("線程 1 第 " + i + "次執行!");
17             try {
18                 Thread.sleep(100);
19             } catch (InterruptedException e) {
20                 e.printStackTrace();
21             }
22         }
23     }
24 }
25 
26 class MyThread2 implements Runnable {
27     @Override
28     public void run() {
29         for (int i = 0; i < 10; i++) {
30             System.out.println("線程 2 第 " + i + "次執行!");
31             try {
32                 Thread.sleep(100);
33             } catch (InterruptedException e) {
34                 e.printStackTrace();
35             }
36         }
37     }
38 }

3、線程的同步

       因爲同一進程的多個線程共享同一片存儲空間,在帶來方便的同時,也帶來了訪問衝突這個嚴重的問題。Java 語言提供了專門機制以解決這種衝突,有效避免了同一個數據對象被多個線程同時訪問。 因爲咱們能夠經過 private 關鍵字來保證數據對象只能被方法訪問,因此咱們只需針對方法提出一套機制,這套機制就是 synchronized 關鍵字,它包括兩種用法:synchronized 方法synchronized
一、synchronized 方法:經過在方法聲明中加入 synchronized 關鍵字來聲明 synchronized 方法。 如:
ide

public synchronized void synMethod() {
     //方法體
}

二、synchronized 塊:經過 synchronized 方法來聲明 synchronized 塊 。如:測試

synchronized(syncObject) {  //容許訪問控制的代碼 }

下面是例子:this

 1 public class Synchronized {
 2 
 3     public static void main(String[] args) {
 4         SyncThread t = new SyncThread();
 5         new Thread(t).start();
 6         new Thread(t).start();
 7         new Thread(t).start();
 8         new Thread(t).start();
 9     }
10     
11 }
12 
13 class SyncThread implements Runnable {
14     
15     int num = 10;
16     
17     @Override
18     public void run() {
19         synchronized(this) {
20             while(num > 0) {
21                 try {
22                     Thread.sleep(100);
23                 } catch (InterruptedException e) {
24                     e.printStackTrace();
25                 }
26                 System.out.println(Thread.currentThread().getName() + " : this is " + num --);
27             }
28         }
29     }
30     
31 }

 輸出結果:spa

Thread-0 : this is 10 Thread-0 : this is 9 Thread-0 : this is 8 Thread-0 : this is 7 Thread-0 : this is 6 Thread-0 : this is 5 Thread-0 : this is 4 Thread-0 : this is 3 Thread-0 : this is 2 Thread-0 : this is 1

4、線程的阻塞

       爲了解決對共享存儲區的訪問衝突,Java 引入了同步機制,如今讓咱們來考察多個線程對共享資源的訪問,顯然同步機制已經不夠了,由於在任意時刻所要求的資源不必定已經準備好了被訪問,反過來,同一時刻準備好了的資源也可能不止一個。爲了解決這種狀況下的訪問控制問題,Java 引入了對阻塞機制的支持。 操作系統

阻塞指的是暫停一個線程的執行以等待某個條件發生(如某資源就緒),學過操做系統的同窗對它必定已經很熟悉了。Java 提供了大量方法來支持阻塞,下面讓咱們逐一分析: 線程

一、sleep() 方法
code

     sleep() 容許 指定以毫秒爲單位的一段時間做爲參數,它使得線程在指定的時間內進入阻塞狀態,不能獲得 CPU 時間,指定的時間一過,線程從新進入可執行狀態。orm

     典型地,sleep() 被用在等待某個資源就緒的情形:測試發現條件不知足後,讓線程阻塞一段時間後從新測試,直到條件知足爲止。 對象

二、suspend() resume() 方法

     兩個方法配套使用,suspend()使得線程進入阻塞狀態,而且不會自動恢復,必須其對應的 resume() 被調用,才能使得線程從新進入可執行狀態。

     典型地,suspend() resume() 被用在等待另外一個線程產生的結果的情形:測試發現結果尚未產生後,讓線程阻塞,另外一個線程產生告終果後,調用 resume() 使其恢復。

三、yield() 方法

     yield() 使得線程放棄當前分得的 CPU 時間,可是不使線程阻塞,即線程仍處於可執行狀態,隨時可能再次分得 CPU 時間。調用 yield() 的效果等價於調度程序認爲該線程已執行了足夠的時間從而轉到另外一個線程。

四、wait() notify() 方法
     兩個方法配套使用,wait() 使得線程進入阻塞狀態,它有兩種形式,一種容許 指定以毫秒爲單位的一段時間做爲參數,另外一種沒有參數,前者當對應的 notify() 被調用或者超出指定時間時線程從新進入可執行狀態,後者則必須對應的notify() 被調用 。

關於 wait() 和 notify() 方法最後再說明兩點: 

一、調用 notify() 方法致使解除阻塞的線程是從因調用該對象的 wait() 方法而阻塞的線程中隨機選取的,咱們沒法預料哪個線程將會被選擇,因此編程時要特別當心,避免因這種不肯定性而產生問題。

二、除了 notify(),還有一個方法 notifyAll() 也可起到相似做用,惟一的區別在於,調用 notifyAll() 方法將把因調用該對象的 wait() 方法而阻塞的全部線程一次性所有解除阻塞。固然,只有得到鎖的那一個線程才能進入可執行狀態。 

相關文章
相關標籤/搜索