1 、線程中斷:
線程中斷是一種重要的線程協作機制。線程中斷並不會讓線程退出,只是給線程發送一個通知,線程執行過程會檢測到這個通知,然後可以自定義做出動作,比如退出,但也並不是都是退出。
線程中有三個有關中斷的方法:
public void interrupt() 中斷線程
public booklean isInterrupted() 判斷是否被中斷,不清除當前中斷狀態
public static boolean interrupt() 判斷是否被中斷,並清除當前中斷狀態。
public class ThreadInterrupt {
public static void main(String args[]) throws InterruptedException {
Thread t1 = new Thread() {
public void run() {
while (true) {
if(Thread.currentThread().isInterrupted()){ //1 在中斷處理中並未執行退出
// 2 此方法並未清除中斷標誌位,因此還會被檢測到
System.out.println("線程第一次檢測到中斷,並不退出");
}
System.out.println("線程執行過程中 ");
if(Thread.currentThread().isInterrupted()){
System.out.println("線程再次檢測到中斷,然後退出");
break;
}
System.out.println("線程執行過程中 ");
Thread.yield();
}
}
};
t1.start();
Thread.sleep(3000);
t1.interrupt();
}
}
Thead.sleep() 方法會讓當前線程休眠若干時間,會拋出一個InterruptedException 中斷異常。 不是運行時異常,程序必須捕獲它。,當線程在sleep休眠時,如果被中斷,這個異常就會產生。
Thread.sleep 方法由於中斷而拋出異常,此時,它會清除中斷標記,如果不加處理,那麼在下一次循環開始時,就無法捕獲這個中斷,故在異常處理中,再次設置中斷標記位。
2、等待 wait通知 notify
爲了支持多線程之間的協作,jdk提供了兩個非常重要的接口:wait 和notify方法。這兩個方法在Object類中定義,這意味着任何對象都可以調用這兩個方法,但是 wait和notify不是隨意調用的,它必須包含在對應的synchronized語句中。還有個地方需要注意,儘量不在Thread實例上調用wait和notify方法。無論是wait還是notify,都需要首先獲得目標對象的一個監視器。
線程執行wait和notify的流程:
T1在執行object.wait方法之前首先獲得object對象的監視器,執行之後,釋放object的監視器,此時線程就會進入等待狀態, 等待其他線程的喚醒。
T2 在notify調用前,也必須獲得object的監視器,此時T1已經釋放了這個監視器,因此T2可以順利獲得object的監視器。接着T2執行了notify方法嘗試喚醒一個等待線程,這裏是隨機喚醒,假設喚醒了T1 。T1被喚醒後,要做的第一件事並不是執行後續的代碼,而是嘗試從新獲得object的監視器,而這個監視器也正是t1在wait方法執行前所持有的那個。
object.wait 和thread.sleep 方法都可以讓線程等待若干時間。除了wait可以被喚醒外,另外一個主要的區別就是wait 方法會釋放目標對象的鎖,而Thread.sleep方法不會釋放任何資源。
3、掛起 suspend 繼續執行 resume
在導致線程暫停的同時,並不會釋放任何資源。此時其他任何線程想要訪問被它暫用的鎖時,都會被牽連。導致無法正常繼續運行。直到resume操作,假設無resume的執行,或者resume已經提前調用過了,那麼這個線程永遠處於掛起狀態了。
4、等待線程結束 join 謙讓 yield
join有兩個方法簽名,無參數的join,表示無限期等待, 有參數join表示等待指定的時間。
在線程T1中調用 T2.join 表示等待T2線程調用完畢之後,纔會調用繼續調用線程T1。
(顯然在本身的方法裏,調用自身的join方法是沒有意義的。)
yield 總是一個靜態方法,一旦執行,它會使當前線程讓出CPU,但要注意,讓出CPU並不是表示當前線程不執行了。當前線程在讓出CPU後,還會進行CPU資源的爭奪。
5、守護線程
Daemon 是一種特殊的線程,它是系統的守護者,在後臺默默地完成一些系統性的服務。 比如垃圾回收線程,JIT線程。 當一個Java應用內,只有守護線程時,Java虛擬機就會自然退出。
6、關於synchronized的用法:
指定加鎖對象: 對給定對象加鎖,進入同步代碼前要獲得給定對象的鎖。
直接作用於實例方法: 相當於對當前實例加鎖,進入同步代碼前要獲得當前實例的鎖。
直接作用於靜態方法:相當於對當前類加鎖,進入同步代碼前要獲得當前類的鎖。