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() 方法,這樣實際是把該線程類當作了一個普通類而已。