概念:
1.進程:
定義:在一個操作系統中,每個獨立運行的程序都可以稱爲一個進程,也就是“正在運行的程序”。
在多任務操作系統中,表面上看是支持進程併發執行的,但實際上這些進程並不是同時運行的。
2.線程:
定義:每個運行的程序都是一個進程,在一個進程中還可以有多個單元同時運行,這些執行單元可以看做程序執行的一條條線索,這些線索被稱爲線程。
操作系統中的每一個進程中至少存在一個線程。當一個Java程序啓動時,就會產生一個進程,該進程會默認創建一個線程,在這個線程上會運行main()方法中的代碼。
線程的創建:
java中實現多線程有兩種方式,一種是繼承java.long包下的Thread類,覆寫Thread類的run()方法,在run()方法中實現運行在線程上的代碼;另一種是實現java.long.Runnable接口,同樣是在run()方法中實現運行在線程上的代碼。
1.繼承Thread類創建多線程
在學習多線程之前,先來看看我們所熟悉的單線程程序:
Example01:
public class Example01 {
public static void main(String[] args) {
MyThread myThread=new MyThread(); // 創建MyThread實例對象
myThread.run(); // 調用MyThread類的run()方法
while (true) { // 該循環是一個死循環,打印輸出語句
System.out.println("Main方法在運行");
}
}
}
class MyThread {
public void run() {
while (true) { // 該循環是一個死循環,打印輸出語句
System.out.println("MyThread類的run()方法在運行");
}
}
}
運行結果如下所示:
概念:
1.進程:
定義:在一個操作系統中,每個獨立運行的程序都可以稱爲一個進程,也就是“正在運行的程序”。
在多任務操作系統中,表面上看是支持進程併發執行的,但實際上這些進程並不是同時運行的。
2.線程:
定義:每個運行的程序都是一個進程,在一個進程中還可以有多個單元同時運行,這些執行單元可以看做程序執行的一條條線索,這些線索被稱爲線程。
操作系統中的每一個進程中至少存在一個線程。當一個Java程序啓動時,就會產生一個進程,該進程會默認創建一個線程,在這個線程上會運行main()方法中的代碼。
線程的創建:
java中實現多線程有兩種方式,一種是繼承java.long包下的Thread類,覆寫Thread類的run()方法,在run()方法中實現運行在線程上的代碼;另一種是實現java.long.Runnable接口,同樣是在run()方法中實現運行在線程上的代碼。
1.繼承Thread類創建多線程
在學習多線程之前,先來看看我們所熟悉的單線程程序:
Example01:
public class Example01 {
public static void main(String[] args) {
MyThread myThread=new MyThread(); // 創建MyThread實例對象
myThread.run(); // 調用MyThread類的run()方法
while (true) { // 該循環是一個死循環,打印輸出語句
System.out.println("Main方法在運行");
}
}
}
class MyThread {
public void run() {
while (true) { // 該循環是一個死循環,打印輸出語句
System.out.println("MyThread類的run()方法在運行");
}
}
}
運行結果如下所示:
從上圖可以看出,程序一直打印的是“MyThread類的run()方法在運行”,這是因爲該程序是一個單線程程序,當調用MyThread類的run()方法時,遇到死循環,循環會一直進行。因此,MyThread類的打印語句將永遠執行,而main()方法中的打印語句無法得到執行。
如果希望上述代碼中兩個while循環中的打印語句能夠併發執行,就需要實現多線程。
Example02:
public class Example02 {
public static void main(String[] args) {
MyThread myThread = new MyThread(); // 創建線程MyThread的線程對象
myThread.start(); // 開啓線程
while (true) { // 通過死循環語句打印輸出
System.out.println("main()方法在運行");
}
}
}
class MyThread extends Thread {
public void run() {
while (true) { // 通過死循環語句打印輸出
System.out.println("MyThread類的run()方法在運行");
}
}
}
運行結果如下:
從上述結果看,兩個while循環中的打印語句輪流執行了,說明該例子實現了多線程。
分析:單線程的程序在運行時,會按照代碼的調用順序進行執行。而在多線程中,main()方法和MyThread類的run()方法卻可以同時運行互不影響,這正是單線程與多線程的區別。
實現Runnable接口創建多線程
通過繼承Thread類有一定侷限性。因爲Java中只支持單繼承,一個類一旦繼承了某個父類就無法再繼承Thread類。爲了克服這種弊端,Thread類提供了另外一種構造方法Thread(Runnable target),其中Runnable是一個接口,他只有一個run()方法。當通過Thread(Runnable target)構造方法創建線程對象時,只需要爲該方法傳遞一個實現了Runnable接口的實例對象,這樣創建線程將調用實現了Runnable接口中的run()方法作爲運行代碼,而不需要調用Thread類的run()方法,接下來通過一個案例來演示如何通過實現Runnable接口的方式來創建多線程,如下所示:
Example03:
public class Example03 {
public static void main(String[] args) {
MyThread myThread = new MyThread(); // 創建MyThread的實例對象
Thread thread=new Thread(myThread); // 創建線程對象
thread.start(); // 開啓線程,執行線程中的run()方法
while (true) {
System.out.println("main()方法在運行");
}
}
}
class MyThread implements Runnable {
public void run() { // 線程的代碼段,當調用start()方法時,線程從此處開始執行
while (true) {
System.out.println("MyThread類的run()方法在運行");
}
}
}
運行結果如下所示:
MyThread類實現了Runnable接口,並重寫了Runnable接口中的run()方法,通過Thread類的構造方法將MyThread類的實力對象作爲參數傳入。從運行結果看出該例實現了多線程。
後臺線程
對java程序來說,只要還有一個前臺進程在運行,這個進程就不會結束,如果一個進程中只有後臺線程雲心,這個進程就會結束。這裏提到的前臺線程和後臺線程是一種相對的概念,新創建的線程默認都是前臺線程,如果某個線程對象在啓動之前調用了setDeamon(true)語句,這個線程就會變成一個後臺線程。
Example04
class DamonThread implements Runnable { // 創建DamonThread類,實現Runnable接口
public void run() { // 實現接口中的run()方法
while (true) {
System.out.println(Thread.currentThread().getName()
+ "---is running.");
}
}
}
public class Example04 {
public static void main(String[] args) {
System.out.println("main線程是後臺線程嗎?"+ Thread.currentThread().isDaemon());//通過Thread的
currentThread()方法得到當前線程對象 DamonThread dt = new DamonThread(); // 創建一個DamonThread對象dt
Thread t = new Thread(dt,"後臺線程"); // 創建線程t共享dt資源
System.out.println("t線程默認是後臺線程嗎? "+t.isDaemon()); // 判斷是否爲後臺線程
t.setDaemon(true); // 將線程t設置爲後臺線程
t.start(); // 調用start()方法開啓線程t
for(int i=0;i<10;i++){
System.out.println(i);
}
}
}
運行結果如下所示:
該示例演示了一個後臺線程結束的過程。當開啓線程t時,會執行死循環中的打印語句,但我們將線程t設置爲後臺線程後,當前臺線程死亡後,JVM會通知後臺線程。由於後臺線程從接受指令到作出相應需要一段時間,因此打印了幾次“後臺線程---is running.”語句後,後臺線程也結束了。由此說明進程中只有後臺線程運行時,程序就會結束。
注意:將某個線程設置爲後臺線程,必須在該線程啓動之前,也就是說setDeamon()方法必須在start()方法之前調用,否則就會引發IllegalThreadStateException異常。
從上圖可以看出,程序一直打印的是“MyThread類的run()方法在運行”,這是因爲該程序是一個單線程程序,當調用MyThread類的run()方法時,遇到死循環,循環會一直進行。因此,MyThread類的打印語句將永遠執行,而main()方法中的打印語句無法得到執行。
如果希望上述代碼中兩個while循環中的打印語句能夠併發執行,就需要實現多線程。
Example02:
public class Example02 {
public static void main(String[] args) {
MyThread myThread = new MyThread(); // 創建線程MyThread的線程對象
myThread.start(); // 開啓線程
while (true) { // 通過死循環語句打印輸出
System.out.println("main()方法在運行");
}
}
}
class MyThread extends Thread {
public void run() {
while (true) { // 通過死循環語句打印輸出
System.out.println("MyThread類的run()方法在運行");
}
}
}
運行結果如下:
從上述結果看,兩個while循環中的打印語句輪流執行了,說明該例子實現了多線程。
分析:單線程的程序在運行時,會按照代碼的調用順序進行執行。而在多線程中,main()方法和MyThread類的run()方法卻可以同時運行互不影響,這正是單線程與多線程的區別。
實現Runnable接口創建多線程
通過繼承Thread類有一定侷限性。因爲Java中只支持單繼承,一個類一旦繼承了某個父類就無法再繼承Thread類。爲了克服這種弊端,Thread類提供了另外一種構造方法Thread(Runnable target),其中Runnable是一個接口,他只有一個run()方法。當通過Thread(Runnable target)構造方法創建線程對象時,只需要爲該方法傳遞一個實現了Runnable接口的實例對象,這樣創建線程將調用實現了Runnable接口中的run()方法作爲運行代碼,而不需要調用Thread類的run()方法,接下來通過一個案例來演示如何通過實現Runnable接口的方式來創建多線程,如下所示:
Example03:
public class Example03 {
public static void main(String[] args) {
MyThread myThread = new MyThread(); // 創建MyThread的實例對象
Thread thread=new Thread(myThread); // 創建線程對象
thread.start(); // 開啓線程,執行線程中的run()方法
while (true) {
System.out.println("main()方法在運行");
}
}
}
class MyThread implements Runnable {
public void run() { // 線程的代碼段,當調用start()方法時,線程從此處開始執行
while (true) {
System.out.println("MyThread類的run()方法在運行");
}
}
}
運行結果如下所示:
MyThread類實現了Runnable接口,並重寫了Runnable接口中的run()方法,通過Thread類的構造方法將MyThread類的實力對象作爲參數傳入。從運行結果看出該例實現了多線程。
後臺線程
對java程序來說,只要還有一個前臺進程在運行,這個進程就不會結束,如果一個進程中只有後臺線程雲心,這個進程就會結束。這裏提到的前臺線程和後臺線程是一種相對的概念,新創建的線程默認都是前臺線程,如果某個線程對象在啓動之前調用了setDeamon(true)語句,這個線程就會變成一個後臺線程。
Example04
class DamonThread implements Runnable { // 創建DamonThread類,實現Runnable接口
public void run() { // 實現接口中的run()方法
while (true) {
System.out.println(Thread.currentThread().getName()
+ "---is running.");
}
}
}
public class Example04 {
public static void main(String[] args) {
System.out.println("main線程是後臺線程嗎?"+ Thread.currentThread().isDaemon());//通過Thread的
currentThread()方法得到當前線程對象 DamonThread dt = new DamonThread(); // 創建一個DamonThread對象dt
Thread t = new Thread(dt,"後臺線程"); // 創建線程t共享dt資源
System.out.println("t線程默認是後臺線程嗎? "+t.isDaemon()); // 判斷是否爲後臺線程
t.setDaemon(true); // 將線程t設置爲後臺線程
t.start(); // 調用start()方法開啓線程t
for(int i=0;i<10;i++){
System.out.println(i);
}
}
}
運行結果如下所示:
該示例演示了一個後臺線程結束的過程。當開啓線程t時,會執行死循環中的打印語句,但我們將線程t設置爲後臺線程後,當前臺線程死亡後,JVM會通知後臺線程。由於後臺線程從接受指令到作出相應需要一段時間,因此打印了幾次“後臺線程---is running.”語句後,後臺線程也結束了。由此說明進程中只有後臺線程運行時,程序就會結束。
注意:將某個線程設置爲後臺線程,必須在該線程啓動之前,也就是說setDeamon()方法必須在start()方法之前調用,否則就會引發IllegalThreadStateException異常。