一、Join線程
當前線程調用了 另一個線程的join() 方法,當前線程會阻塞,直到 被join的線程執行完成後 纔會繼續執行。
public class JoinThread extends Thread{
JoinThread(String name){
super(name);
}
@Override
public void run() {
super.run();
for (int i=0;i<100;i++){
Log.e("testthread",getName() +","+ i);
}
}
}
mBntFun4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new JoinThread("新線程").start();
for (int i = 0;i<100;i++){
Log.e("testthread",Thread.currentThread().getName() +","+ i);
if (i == 20){
// 啓動新線程
JoinThread joinThread = new JoinThread("join線程");
joinThread.start();
try {
//1. 調用新線程的join方法,當前線程會阻塞,知道join的線程執行完成
joinThread.join();
// 2.當前線程最多等待1毫秒,超過20毫秒Join的線程還沒有執行完,則不再等待
//joinThread.join(1);
//3. 當前線程最多等待1毫秒加10毫微秒(一般不用這個,因爲程序無法精確到毫微秒)
//joinThread.join(1,10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
說明
join方法有以上代碼的三種重載方式
二、後臺線程(守護線程、精靈線程)
- 有些線程在後臺運行,爲其他線程提供服務,比如JVM垃圾回收線程
- 當所有的前臺線程死亡,那後臺線程也會隨之死亡,因爲當前臺進程都死亡後,就沒有運行的必要了,虛擬機也就退出了,後臺進程也就死亡了。
- 主線程默認是前臺線程,前臺線程創建的子線程是前臺線程,後臺線程創建的子線程是後臺線程
- 調用線程的 setDaemon(true) 設置爲後臺線程
- 調用線程 isDaemon() 判斷是否是後臺線程
- setDaemon要在start()之前調用
class FirstThread extends Thread{
private int i;
@Override
public void run() {
super.run();
for (;i < 1000; i++){
Log.e("testthread",getName() +","+ i);
}
}
}
mBntFun5.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
FirstThread thread = new FirstThread();
// 要在start()之前調用
thread.setDaemon(true);
//啓動線程
thread.start();
for (int i=0;i<10;i++){
Log.e("testthread",Thread.currentThread().getName() +","+ i);
}
// 主線程運行到這就結束了,後臺線程也隨之結束,所以thread並不會打印到 999
}
});
三、線程睡眠 :sleep(是Thread的靜態方法)
可以讓正在執行的線程暫停一段時間,進入阻塞狀態
mBntFun5.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
for (int i=0;i<10;i++){
Log.e("testthread",Thread.currentThread().getName() +","+ new Date());
try {
//讓主線程睡1毫秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
說明
從上面的運行結果可以看到,線程每隔一秒打印一次
- sleep也有兩種重載方式:
- void sleep(long millis) : 暫停多少毫秒
- void sleep(long millis, int nanos):暫停多少毫秒加毫微秒(一般不用這個)
- 線程調用sleep()進入阻塞後,在睡眠時間內,不會獲得執行的機會,即便系統中沒有其他線程在執行,處於sleep狀態的線程也不會執行
四、線程讓步 :yield(靜態方法)
可以暫停當前的線程,讓它進入就緒狀態,並不會阻塞該線程
class FirstThread extends Thread{
FirstThread(String name){
super(name);
}
@Override
public void run() {
super.run();
for (int i=0;i < 100; i++){
Log.e("testthread",getName() +","+ i);
if (i == 20){
Thread.yield();
}
}
}
}
mBntFun5.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
FirstThread thread1 = new FirstThread("高級");
thread1.setPriority(Thread.MAX_PRIORITY);
thread1.start();
FirstThread thread2 = new FirstThread("低級");
thread2.setPriority(Thread.MAX_PRIORITY);
thread2.start();
}
});
說明
- 通過**setPriority()**設置線程的優先級
- 調用yield()後,只有和當前線程同級或者比他優先級高的纔會獲得執行的機會
- 當沒有比它優先級高的線程,調用yield()後當前線程繼續執行
sleep()和yield()的區別:
- 優先級:sleep()調用後,不會理會其他線程的優先級;yield需要
- 狀態:調用sleep()後會進入阻塞狀態,經過阻塞事件纔會進入就緒狀態;而yield直接就進入就緒狀態了
- 異常:調用sleep後會拋出InterruptedException異常,而yield沒有拋出任何異常
- 可移植性:sleep()有更好的可移植性,**不建議用yield()來控制併發線程
五、改變線程的優先級
- 每個線程的優先級都和創建它的父線程優先級相同
- main線程具有普通優先級
- 設置優先級:
setPriority(1~10)
public static final int MAX_PRIORITY = 10;
public static final int MIN_PRIORITY = 1;
public static final int NORM_PRIORITY = 5;
- 返回優先級:
getPriority()