1. join線程:
在線程執行過程中,有時想讓另一個線程先執行,例如將一大問題分割成許多小問題,給每一個小問題分配線程,但所有小問題處理完後再讓主線程進一步操作。此時我們可以在主執行緒中呼叫其它執行緒的join()方法,以阻塞呼叫執行緒(在這裡為主執行緒)。
範例程式碼:
複製代碼代碼如下:
package org.frzh.thread;
public class JoinThread extends Thread{
//提供一個有參構造器,用來設定線程的名字
public JoinThread(String name) {
super(name);
}
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() + " " + i);
}
}
public static void main(String[] args) {
//啟動子執行緒
new JoinThread("新執行緒").start();
for (int i = 0; i < 100; i++) {
if (i == 20) {
JoinThread jt = new JoinThread("被join的執行緒");
jt.start();
//main執行緒呼叫了jt執行緒的join方法,則main執行緒必須等待jt執行完之後才能執行
try {
jt.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + " " +i);
}
}
}
本來有三套線程(兩個子線程和一main線程),當i=20後,main線程被阻塞必須等到“被join線程”執行完之後才有機會執行,所以此後只有兩個線程執行。
join()方法的三種重載形式:
join():等待被join執行緒執行完;
join(long millis):等待被join線程執行最長為mills豪秒,在這之後即使被join線程沒有執行完也不再等待;
join(long millis, int nanos):等待被join執行緒執行最長時間為millis毫秒+nanos微秒。 (此方法基本上用不上)。
2:後台執行緒:
有一種線程,他是在後台運行,他的任務是為其他線程服務,這種線程被稱為“後台線程”、“守護線程”或“精靈線程”。當所有前台線程都死亡後,後台線程會自動死亡。
範例程式碼:
複製代碼代碼如下:
package org.frzh.thread;
public class DaemonThread extends Thread{
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(getName() + " " +i);
}
}
public static void main(String[] args) {
DaemonThread dt = new DaemonThread();
//將此執行緒設定為後台執行緒
dt.setDaemon(true);
dt.start();
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
//前台執行緒結束,那麼後台執行緒dt也會結束,所以它執行不到999
}
}
主線程預設是前台線程,前台線程創建的子線程預設是前台線程,後台線程創建的子線程預設是後台線程。
3.線程睡眠(sleep):
前面的join方法是讓呼叫執行緒等待被join執行緒執行完之後再繼續執行,而sleep()方法是讓呼叫執行緒阻塞一段時間後再重新進入就緒狀態等待被調度。因此它通常用來暫停程式的執行。
範例程式碼:
複製代碼代碼如下:
package org.frzh.thread;
import java.util.Date;
public class SleepThread{
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println("目前時間:" + new Date());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
sleep()方法的兩種重載方式:
static void sleep(long millis):讓目前執行緒暫停millis毫秒,並進入阻塞狀態。此方法會受到系統計時器和執行緒調度器的精確度和準度的影響。
static void sleep(long millis, int nanos):暫停mills毫秒+nanos微秒,並進入阻塞狀態,同樣會受系統計時器和線程調度器的精度和準度的影響。基本不用。
4.線程讓步(yield):
yield()方法和sleep方法有點類似,它同樣可以使當前正在運行的線程暫停,但他不會阻塞該線程,只是將他轉入就緒狀態(注意不是阻塞狀態)。 yield()方法只會讓和它同等優先權或更高優先權的執行緒有被執行的機會,所以某一執行緒呼叫該方法後可能又被重新調度回來繼續執行。
範例程式碼:
複製代碼代碼如下:
package org.frzh.thread;
public class YieldThread extends Thread{
public YieldThread() {
}
public YieldThread(String name) {
super(name);
}
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() + " " +i);
if (i == 20) {
//當前執行緒讓步
Thread.yield();
}
}
}
public static void main(String[] args) {
//啟動兩個並發線程
YieldThread yt1 = new YieldThread("高級");
//設定yt1為最高優先權
yt1.setPriority(Thread.MAX_PRIORITY);
yt1.start();
YieldThread yt2 = new YieldThread("低級");
yt2.setPriority(Thread.MIN_PRIORITY);
yt2.start();
/*
* 如果不給執行緒設定優先權,則兩個執行緒的優先權是相同的,所以兩個執行緒會交替執行,當呼叫yield後會讓另一個執行緒執行;
* 但是,給兩個執行緒分別設定上述優先權之後,剛開始高階執行緒執行,當i=20時,呼叫yield,但由於yield方法只會
* 給和它同優先權或更高優先權的執行緒執行機會,所以此時仍是高階執行緒執行,而不會讓給低階執行緒
*/
}
}
5:改變執行緒的優先權:
此舉比較簡單,只要呼叫呼叫實例方法setPriority(int priority)方法即可。每個執行緒預設與其父執行緒的優先權相同,main執行緒預設具有普通優先權(5)。 java提供1~10個優先級,也可以使用三個靜態常數:
MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5
注意的是:儘管java提供10個優先級,但是不同的系統支援的優先級不一樣,所以盡量避免直接使用1~10之間的數字,而使用靜態常量,以保證具有良好的可移植性。