目錄
1 wait()被中斷的過程
1.1 代碼示例
開啓兩個線程,一個線程等待,另一個線程獲取鎖後打印信息,打印期間對等待線程進行中斷,通過打印的控制檯信息來查看中斷過程。
public class Test3 {
static Object lock = new Object(); // 同步鎖和等待鎖
public static void main(String[] args) throws InterruptedException {
MyThread myThread1 = new MyThread("線程1", true);
MyThread myThread2 = new MyThread("線程2", false);
myThread1.start();
Thread.sleep(100); // 給myThread1啓動留時間
myThread2.start(); // 給myThread2啓動留時間
Thread.sleep(100);
System.out.println(myThread1.getName()+":狀態爲"+myThread1.getState());
myThread1.interrupt();
Thread.sleep(100); // 給中斷操作留時間
System.out.println(myThread1.getName()+":被中斷");
System.out.println(myThread1.getName()+":狀態爲"+myThread1.getState());
}
private static class MyThread extends Thread{
volatile boolean wait; // 等待標誌,true則線程會在run()中等待
MyThread(String name, boolean wait){
super(name);
this.wait = wait;
}
@Override
public void run() {
synchronized (lock){
if (wait){
try {
lock.wait();
} catch (InterruptedException e) {
System.out.println(this.getName()+":被中斷後的打印信息");
}
}else{
int i = 3;
while (i-- > 0){ // 每隔1s打印,打印3次
try {
Thread.sleep(1000);
System.out.println("printInfo");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println(this.getName()+":釋放鎖");
}
}
}
}
打印結果如下:
線程1:狀態爲WAITING
線程1:被中斷
線程1:狀態爲BLOCKED
printInfo
printInfo
printInfo
線程2:釋放鎖
線程1:被中斷後的打印信息
線程1:釋放鎖
Process finished with exit code 0
1.2 結果分析
顯然,對wait的線程進行中斷首先將線程從等待隊列移到阻塞隊列(線程狀態由WAITING——>BLOCKED),然後等待鎖被釋放,釋放後才拋出InterruptedException,打印catch中的信息。
2 join()被中斷過程
2.1 代碼示例
在join線程執行期間,對joined線程進行中斷。
public class Test4 {
public static void main(String[] args) throws InterruptedException {
MyThread join = new MyThread("join線程", false, null);
join.start();
MyThread interruptThread = null;
for (int i=1;i<=10;++i){ // 創建10個線程
MyThread joined = new MyThread("joined線程"+i, true, join);
joined.start();
if (i == 5){ // 中斷第5個線程
interruptThread = joined;
}
}
Thread.sleep(1000); // 留出時間給join線程運行
interruptThread.interrupt();
System.out.println(interruptThread.getName()+":被中斷");
}
private static class MyThread extends Thread{
boolean joined; // true表示該線程是joined線程,false爲join線程
Thread joinThread;
MyThread(String name , boolean joined , Thread joinThread){
super(name);
this.joined = joined;
this.joinThread = joinThread;
}
@Override
public void run() {
if (joined){
try {
joinThread.join();
System.out.println(this.getName()+":被notify後的打印信息");
} catch (InterruptedException e) {
System.out.println(this.getName()+":被中斷後的打印信息");
}
}else{
int i = 3;
while (i-- > 0){ // 每隔0.5s打印,打印3次
try {
Thread.sleep(500);
System.out.println(this.getName()+":printInfo");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
打印結果如下:
join線程:printInfo
joined線程5:被中斷
joined線程5:被中斷後的打印信息
join線程:printInfo
join線程:printInfo
joined線程10:被notify後的打印信息
joined線程6:被notify後的打印信息
joined線程2:被notify後的打印信息
joined線程1:被notify後的打印信息
joined線程9:被notify後的打印信息
joined線程7:被notify後的打印信息
joined線程3:被notify後的打印信息
joined線程8:被notify後的打印信息
joined線程4:被notify後的打印信息
Process finished with exit code 0
2.2 結果分析
顯然,被中斷的joined線程在join線程運行期間直接返回並拋出了InterruptedException。其實join()就相當於joined線程在synchronized中執行了join線程對象的wait(),因爲join方法被synchronized關鍵字修飾了,執行join()必須獲取到join線程對象這個鎖,與wait()中斷的過程一模一樣。
在上面例子中,因爲join線程對象沒有在我們代碼其它地方作爲synchronized的鎖被其它線程持有,所以joined線程5被中斷之後能立刻獲取鎖從join()返回。Thread.join()如下:
public final synchronized void join(long millis) throws InterruptedException {
...
while (isAlive()) {
wait(0);
}
...
}