建立執行緒的三種方式
繼承Thread類
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() + " " + i);
}
}
public static void main(String[] args) {
new MyThread().start();
new MyThread().start();
new MyThread().start();
}
}
實現Runnable介面
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable, "T1").start();
new Thread(myRunnable, "T2").start();
new Thread(myRunnable, "T3").start();
}
}
實現Callable介面
class CallerTask implements Callable<String> {
@Override
public String call() throws Exception {
return "回撥結果";
}
public static void main(String[] args) {
// 建立非同步任務
FutureTask<String> task = new FutureTask<>(new CallerTask());
// 啟動執行緒
new Thread(task).start();
try {
// 等待執行完成,並獲取返回結果
String result = task.get();
System.out.println(result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
-
run()
:封裝執行緒執行的程式碼,直接呼叫相當於呼叫普通方法。 -
start()
:啟動執行緒,然後由 JVM 呼叫此執行緒的run()
方法。 -
實現 Runnable 介面避免了 Java 單繼承的侷限性,Java 不支援多重繼承,因此如果我們的類已經繼承了另一個類,就不能再繼承 Thread 類了。並且適合多個相同的程式程式碼去處理同一資源的情況,把執行緒、程式碼和資料有效的分離,更符合物件導向的設計思想。Callable 介面與 Runnable 非常相似,但可以返回一個結果。
控制執行緒的其他方法
-
sleep():使當前正在執行的執行緒暫停指定的毫秒數,也就是進入休眠的狀態。
-
join():等待這個執行緒執行完才會輪到後續執行緒得到 cpu 的執行權。
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread t1 = new Thread(myRunnable, "T1");
t1.start();
try {
// t1執行完才會輪到後面的執行緒執行
t1.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(myRunnable, "T2").start();
new Thread(myRunnable, "T3").start();
}
-
setDaemon():將此執行緒標記為守護執行緒,準確來說,就是服務其他的執行緒,像 Java 中的垃圾回收執行緒,就是典型的守護執行緒。
-
yield():yield() 方法是一個靜態方法,用於暗示當前執行緒願意放棄其當前的時間片,允許其他執行緒執行。然而,它只是向執行緒排程器提出建議,排程器可能會忽略這個建議。具體行為取決於作業系統和 JVM 的執行緒排程策略。
class YieldExample {
public static void main(String[] args) {
Thread thread1 = new Thread(YieldExample::printNumbers, "劉備");
Thread thread2 = new Thread(YieldExample::printNumbers, "關羽");
thread1.start();
thread2.start();
/*
關羽 讓出控制權...
劉備 讓出控制權...
關羽: 3
關羽: 4
關羽 讓出控制權... // 即便有時候讓出了控制權,其他執行緒也不一定會執行
關羽: 5
劉備: 3
劉備: 4
劉備 讓出控制權...
劉備: 5
*/
}
private static void printNumbers() {
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + ": " + i);
// 當 i 是偶數時,當前執行緒暫停執行
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + " 讓出控制權...");
Thread.yield();
}
}
}
}