1. 程式人生 > 其它 >Java程序和執行緒的概念講解

Java程序和執行緒的概念講解

Java是一門面向物件程式語言,不僅吸收了C++語言的各種優點,還摒棄了C++裡難以理解的多繼承、指標等概念,因此Java語言具有功能強大和簡單易用兩個特徵。Java語言作為靜態面向物件程式語言的代表,極好地實現了面向物件理論,允許程式設計師以優雅的思維方式進行復雜的程式設計,下面就由千鋒重慶小編帶大家一起了解一下Java的程序和執行緒的概念

程序和執行緒的概念

程序

幾乎所有的作業系統都支援程序的概念。一個任務通常對應一個程序。程序具有如下特徵:

程序通常是獨立存在的,擁有自己獨立的資源。

程序擁有自己的生命週期和各種不同的狀態。

多個程序可以在單個處理器上併發執行,多個程序之間不會互相響應。

執行緒

執行緒是cpu執行的最小單元,一個程序可以有多個執行緒。一個執行緒必須有一個父程序。執行緒可以擁有自己的堆疊,但不擁有系統資源。對 cpu 而言,在同一時間,只能執行一個執行緒。之所以看起來像是在同時執行,是因為cpu輪循的時間特別快。執行緒由程序來負責管理和排程。

Java執行緒具有五種基本狀態

新建狀態(New):當執行緒物件對建立後,即進入了新建狀態,如:Thread t = new MyThread();

就緒狀態(Runnable):當呼叫執行緒物件的start()方法(t.start();),執行緒即進入就緒狀態。處於就緒狀態的執行緒,只是說明此執行緒已經做好了準備,隨時等待CPU排程執行,並不是說執行了t.start()此執行緒立即就會執行;

執行狀態(Running):當CPU開始排程處於就緒狀態的執行緒時,此時執行緒才得以真正執行,即進入到執行狀態。注:就 緒狀態是進入到執行狀態的唯一入口,也就是說,執行緒要想進入執行狀態執行,首先必須處於就緒狀態中;

阻塞狀態(Blocked):處於執行狀態中的執行緒由於某種原因,暫時放棄對CPU的使用權,停止執行,此時進入阻塞狀態,直到其進入到就緒狀態,才 有機會再次被CPU呼叫以進入到執行狀態。根據阻塞產生的原因不同,阻塞狀態又可以分為三種:

1.等待阻塞:執行狀態中的執行緒執行wait()方法,使本執行緒進入到等待阻塞狀態;

2.同步阻塞 -- 執行緒在獲取synchronized同步鎖失敗(因為鎖被其它執行緒所佔用),它會進入同步阻塞狀態;

3.其他阻塞 -- 通過呼叫執行緒的sleep()或join()或發出了I/O請求時,執行緒會進入到阻塞狀態。當sleep()狀態超時、join()等待執行緒終止或者超時、或者I/O處理完畢時,執行緒重新轉入就緒狀態。

死亡狀態(Dead):執行緒執行完了或者因異常退出了run()方法,該執行緒結束生命週期。

需要注意的是: wait() 、notify()、notifyAll() 方法是 Object 類的方法。

Java 中執行緒的建立和啟動

1.繼承自 Thread 類建立執行緒:

定義類繼承自 Thread 類,重寫該類的 run() 方法,run() 方法方法體代執行緒要執行的任務。因此,run() 方法也稱執行緒執行體。

建立定義的執行緒類的例項,即建立執行緒物件。

呼叫執行緒物件的 start() 方法啟動該執行緒。

public class MyThread extends Thread {

@Override

public void run() {

for (int i = 0; i < 1000; i++) {

System.out.println(getName() + "-----" + i);

}

}

public static void main(String[] args){

new MyThread().start();

new MyThread().start();

}

}

2.實現Runnable介面建立執行緒:

定義 Runnable 介面的實現類,並重寫該介面的 run()方法,該 run() 同樣是執行緒執行體。

建立 Runnable 實現類的例項,將 Runnable 實現類的例項傳入作為引數傳入,建立 Thread 類的例項,作為執行緒物件。

呼叫執行緒物件的 start() 方法啟動執行緒。

public class MyThread implements Runnable {

@Override

public void run() {

for (int i = 0; i < 1000; i++) {

System.out.println(Thread.currentThread().getName() + "-----" + i);

}

}

public static void main(String[] args){

MyThread mt = new MyThread();

new Thread(mt).start();

new Thread(mt).start();

}

}

3.使用 Callable 和 Future 建立執行緒:

建立 Callable 的實現類,並實現 call() 方法,call() 方法為執行緒執行體。泛型引數為 call() 返回值。

建立 Callable 實現類的例項,並將該物件傳入,建立 FutureTask 類的例項。該 FutureTask 的物件封裝了 該 Callable 例項物件的返回值。

建立 FutureTask 的例項,作為 target 傳入,建立 Thread 類的物件,作為執行緒物件。

呼叫執行緒物件的 start() 方法啟動執行緒。

如有必要,可以通過 FutureTask 物件的 get() 方法來獲得執行緒執行結束後的返回值。

public class MyCallable implements Callable {

@Override

public Integer call() throws Exception {

int i = 0;

for (; i < 1000; i++) {

System.out.println(Thread.currentThread().getName() + "-----" + i);

}

return i;

}

public static void main(String[] args) {

MyCallable mc = new MyCallable();

FutureTask task = new FutureTask(mc);

new Thread(task).start();

try {

Thread.sleep(5000);// 可能做一些事情

System.out.println("----------" + task.get());

} catch (InterruptedException e) {

e.printStackTrace();

} catch (ExecutionException e) {

e.printStackTrace();

}

}

}

值得一提的是:雖然直接繼承自 Thread 類的方式實現起來最為簡單,但是由於Java的類只能單繼承,但可以實現多個介面。所以一般我們不採用該方式。另外,啟動執行緒的方式,都是通過呼叫執行緒物件的 start() 方法,切莫不要直接呼叫 run() 方法,這樣實際是把該執行緒類當作了一個普通類而已。