【Java 语言】Java 多线程 一 ( 线程基础 : 线程启动 | 线程停止 | 线程暂停 | 线程优先级 | 守护线程)
一. 線程啟動(dòng)
線程啟動(dòng) :?
-- 1. 繼承 Thread 運(yùn)行線程 : 重寫 Thread 類的 run 方法, 然后執(zhí)行該線程;
-- 2. 實(shí)現(xiàn) Runnable 接口, 并運(yùn)行線程;
-- 代碼示例 :?
package com.hanshuliang.thread;public class ThreadStart {public static void main(String[] args) {//1. 繼承 Thread 運(yùn)行線程MyThread thread = new MyThread();thread.start();//2. 實(shí)現(xiàn) Runnable 接口, 并運(yùn)行線程Thread runnableThread = new Thread(new MyRunnable());runnableThread.start();}//1. 繼承 Thread 類static class MyThread extends Thread{@Overridepublic void run() {super.run();System.out.println("MyThread 線程啟動(dòng)");}}//2. 實(shí)現(xiàn) Runnable 接口static class MyRunnable implements Runnable{@Overridepublic void run() {System.out.println("MyRunnable 線程啟動(dòng)");}} }
-- 運(yùn)行結(jié)果 :?
MyThread 線程啟動(dòng) MyRunnable 線程啟動(dòng)
三. 線程停止
線程停止常用方法 :?
-- 1. 使用 interrupt() 方法停止線程;
-- 2. 使用退出標(biāo)志, 讓線程正常退出;
-- 3. 棄用的方法 (不推薦) : 使用 stop() 方法強(qiáng)制停止線程, 但是該方法已經(jīng)作廢, 不建議使用;
1. 使用 interrupt() 方法停止線程
(1) 線程無法立即停止
interrupt() 使用說明 :?
-- 打標(biāo)記 : 調(diào)用該方法, 不能馬上停止該線程, 只是在當(dāng)前線程打了一個(gè)停止標(biāo)記;
代碼示例 :?
-- 代碼 :?
public class InterruptDemo {public static class MyThread extends Thread {@Overridepublic void run() {super.run();for (int i = 1; i <= 1000000; i++) //打印 一百萬 數(shù)字, 大概持續(xù) 5 ~ 10 秒左右System.out.println(i);}}public static void main(String[] args) throws InterruptedException {MyThread thread = new MyThread();thread.start(); //啟動(dòng)線程Thread.sleep(100); //啟動(dòng)線程 100ms 后中斷線程thread.interrupt(); //中斷線程} }
-- 運(yùn)行結(jié)果 : 這里只貼上最后幾行 命令行的運(yùn)行結(jié)果;
... ... 999996 999997 999998 999999 1000000
-- 總結(jié) : 在上述程序中, 打印了 100 萬數(shù)字, 從 1 到 100 0000, 整個(gè)過程持續(xù)了 10秒左右, 但是我們?cè)?線程開始后?100ms 就中斷了線程, 但是線程還是執(zhí)行完畢了, 說明線程并沒有在調(diào)用 interrupt() 方法后立即停止;
(2) 線程停止?fàn)顟B(tài)判定
兩個(gè)線程停止?fàn)顟B(tài)判定的方法 :?
-- 1. interrupted() 方法 : ①判斷當(dāng)前線程的中斷標(biāo)志, ②如果是中斷標(biāo)志 true, 那么清除中斷標(biāo)志, 改為 false;,③ 連續(xù)兩次調(diào)用該方法, 第二次返回 false, ④ 靜態(tài)方法 : 該方法是測試當(dāng)前線程的中斷標(biāo)志, 在哪個(gè)線程中調(diào)用, 就是判定的哪個(gè)線程的中斷標(biāo)志, 不管調(diào)用的主體是哪個(gè)線程;
-- 2. isInterrupted() 方法 : 判斷線程的?中斷狀態(tài), 不管真實(shí)的運(yùn)行狀態(tài), 只關(guān)心狀態(tài);
-- 注意 : 兩個(gè)方法都是判斷 中斷狀態(tài)的, 與線程的真實(shí)運(yùn)行狀況無關(guān);
(3) interrupted() 方法測試
interrupted () 方法測試1 : 測試 interrupted 方法的判斷是否已經(jīng)中斷的效果;
-- 測試代碼 :?
public class InterruptedDemo1 {public static class MyThread extends Thread {@Overridepublic void run() {super.run();for (int i = 1; i <= 10; i++) //打印10個(gè)數(shù)字System.out.println(i);}}public static void main(String[] args) throws InterruptedException {MyThread thread = new MyThread();thread.start(); //啟動(dòng)線程thread.interrupt(); //啟動(dòng)線程后馬上 中斷線程System.out.println("第一次 : thread.interrupted() = " + thread.interrupted());System.out.println("第二次 : thread.interrupted() = " + thread.interrupted());} }
-- 執(zhí)行結(jié)果 :?
第一次 : thread.interrupted() = false 1 2 第二次 : thread.interrupted() = false 3 4 5 6 7 8 9 10
-- 總結(jié) : 啟動(dòng)線程后, 立即調(diào)用 interrupt 方法 中斷線程, 但是 在主線程中?調(diào)用 thread.Interrupted() 方法, 打印出來的是 主線程的中斷狀態(tài)標(biāo)志, 雖然是調(diào)用的 thread 子線程的對(duì)象的方法, 但是該方法是一個(gè)靜態(tài)方法, 在哪個(gè)線程調(diào)用, 就是打印哪個(gè)線程的中斷標(biāo)志;
interrupted () 方法測試2 : 測試 interrupted 方法的 清除 中斷狀態(tài) 的效果;
-- 1. 測試代碼 :?
public class InterruptedDemo {public static void main(String[] args) throws InterruptedException {Thread.currentThread().interrupt(); //中斷主線程System.out.println("第一次 : thread.interrupted() = " + Thread.interrupted());System.out.println("第二次 : thread.interrupted() = " + Thread.interrupted());} }
-- 2. 執(zhí)行結(jié)果 :?
第一次 : thread.interrupted() = true 第二次 : thread.interrupted() = false
-- 3. 總結(jié) : 使用 interrupted() 方法, 如果當(dāng)前線程的狀態(tài)是中斷狀態(tài), 即返回了 true, 那么需要清除該標(biāo)志, 下一次調(diào)用 interrupted() 方法后, 返回值就是 false 了;
(4) isInterrupted() 方法測試
isInterrupted() 方法測試1 : 測試其 中斷狀態(tài), 與上面的 interrupted() 方法對(duì)比;
-- 1. 測試代碼 :?
public class IsInterruptedDemo {public static class MyThread extends Thread {@Overridepublic void run() {super.run();for (int i = 1; i <= 10; i++) //打印10個(gè)數(shù)字System.out.println(i);}}public static void main(String[] args) throws InterruptedException {MyThread thread = new MyThread();thread.start(); //啟動(dòng)線程thread.interrupt(); //啟動(dòng)線程后馬上 中斷線程System.out.println("第一次 : thread.interrupted() = " + thread.isInterrupted());System.out.println("第二次 : thread.interrupted() = " + thread.isInterrupted());} }
-- 2. 返回值 :?
第一次 : thread.interrupted() = true 1 2 第二次 : thread.interrupted() = true 3 4 5 6 7 8 9 10
-- 3. 總結(jié)分析 : isInterrupted() 方法 只 判斷 被調(diào)用對(duì)象的 該對(duì)象線程的?線程的中斷 狀態(tài), 不管線程的真實(shí)運(yùn)行狀況, 即使當(dāng)前線程正在運(yùn)行, 但是線程調(diào)用了 interrupt() 方法, 其中斷狀態(tài)為 true, 因此 isInterrupted() 方法的返回值一直是 true;
-- 4. 對(duì)比 interrupted() 方法 : interrupted() 方法反應(yīng)的是真實(shí)的線程運(yùn)行狀態(tài), 線程正在運(yùn)行, 那么返回 false, 如果線程沒有運(yùn)行, 返回 true;
-- 5. 對(duì)比 Interrupted() 方法 (靜態(tài)與普通方法) : isInterrupted 方法是非靜態(tài)方法, 哪個(gè)對(duì)象調(diào)用返回的就是哪個(gè)對(duì)象的中斷狀態(tài); interrupted 是靜態(tài)方法, 在哪個(gè)線程調(diào)用就是返回哪個(gè)線程的中斷狀態(tài);
2. 異常法停止線程
(1) 線程循環(huán)中正常退出停止
退出方法 : 正常退出線程;
-- 1. 前提 : 線程中執(zhí)行一個(gè)循環(huán);
-- 2. 中斷線程 : 執(zhí)行線程中斷操作, 調(diào)用 線程的 interrupt() 方法;
-- 3. 查詢中斷標(biāo)志 : 在線程中通過調(diào)用 interrupted 方法, 查詢當(dāng)前的線程中斷標(biāo)志, 之后該方法就會(huì)將中斷標(biāo)志清除;
-- 4. 退出循環(huán) : 如果查詢到中斷標(biāo)志后, 直接使用 break 退出循環(huán);
-- 5. 弊端 : 在線程中, 線程沒有真正的停止, 線程還是完整的執(zhí)行了;
線程正常退出代碼示例 :?
-- 1. 代碼 :?
public class ExceptionInterruptDeo {public static class MyThread extends Thread{@Overridepublic void run() {super.run();for(int i = 0; i < 500; i ++){if(interrupted()){ //判斷線程的中斷狀態(tài), 如果中斷直接 breakSystem.out.println("停止?fàn)顟B(tài), 退出");break;}System.out.println(i);}System.out.println("MyThread 線程執(zhí)行完畢");//線程結(jié)束標(biāo)志}}public static void main(String[] args) throws InterruptedException {MyThread thread = new MyThread(); //創(chuàng)建線程并執(zhí)行thread.start(); //啟動(dòng)線程Thread.sleep(1); //沉睡 1 毫秒thread.interrupt(); //中斷線程System.out.println("主線程執(zhí)行完畢"); //判斷主線程停止} }
-- 2. 執(zhí)行結(jié)果 :?
... ... 50 51 52 53 54 主線程執(zhí)行完畢 停止?fàn)顟B(tài), 退出 MyThread 線程執(zhí)行完畢
-- 3. 總結(jié)分析 : 在線程中調(diào)用 interrupted() 方法, 查詢中斷標(biāo)志(查詢后立即清除中斷標(biāo)志), 弊端是停止線程后, 線程還是繼續(xù)執(zhí)行后面的邏輯, 繼續(xù)執(zhí)行完畢, 自動(dòng)退出的;
(2) 異常退出線程
異常法退出線程 : 通過拋出一個(gè)異常, 來終止線程執(zhí)行;
--?1. 前提?: 線程中執(zhí)行一個(gè)循環(huán);
--?2. 中斷線程?: 執(zhí)行線程中斷操作, 調(diào)用 線程的 interrupt() 方法;
--?3. 查詢中斷標(biāo)志?: 在線程中通過調(diào)用 interrupted 方法, 查詢當(dāng)前的線程中斷標(biāo)志, 之后該方法就會(huì)將中斷標(biāo)志清除;
--?4. 拋出異常退出循環(huán)?: 如果查詢到中斷標(biāo)志后, 直接拋出一個(gè) InterruptException 異常;
-- 5. 捕獲處理異常 : 要將整個(gè) run 方法中的內(nèi)容使用 try catch 代碼塊捕獲, 因因?yàn)楫惓2东@后還會(huì)繼續(xù)處理 try catch 之后的代碼邏輯, 如果 try catch 代碼塊之后還有代碼邏輯, 程序還會(huì)執(zhí)行這段代碼;
-- 6. 好處 : 可以自由控制要中斷哪些邏輯;
異常捕獲規(guī)則 :?
-- 1. 執(zhí)行邏輯 : 捕獲異常后, 進(jìn)行異常處理, 然后會(huì)繼續(xù)執(zhí)行 try catch 代碼塊 后面的代碼邏輯;
-- 2. 異常退出范圍可控 : 可以自由控制中斷哪些操作, 繼續(xù)執(zhí)行哪些操作;
代碼測試 :?
-- 1. 代碼 :?
public class ExceptionInterruptDeo {public static class MyThread extends Thread {@Overridepublic void run() {try {super.run();for (int i = 0; i < 500; i++) {if (interrupted()) { // 判斷線程的中斷狀態(tài), 如果中斷直接 breakSystem.out.println("停止?fàn)顟B(tài), 拋出異常退出");throw new InterruptedException();}// 中斷標(biāo)志 判定結(jié)束System.out.println(i);}//for 循環(huán)結(jié)束System.out.println("MyThread 線程執(zhí)行完畢");// 線程結(jié)束標(biāo)志} catch (InterruptedException e) {System.out.println("線程中捕獲異常代碼塊");e.printStackTrace();} // try catch 代碼塊}//run方法結(jié)束}//線程結(jié)束public static void main(String[] args) throws InterruptedException {MyThread thread = new MyThread(); // 創(chuàng)建線程并執(zhí)行thread.start(); // 啟動(dòng)線程Thread.sleep(1); // 沉睡 1 毫秒thread.interrupt(); // 中斷線程System.out.println("主線程執(zhí)行完畢"); // 判斷主線程停止} }
-- 2. 執(zhí)行結(jié)果 :?
113 114 115 116 主線程執(zhí)行完畢 停止?fàn)顟B(tài), 拋出異常退出 線程中捕獲異常代碼塊 java.lang.InterruptedExceptionat base.ExceptionInterruptDeo$MyThread.run(ExceptionInterruptDeo.java:12)
-- 3. 總結(jié)分析 : 在 run 方法中將整個(gè)代碼邏輯使用 try catch 代碼塊包裹, 異常法只能中斷 try catch 代碼塊中的邏輯;
3. sleep() 中停止線程
(1) 先沉睡在終止線程
先 sleep() 再 interrupt() : 先沉睡, 再終止線程, 線程直接就停止了;
代碼示例 :?
-- 1. 代碼 :?
public class SleepInterruptDemo {public static class MyThread extends Thread{@Overridepublic void run() {try {System.out.println("線程邏輯開始");super.run();sleep(1000); //啟動(dòng)后立即進(jìn)入沉睡狀態(tài), 沉睡 1000msSystem.out.println("線程邏輯結(jié)束");} catch (InterruptedException e) {System.out.println("捕獲到了異常 , 進(jìn)入了 catch 代碼塊");e.printStackTrace();}//catch代碼塊System.out.println("run 方法結(jié)束");}//run方法}//線程public static void main(String[] args) throws InterruptedException {MyThread thread = new MyThread(); //新建線程thread.start(); //線程啟動(dòng)Thread.sleep(100); //沉睡 100 毫秒, 線程中thread.interrupt(); //中斷線程} }
-- 2. 執(zhí)行結(jié)果 :?
線程邏輯開始 捕獲到了異常 , 進(jìn)入了 catch 代碼塊 run 方法結(jié)束 java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at base.SleepInterruptDemo$MyThread.run(SleepInterruptDemo.java:11)
-- 3. 總結(jié)分析 : 在沉睡狀態(tài)下, 如果調(diào)用 interrupt() 方法, 線程中會(huì)直接拋出 InterruptException 異常;
(2) 先終止線程 再 沉睡
先 終止線程 再 sleep : 先 終止線程, 在 sleep, 那么 sleep 之前的代碼需要實(shí)現(xiàn)相關(guān)邏輯
代碼示例 :?
-- 1. 代碼 : 與上面的區(qū)別是 在 sleep 之前有一段 循環(huán)邏輯;
public class SleepInterruptDemo {public static class MyThread extends Thread{@Overridepublic void run() {try {System.out.println("線程邏輯開始");super.run();for(int i = 0; i < 500; i ++)System.out.println(i);sleep(1000); //啟動(dòng)后立即進(jìn)入沉睡狀態(tài), 沉睡 1000msSystem.out.println("線程邏輯結(jié)束");} catch (InterruptedException e) {System.out.println("捕獲到了異常 , 進(jìn)入了 catch 代碼塊");e.printStackTrace();}//catch代碼塊System.out.println("run 方法結(jié)束");}//run方法}//線程public static void main(String[] args) throws InterruptedException {MyThread thread = new MyThread(); //新建線程thread.start(); //線程啟動(dòng)thread.interrupt(); //中斷線程System.out.println("主線程中斷線程");} }
-- 2. 執(zhí)行結(jié)果 :?
496 497 498 499 捕獲到了異常 , 進(jìn)入了 catch 代碼塊 run 方法結(jié)束 java.lang.InterruptedException: sleep interruptedat java.lang.Thread.sleep(Native Method)at base.SleepInterruptDemo$MyThread.run(SleepInterruptDemo.java:12)
-- 3. 總結(jié) : 使用 Interrupt 方法后, 如果正在執(zhí)行循環(huán), 就不會(huì)拋異常退出線程, 進(jìn)入 sleep 狀態(tài)后, 會(huì)立即拋出異常, 退出線程;
4. stop() 停止線程
(1) stop 方法停止線程的效果
stop 停止線程 :?
-- 1. 立即停止 : 調(diào)用 stop() 方法停止線程, 比較暴力, 會(huì)立即停止當(dāng)前的線程;
-- 2. 拋出異常 : 使用 stop() 方法停止線程會(huì)拋出一個(gè) ThreadDeath 異常, 這個(gè)異常可以不捕捉;
-- 3. 適用場景 : 適用該方法停止線程, 前提示 線程的相關(guān)數(shù)據(jù) 和 線程本身 都不再使用了, 否則會(huì)造成數(shù)據(jù)混亂;
stop() 停止線程效果演示 :?
-- 1. 代碼示例 :?
public class StopDemo {public static class MyThread extends Thread{@Overridepublic void run() {try {System.out.println("線程邏輯開始");super.run();for(int i = 0; i < 5000; i ++){System.out.println(i);sleep(100); }System.out.println("線程邏輯結(jié)束");} catch (InterruptedException e) {System.out.println("捕獲到了 InterruptedException 異常 , 進(jìn)入了 catch 代碼塊");e.printStackTrace();}//catch代碼塊System.out.println("run 方法結(jié)束");}//run方法}//線程public static void main(String[] args) throws InterruptedException {MyThread thread = new MyThread(); //新建線程thread.start(); //線程啟動(dòng)Thread.sleep(500); //沉睡 500ms, 讓線程打印 5 個(gè)數(shù)字thread.stop(); //中斷線程System.out.println("主線程中斷線程");} }
-- 2. 運(yùn)行結(jié)果 :?
線程邏輯開始 0 1 2 3 4 主線程中斷線程
-- 3. 總結(jié)分析 : 線程直接中斷了, 線程中 run() 方法的最后一行代碼也沒有執(zhí)行, 循環(huán)邏輯結(jié)束也沒有執(zhí)行, 說明線程很暴力的直接退出, 沒有任何處理;
(2) stop 方法停止線程 捕獲 ThreadDeath 異常
關(guān)于異常捕捉 :?
-- 1. 捕捉 ThreadDeath 異常 : 線程捕獲異常處理后, 還會(huì)繼續(xù)執(zhí)行 try catch 代碼塊下面的代碼;
-- 2. 不捕捉 ThreadDeath 異常 : 線程直接從 stop 時(shí)刻退出, 不會(huì)執(zhí)行下面的代碼;
stop() 停止線程 并 捕獲異常 效果演示 :?
-- 1. 代碼示例 : 代碼中比上面多了一個(gè) catch ThreadDeath 異常的代碼塊, 其它一樣;
public class StopDemo {public static class MyThread extends Thread{@Overridepublic void run() {try {System.out.println("線程邏輯開始");super.run();for(int i = 0; i < 5000; i ++){System.out.println(i);sleep(100); }System.out.println("線程邏輯結(jié)束");} catch (InterruptedException e) {System.out.println("捕獲到了 InterruptedException 異常 , 進(jìn)入了 catch 代碼塊");e.printStackTrace();}catch (ThreadDeath e){System.out.println("捕獲到了 ThreadDeath 異常 , 進(jìn)入了 catch 代碼塊");e.printStackTrace();}//catch代碼塊System.out.println("run 方法結(jié)束");}//run方法}//線程public static void main(String[] args) throws InterruptedException {MyThread thread = new MyThread(); //新建線程thread.start(); //線程啟動(dòng)Thread.sleep(500); //沉睡 500ms, 讓線程打印 5 個(gè)數(shù)字thread.stop(); //中斷線程System.out.println("主線程中斷線程");} }
-- 2. 運(yùn)行結(jié)果 :?
線程邏輯開始 0 1 2 3 4 主線程中斷線程 捕獲到了 ThreadDeath 異常 , 進(jìn)入了 catch 代碼塊 run 方法結(jié)束 java.lang.ThreadDeathat java.lang.Thread.stop(Unknown Source)at com.hanshuliang.thread.StopDemo.main(StopDemo.java:31)
-- 3. 總結(jié)分析 : 如果捕獲了 ThreadDeath 異常, 就會(huì)處理這個(gè)異常, 并會(huì)執(zhí)行異常處理后面的代碼, run() 方法的最后一行代碼也執(zhí)行完畢了;
5. return 停止線程
return 停止線程說明 :?
-- 1. 執(zhí)行過程 : 線程運(yùn)行中, 隨時(shí)監(jiān)測中斷標(biāo)記, 如果檢測到中斷標(biāo)記后, 直接 return 退出 run 方法;
-- 2. 不建議使用該方法, 多個(gè) return 會(huì)污染代碼;
return 退出演示 :?
-- 1. 代碼示例 :?
public class ReturnDemo {public static class MyThread extends Thread{@Overridepublic void run() {super.run();for(int i = 0; i < 500; i ++){if(interrupted()){ //判斷線程的中斷狀態(tài), 如果中斷直接 breakSystem.out.println("停止?fàn)顟B(tài), return 退出");return;}System.out.println(i);}System.out.println("MyThread 線程執(zhí)行完畢");//線程結(jié)束標(biāo)志}}public static void main(String[] args) throws InterruptedException {MyThread thread = new MyThread(); //創(chuàng)建線程并執(zhí)行thread.start(); //啟動(dòng)線程Thread.sleep(1); //沉睡 1 毫秒thread.interrupt(); //中斷線程System.out.println("主線程執(zhí)行完畢"); //判斷主線程停止} }
-- 2. 執(zhí)行結(jié)果 :?
... ... 35 36 37 38 39 主線程執(zhí)行完畢 停止?fàn)顟B(tài), return 退出
-- 3. 總結(jié)分析 : 使用 return 直接退出 run 方法, 確實(shí)實(shí)現(xiàn)了立即停止線程的目的, 但是我們還是建議使用 異常法 控制線程停止;
.
四. 線程暫停
線程停止常用方法?:?
--?1. 使用 interrupt() 方法停止線程;
--?2. 使用退出標(biāo)志, 讓線程正常退出;
--?3. 棄用的方法 (不推薦)?: 使用 stop() 方法強(qiáng)制停止線程, 但是該方法已經(jīng)作廢, 不建議使用;
1. 使用 interrupt() 方法停止線程
(1) 線程無法立即停止
interrupt() 使用說明?:?
.
.
.
.
轉(zhuǎn)載注明出處 :?http://blog.csdn.net/shulianghan/article/details/52369486
總結(jié)
以上是生活随笔為你收集整理的【Java 语言】Java 多线程 一 ( 线程基础 : 线程启动 | 线程停止 | 线程暂停 | 线程优先级 | 守护线程)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android 应用开发】 Andro
- 下一篇: 【C 语言】编译过程 分析 ( 预处理