Java 线程实例二(终止线程、生产者/消费者问题、获取线程状态、获取所有线程、查看线程优先级、中断线程)
終止線程
Java中原來在Thread中提供了stop()方法來終止線程,但這個方法是不安全的,所以一般不建議使用。
本文向大家介紹使用interrupt方法中斷線程。
使用interrupt方法來終端線程可分為兩種情況:
- (1)線程處于阻塞狀態,如使用了sleep方法。
- (2)使用while(!isInterrupted()){……}來判斷線程是否被中斷。
在第一種情況下使用interrupt方法,sleep方法將拋出一個InterruptedException例外,而在第二種情況下線程將直接退出。下面的代碼演示了在第一種情況下使用interrupt方法。
public class ThreadInterrupt extends Thread { public void run() { try { sleep(50000); // 延遲50秒 } catch (InterruptedException e) { System.out.println(e.getMessage()); } } public static void main(String[] args) throws Exception { Thread thread = new ThreadInterrupt(); thread.start(); System.out.println("在50秒之內按任意鍵中斷線程!"); System.in.read(); thread.interrupt(); thread.join(); System.out.println("線程已經退出!"); } }以上代碼運行輸出結果為:
在50秒之內按任意鍵中斷線程!sleep interrupted 線程已經退出!?
生產者/消費者問題
生產者和消費者問題是線程模型中的經典問題:生產者和消費者在同一時間段內共用同一個存儲空間,如下圖所示,生產者向空間里存放數據,而消費者取用數據,如果不加以協調可能會出現以下情況:
存儲空間已滿,而生產者占用著它,消費者等著生產者讓出空間從而去除產品,生產者等著消費者消費產品,從而向空間中添加產品。互相等待,從而發生死鎖。
以下實例演示了如何通過線程解決生產者/消費者問題:
public class ProducerConsumerTest {public static void main(String[] args) {CubbyHole c = new CubbyHole();Producer p1 = new Producer(c, 1);Consumer c1 = new Consumer(c, 1);p1.start(); c1.start();} } class CubbyHole {private int contents;private boolean available = false;public synchronized int get() {while (available == false) {try {wait();}catch (InterruptedException e) {}}available = false;notifyAll();return contents;}public synchronized void put(int value) {while (available == true) {try {wait();}catch (InterruptedException e) { } }contents = value;available = true;notifyAll();} }class Consumer extends Thread {private CubbyHole cubbyhole;private int number;public Consumer(CubbyHole c, int number) {cubbyhole = c;this.number = number;}public void run() {int value = 0;for (int i = 0; i < 10; i++) {value = cubbyhole.get();System.out.println("消費者 #" + this.number+ " got: " + value);}} }class Producer extends Thread {private CubbyHole cubbyhole;private int number;public Producer(CubbyHole c, int number) {cubbyhole = c;this.number = number;}public void run() {for (int i = 0; i < 10; i++) {cubbyhole.put(i);System.out.println("生產者 #" + this.number + " put: " + i);try {sleep((int)(Math.random() * 100));} catch (InterruptedException e) { }}} }以上代碼運行輸出結果為:
消費者 #1 got: 0 生產者 #1 put: 0 生產者 #1 put: 1 消費者 #1 got: 1 生產者 #1 put: 2 消費者 #1 got: 2 生產者 #1 put: 3 消費者 #1 got: 3 生產者 #1 put: 4 消費者 #1 got: 4 生產者 #1 put: 5 消費者 #1 got: 5 生產者 #1 put: 6 消費者 #1 got: 6 生產者 #1 put: 7 消費者 #1 got: 7 生產者 #1 put: 8 消費者 #1 got: 8 生產者 #1 put: 9 消費者 #1 got: 9?
獲取線程狀態
Java 線程的生命周期中,在 Thread 類里有一個枚舉類型 State,定義了線程的幾種狀態,分別有:
- New
- Runnable
- Blocked
- Waiting
- Timed Waiting
- Terminated
各個狀態說明:
1. 初始狀態 - NEW
聲明:
public static final Thread.State NEW實現 Runnable 接口和繼承 Thread 可以得到一個線程類,new 一個實例出來,線程就進入了初始狀態。
2. RUNNABLE
聲明:
public static final Thread.State RUNNABLE2.1. 就緒狀態
就緒狀態只是說你資格運行,調度程序沒有挑選到你,你就永遠是就緒狀態。
調用線程的 start() 方法,此線程進入就緒狀態。
當前線程 sleep() 方法結束,其他線程 join() 結束,等待用戶輸入完畢,某個線程拿到對象鎖,這些線程也將進入就緒狀態。
當前線程時間片用完了,調用當前線程的 yield() 方法,當前線程進入就緒狀態。
鎖池里的線程拿到對象鎖后,進入就緒狀態。
2.2. 運行中狀態
線程調度程序從可運行池中選擇一個線程作為當前線程時線程所處的狀態。這也是線程進入運行狀態的唯一一種方式。
3. 阻塞狀態 - BLOCKED
聲明:
public static final Thread.State BLOCKED阻塞狀態是線程阻塞在進入synchronized關鍵字修飾的方法或代碼塊(獲取鎖)時的狀態。
4. 等待 - WAITING
聲明:
public static final Thread.State WAITING處于這種狀態的線程不會被分配 CPU 執行時間,它們要等待被顯式地喚醒,否則會處于無限期等待的狀態。
5. 超時等待 - TIMED_WAITING
聲明:
public static final Thread.State TIMED_WAITING處于這種狀態的線程不會被分配 CPU 執行時間,不過無須無限期等待被其他線程顯示地喚醒,在達到一定時間后它們會自動喚醒。
6. 終止狀態 - TERMINATED
聲明:
public static final Thread.State TERMINATED當線程的 run() 方法完成時,或者主線程的 main() 方法完成時,我們就認為它終止了。這個線程對象也許是活的,但是,它已經不是一個單獨執行的線程。線程一旦終止了,就不能復生。
在一個終止的線程上調用 start() 方法,會拋出 java.lang.IllegalThreadStateException 異常。
以下實例演示了如何獲取線程的狀態:
class thread implements Runnable { public void run() { // thread2 - 超時等待try{ Thread.sleep(1500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("State of thread1 while it called join() method on thread2 -"+ Test.thread1.getState()); try{ Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } public class Test implements Runnable { public static Thread thread1; public static Test obj; public static void main(String[] args) { obj = new Test(); thread1 = new Thread(obj); // 創建 thread1,現在是初始狀態System.out.println("State of thread1 after creating it - " + thread1.getState()); thread1.start(); // thread1 - 就緒狀態System.out.println("State of thread1 after calling .start() method on it - " + thread1.getState()); } public void run() { thread myThread = new thread(); Thread thread2 = new Thread(myThread); // 創建 thread1,現在是初始狀態System.out.println("State of thread2 after creating it - "+ thread2.getState()); thread2.start(); // thread2 - 就緒狀態System.out.println("State of thread2 after calling .start() method on it - " + thread2.getState()); // moving thread1 to timed waiting state try{ //moving - 超時等待Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("State of thread2 after calling .sleep() method on it - "+ thread2.getState() ); try { // 等待 thread2 終止thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("State of thread2 when it has finished it's execution - " + thread2.getState()); } }以上代碼運行輸出結果為:
State of thread1 after creating it - NEW State of thread1 after calling .start() method on it - RUNNABLE State of thread2 after creating it - NEW State of thread2 after calling .start() method on it - RUNNABLE State of thread2 after calling .sleep() method on it - TIMED_WAITING State of thread1 while it called join() method on thread2 -WAITING State of thread2 when it has finished it's execution - TERMINATED?
獲取所有線程
以下實例演示了如何使用 getName() 方法獲取所有正在運行的線程:
public class Main extends Thread {public static void main(String[] args) {Main t1 = new Main();t1.setName("thread1");t1.start();ThreadGroup currentGroup = Thread.currentThread().getThreadGroup();int noThreads = currentGroup.activeCount();Thread[] lstThreads = new Thread[noThreads];currentGroup.enumerate(lstThreads);for (int i = 0; i < noThreads; i++)System.out.println("線程號:" + i + " = " + lstThreads[i].getName());} }以上代碼運行輸出結果為:
線程號:0 = main 線程號:1 = thread1?
查看線程優先級
以下實例演示了如何使用 getThreadId() 方法獲取線程id:
public class Main extends Object {private static Runnable makeRunnable() {Runnable r = new Runnable() {public void run() {for (int i = 0; i < 5; i++) {Thread t = Thread.currentThread();System.out.println("in run() - priority="+ t.getPriority()+ ", name=" + t.getName());try {Thread.sleep(2000);}catch (InterruptedException x) {}}}};return r;}public static void main(String[] args) {System.out.println("in main() - Thread.currentThread().getPriority()=" + Thread.currentThread().getPriority());System.out.println("in main() - Thread.currentThread().getName()="+ Thread.currentThread().getName());Thread threadA = new Thread(makeRunnable(), "threadA");threadA.start();try {Thread.sleep(3000);}catch (InterruptedException x) {}System.out.println("in main() - threadA.getPriority()="+ threadA.getPriority());} }以上代碼運行輸出結果為:
in main() - Thread.currentThread().getPriority()=5 in main() - Thread.currentThread().getName()=main in run() - priority=5, name=threadA in run() - priority=5, name=threadA in main() - threadA.getPriority()=5 in run() - priority=5, name=threadA in run() - priority=5, name=threadA in run() - priority=5, name=threadA?
中斷線程
以下實例演示了如何使用interrupt()方法來中斷線程并使用 isInterrupted() 方法來判斷線程是否已中斷:
public class Main extends Object implements Runnable {public void run() {try {System.out.println("in run() - 將運行 work2() 方法");work2();System.out.println("in run() - 從 work2() 方法回來");}catch (InterruptedException x) {System.out.println("in run() - 中斷 work2() 方法");return;}System.out.println("in run() - 休眠后執行");System.out.println("in run() - 正常離開");}public void work2() throws InterruptedException {while (true) {if (Thread.currentThread().isInterrupted()) {System.out.println("C isInterrupted()=" + Thread.currentThread().isInterrupted());Thread.sleep(2000);System.out.println("D isInterrupted()=" + Thread.currentThread().isInterrupted());}}}public void work() throws InterruptedException {while (true) {for (int i = 0; i < 100000; i++) {int j = i * 2;}System.out.println("A isInterrupted()=" + Thread.currentThread().isInterrupted());if (Thread.interrupted()) {System.out.println("B isInterrupted()=" + Thread.currentThread().isInterrupted());throw new InterruptedException();}}}public static void main(String[] args) {Main si = new Main();Thread t = new Thread(si);t.start();try {Thread.sleep(2000);}catch (InterruptedException x) {}System.out.println("in main() - 中斷其他線程");t.interrupt();System.out.println("in main() - 離開");} }以上代碼運行輸出結果為:
in run() - 將運行 work2() 方法 in main() - 中斷其他線程 in main() - 離開 C isInterrupted()=true in run() - 中斷 work2() 方法?
總結
以上是生活随笔為你收集整理的Java 线程实例二(终止线程、生产者/消费者问题、获取线程状态、获取所有线程、查看线程优先级、中断线程)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python获取环境变量值
- 下一篇: Java 反射调用方法实例,动态动用方法