多線程的概念是相對於順序編程 而言的,在順序編程裏,程序只能按照一條線進行執行,而多線程可以打破這一限制,實現併發 效果。
多線程的基本實現方式
繼承Thread類
通過繼承Thread類可以實現新的線程,這樣會很簡便,但一般來說,是不被建議這樣使用的。
它最大的缺陷是,一旦繼承了Thread類就無法繼承別的類,對設計造成一定的影響。
以下的demo中,我們通過繼承Thread類來實現多線程。
共開啓5個線程,線程名字分別初始化爲1到5的數字。每個線程開始執行後,均是每隔一秒輸出一次當前狀態。
class InheritThread extends Thread {
private int waitSeconds = 5;
private static int threadCount = 0;
public InheritThread() {
super(Integer.toString(threadCount++));
}
public void run() {
while (waitSeconds > 0) {
System.out.print(this);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
waitSeconds--;
}
}
//override toString method
public String toString() {
String name = getName();
String info = "InheritThread:" + name + ", current waitSeconds = " + waitSeconds + "\n";
return info;
}
}
public class TestClass {
public static void main(String[] args) {
Thread thread;
for (int i = 0; i < 5; i++) {
thread = new InheritThread();
thread.start();
}
}
}
輸出結果:(對於多線程問題,不同機器和平臺上,同樣的代碼也可能產生不同的結果)
InheritThread:1, current waitSeconds = 5
InheritThread:2, current waitSeconds = 5
InheritThread:3, current waitSeconds = 5
InheritThread:4, current waitSeconds = 5
InheritThread:5, current waitSeconds = 5
InheritThread:1, current waitSeconds = 4
InheritThread:2, current waitSeconds = 4
InheritThread:3, current waitSeconds = 4
InheritThread:4, current waitSeconds = 4
InheritThread:5, current waitSeconds = 4
InheritThread:1, current waitSeconds = 3
InheritThread:2, current waitSeconds = 3
InheritThread:3, current waitSeconds = 3
InheritThread:4, current waitSeconds = 3
InheritThread:5, current waitSeconds = 3
InheritThread:1, current waitSeconds = 2
InheritThread:3, current waitSeconds = 2
InheritThread:2, current waitSeconds = 2
InheritThread:4, current waitSeconds = 2
InheritThread:5, current waitSeconds = 2
InheritThread:1, current waitSeconds = 1
InheritThread:2, current waitSeconds = 1
InheritThread:3, current waitSeconds = 1
InheritThread:4, current waitSeconds = 1
InheritThread:5, current waitSeconds = 1
實現Runnable接口
Runnable是JDK裏的一個接口,我們可以把它理解爲一個 "任務“, 即是我們要用它實現的線程執行的任務。
Thread類本身就是實現了Runnable接口的,所以我們纔可以直接繼承Thread類實現線程。
同樣,我們只需實現Runnable接口(複寫它的 run 方法), 就可以用它來實現線程。
以下的例子所做的操作和上個例子基本是一樣的:
class ImpRunnable implements Runnable {
private int waitSeconds = 5;
private static int threadCount = 0;
private final int myThreadCount = threadCount;
public ImpRunnable() {
threadCount++;
}
public void run() {
while (waitSeconds > 0) {
System.out.print(this);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
waitSeconds--;
}
}
//override toString method
public String toString() {
String name = "ImplRunnabeThread:" + myThreadCount;
String info = name + ", current waitSeconds = " + waitSeconds + "\n";
return info;
}
}
public class TestClass {
public static void main(String[] args) {
Thread thread;
for (int i = 0; i < 5; i++) {
thread = new Thread(new ImpRunnable());
thread.start();
}
}
}
輸出結果:
ImplRunnabeThread:0, current waitSeconds = 5
ImplRunnabeThread:1, current waitSeconds = 5
ImplRunnabeThread:2, current waitSeconds = 5
ImplRunnabeThread:3, current waitSeconds = 5
ImplRunnabeThread:4, current waitSeconds = 5
ImplRunnabeThread:0, current waitSeconds = 4
ImplRunnabeThread:1, current waitSeconds = 4
ImplRunnabeThread:2, current waitSeconds = 4
ImplRunnabeThread:3, current waitSeconds = 4
ImplRunnabeThread:4, current waitSeconds = 4
ImplRunnabeThread:0, current waitSeconds = 3
ImplRunnabeThread:1, current waitSeconds = 3
ImplRunnabeThread:2, current waitSeconds = 3
ImplRunnabeThread:3, current waitSeconds = 3
ImplRunnabeThread:4, current waitSeconds = 3
ImplRunnabeThread:0, current waitSeconds = 2
ImplRunnabeThread:1, current waitSeconds = 2
ImplRunnabeThread:2, current waitSeconds = 2
ImplRunnabeThread:3, current waitSeconds = 2
ImplRunnabeThread:4, current waitSeconds = 2
ImplRunnabeThread:0, current waitSeconds = 1
ImplRunnabeThread:1, current waitSeconds = 1
ImplRunnabeThread:2, current waitSeconds = 1
ImplRunnabeThread:3, current waitSeconds = 1
ImplRunnabeThread:4, current waitSeconds = 1
幾種常用的線程操作
休眠
可以通過 Thread.sleep( millseconds )方法使線程終止執行給定的時間。
(以上兩個demo中均使用了該方法)
注意使用該方法時需要捕獲 InterruptedException.
讓步
系統在實現多線程時,其實是對cpu的使用時間進行了切分,通過策略分別分配給各個線程cpu的使用機會。
如果我們在實現線程時,某些時間段不需要使用cpu,那麼我們可以通過 Thread.yield() 方法通知線程調度器: 我現在暫時不需要cpu了,讓別的線程使用吧。
但是要注意:這僅僅是一個暗示或者提示,沒有任何機制能夠保證系統會分配給其他線程cpu使用。所以不要完全依賴於 yield 來調度多線程的執行。
設置優先級
初始化一個線程後,它會按照默認的優先級運行。但我們也可以認爲設置線程的優先級。
cpu調度器會傾向於讓優先級高的線程先執行,但並不是說低優先級的線程不被執行,只是執行的頻率會相對低一些。
可以通過 getPriority()方法獲取當前線程的優先級,通過setPriority()方法設置優先級。