Java中停止執行緒、中斷執行緒、等待狀態(wait)(基礎解析)
阿新 • • 發佈:2019-01-11
停止執行緒
測試interrupt中斷執行緒
測試interrupt中斷執行緒
public class Demo {
public static void main(String[] args) {
StopRunnable stopRunnable = new StopRunnable();
Thread t1 = new Thread(stopRunnable);
t1.start();
// 給t1執行緒有執行時間
try {
Thread.sleep(3000 );
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t1.interrupt();
System.out.println("執行緒已中斷");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("主執行緒結束");
}
}
class StopRunnable implements Runnable {
@Override
public void run() {
// 利用死迴圈 測試能不能停止執行緒
while(true) {
try {
// 沉睡1s
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 休眠1s(寫個死迴圈 讓迴圈執行1s結束)
long time = System.currentTimeMillis();
while (System.currentTimeMillis() - time < 1000) {
}
System.out.println(Thread.currentThread().getName() + "...run");
}
}
}
測試結果: 不能結束子執行緒
實際上這個Interrupt() 方法
設定了 isInterrupted 布林值
如果執行緒中有wait() 等待 或者 sleep 休眠
這時 呼叫 interrupt方法
會丟擲一個異常 InterruptedException
並且清除中斷狀態
如果執行緒中沒有等待 或者 休眠
這時呼叫interrupt方法
會設定中斷狀態(true/false的改變)
執行緒中沒有等待或睡眠 呼叫interrupt方法中斷執行緒
public class Demo {
public static void main(String[] args) {
StopRunnable stopRunnable = new StopRunnable();
Thread t1 = new Thread(stopRunnable);
t1.start();
// 給t1執行緒有執行時間
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
t1.interrupt();
System.out.println("執行緒已中斷");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("主執行緒結束");
}
}
class StopRunnable implements Runnable {
@Override
public void run() {
// 利用死迴圈 測試能不能停止執行緒
while(!Thread.currentThread().isInterrupted) {
// 休眠1s(寫個死迴圈 讓迴圈執行1s結束)
long time = System.currentTimeMillis();
while (System.currentTimeMillis() - time < 1000) {
}
System.out.println(Thread.currentThread().getName() + "...run");
}
}
}
利用標記 停止執行緒
利用標記 停止執行緒
public class Demo {
public static void main(String[] args) {
StopRunnable stopRunnable = new StopRunnable();
Thread t1 = new Thread(stopRunnable);
t1.start();
// 給t1執行緒有執行時間
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 利用標記 停止執行緒
stopRunnable.isOver = true;
System.out.println("執行緒已中斷");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("主執行緒結束");
}
}
class StopRunnable implements Runnable {
public boolean isOver = false;
@Override
public void run() {
// 利用死迴圈方式 測試能不能停止執行緒
while(!isOver) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 休眠1s(寫個死迴圈 讓迴圈執行1s結束)
long time = System.currentTimeMillis();
while (System.currentTimeMillis() - time < 1000) {
}
System.out.println(Thread.currentThread().getName() + "...run");
}
}
}
測試中斷狀態 wait方法
public class Demo {
public static void main(String[] args) {
InterruptRunnable it = new InterruptRunnable();
Thread t1 = new Thread(it);
Thread t2 = new Thread(it);
t1.start();
t2.start();
for (int i = 0; i < 50; i++) {
if (i == 25) {
// 呼叫中斷方法 來清楚狀態
t1.interrupt();
t2.interrupt();
break;
}
System.out.println(i + "---");
}
System.out.println("主執行緒結束");
}
}
class InterruptRunnable implements Runnable {
public synchronized void run() {
while(true) {
try {
// 執行緒1進來 帶著鎖 遇到了wait方法 等待
//放棄了CPU的執行權 但是 鎖 會還回去
// 執行緒2也帶著鎖進來 又遇到wait方法 也等待
// 相當於兩個執行緒都在這裡等待
// 進入冷凍(中斷)狀態
// 解決冷凍(中斷)狀態
// 呼叫interrupt方法 清除該狀態
wait();
}catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "...run");
}
}
}
這裡利用interrupt方法 清除冷凍(中斷)狀態
不會中斷執行緒會強行讓執行緒繼續執行
所以報異常後還會列印一次
利用標記法
public class Demo {
public static void main(String[] args) {
InterruptRunnable it = new InterruptRunnable();
Thread t1 = new Thread(it);
Thread t2 = new Thread(it);
t1.start();
t2.start();
for (int i = 0; i < 50; i++) {
if (i == 25) {
// 使用標記
it.isOver = true;
break;
}
System.out.println(i + "---");
}
System.out.println("主執行緒結束");
}
}
class InterruptRunnable implements Runnable {
public boolean isOver = fales;
@Override
public synchronized void run(){
while(!isOver){
try{
wait();
}catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "...run");
}
}
}
在使用標記法發現當到25的時候 程式不再列印
也不會像呼叫interrupt方法一樣報異常
但是也和呼叫interrupt方法一樣 沒有停止執行緒
說明使用了wait方法 會讓 執行緒等待 放棄了CPU的執行資源
執行緒就會一直在這裡等待
如果想喚醒執行緒 我們需要呼叫 notify方法來喚醒執行緒
wait方法 是 Object類的
報的異常為:IllegalMonitorStateException
這個異常解釋中的物件監視器 就是 物件鎖
注意: wait方法 必須用鎖物件去呼叫
注意
interrupt方法 進來不要使用
如果要停止執行緒 直接使用標記法停止
只有遇到了 等待狀態 時 可以使用 該方法
強行清除該狀態
小練習
Person類 姓名 性別
開啟兩個執行緒
一個對Person物件進行賦值
一個對Person物件進行列印
要求 一次列印 小明 男
一次列印 xiaoming nv
間隔輸出
public class Demo {
public static void main(String[] args) {
}
}
// Person類 姓名 性別
class Person {
public String name;
public String gender;
//宣告標記 來切換 列印 和 賦值
}
// 賦值執行緒
class SetRunnable implements Runnable {
// 利用成員變數 操作同一個物件
private Person p;
// 定義一個標識 通過改變標識來進行間隔賦值
Private boolean isTrue = true;
// 利用構造方法來賦值
public SetRunnable() {
}
public SetRunnable(Person p){
this.p = p;
}
@Override
public void run() {
while(true) {
//多個執行緒 操作共享資料
// 新增同步鎖 解決資料安全問題
// 為了保證兩個同步鎖的鎖物件相同 使用傳進來的p的物件
// 賦值執行緒 需要賦值完畢 列印執行緒才能去列印
// 列印執行緒 列印完畢 才能讓賦值執行緒 去賦值
// 賦值的時候 列印執行緒 在等待 等賦值完成了 才能去列印
// 列印完成後 通知複製執行緒 讓複製執行緒繼續賦值
//wait 和 notify 使用一個標記來進行切換
// 這個標記要給賦值執行緒使用 也要給列印執行緒使用
// 必須保證使用的是同一個標記 標記宣告在Person類中
synchronized(p) {
// 先不進入等待 要先進行賦值
if(p.flag == true) {
// 進行等待
try{
p.wait();
}catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 間隔賦值
if(isTrue) {
p.name = "小明";
p.gender = "男";
}else{
p.name = "xiaoming";
p.gender = "nb";
}
// 改變識別符號
isTrue = !isTrue;
// 修改標記
p.flag = true;
// 喚醒執行緒
p.notify();
}
}
}
}
// 列印執行緒
class PrintRunnable implements Runnable {
// 利用成員變數 操作同一個物件
private Person p;
//利用構造方法 來賦值
public PrintRunnable() {
}
public PrintRunnable(Person p) {
this.p = p
}
}
@Override
public void run(){
while(true){
synchronized(p) {
if(p.flag == false) {
// 進入等待
try{
p.wait();
}catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 列印名字 和 性別
System.out.println(p.name + "..." + p.gender);
// 修改標記
p.flag = false;
// 喚醒執行緒
p.notify();
}
}
}