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