Thread類的核心方法較多,讀者應該着重掌握如下關鍵技術點:
□線程的啓動
□如果使線程暫停
□如何使線程停止
□線程的優先級
□線程安全相關的問題
1.1 進程與多線程的概念及線程的優點
本節主要介紹在Java語言中使用多線程技術。但是講到多線程不得不提到進程這個概念:
進程(Process)是計算機中的程序關於某數據集合上的一次運行活動,
是系統進行資源分配和調度的基本單位,是操作系統結構的基礎。在早
期面向進程設計的計算機結構中,進程是程序的基本執行實體;在當代
面向線程設計的計算機結構中,進程是線程的容器。程序是指令、數據
及其組織形式的描述,進程是程序的實體。
將一個正在操作系統中運行的exe程序理解成一個進程!通過查看任務管理器中的列表,完全可以將運行在內存中的exe文件理解成進程,進程是受操作系統管理的基本運行單元。
那什麼是線程呢?線程可以理解成是進程中獨立運行的子任務。比如,QQ.exe運行時就有很多的子任務在同時運行。再如,好友視頻線程,下載文件線程,傳輸數據線程等等,這些不同的任務或者說功能都可以同時運行,其中每一項任務完全可以理解成是線程在工作。使用多任務操作系統後,可以最大限度地利用CPU的空閒時間來處理其它的任務,比如一邊打印,一邊使用word編輯。而CPU在這些任務之間不停地切換,由於切換速度非常快,給使用者的感覺就是這些任務似乎在同時運行。所以在使用多線程技術後,可以在同一時間內運行更多不同種類的任務。
1.2 使用多線程
一個進程正在運行時至少會有一個線程在運行,這種情況在java中也是存在的。這些線程在後臺默默地執行:
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());// main
}
在控制檯輸出的main其實就是一個名稱叫做main的線程在執行main方法中的代碼。另外需要說明一下,在控制檯輸出的main和main方法沒有任何的關係,僅僅是名字相同而已。
1.2.1 繼承Thread類
實現多線程編程的方式有兩種,一種是繼承Thread類,另一種是實現Runnable接口。先來看看Thread類的結構:
public class Thread implements Runnable
從源代碼可以發現,Thread類實現了Runnable接口,它們之間具有多態關係。其實,使用繼承Thread類的方式創建線程時,最大的侷限就是不支持多繼承,因爲Java語言的特點就是單根繼承,所以爲了支持多繼承,完全可以實現Runnable接口的方式,一邊實現一邊繼承。
public class MyThread extends Thread {
@Override
public void run() {
super.run();
System.out.println("My Thread!");
}
public static void main(String[] args) {
MyThread my = new MyThread();
my.start();
System.out.println("運行結束");// 運行結束/n My Thread!
}
}
以上代碼的打印順序可以看出來,run方法執行的時間比較晚,這也說明在使用多線程技術時,代碼的運行結果與代碼執行順序或調用順序無關。
上面代碼介紹了線程的調用的隨機性,下面將演示線程的隨機性。
public class MyThread extends Thread {
@Override
public void run() {
try {
for(int i=0; i<10; i++) {
int time = (int)(Math.random()*1000);
Thread.sleep(time);
System.out.println("run="+Thread.currentThread().getName());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
MyThread my = new MyThread();
my.setName("myThread");
my.start();
try {
for(int i=0; i<10; i++) {
int time = (int)(Math.random()*1000);
Thread.sleep(time);
System.out.println("main="+Thread.currentThread().getName());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在代碼中,爲了展現出線程具有隨機特性,所以使用隨機數的形式來使線程得到掛起的效果,從而表現出CPU執行哪個線程具有不確定性。Thread.java類中的start方法通過‘線程規劃器‘此線程已經準備就緒,等待調用線程對象的run方法。這個過程其實就是讓系統安排一個時間來調用Thread中的run方法,也就是線程得到運行,啓動線程,具有異步執行的效果。如果直接調用代碼thread.run就不是異步執行。 而是同步,那麼此線程對象並不會交給"線程規劃器"來進行處理,而是由main主線程來調用run方法,也就是必須等run方法中的代碼執行完成後才能執行後面的代碼。(看下面代碼中的註釋)
public static void main(String[] args) {
MyThread my = new MyThread();
my.setName("myThread");
my.run();// 由start替換成run,運行結果發生變化,先執行完線程裏面的,然後再執行main方法裏面的
try {
for(int i=0; i<10; i++) {
int time = (int)(Math.random()*1000);
Thread.sleep(time);
System.out.println("main="+Thread.currentThread().getName());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}