Java 线程实例二(终止线程、生产者/消费者问题、获取线程状态、获取所有线程、查看线程优先级、中断线程)
終止線程
Java中原來在Thread中提供了stop()方法來終止線程,但這個(gè)方法是不安全的,所以一般不建議使用。
本文向大家介紹使用interrupt方法中斷線程。
使用interrupt方法來終端線程可分為兩種情況:
- (1)線程處于阻塞狀態(tài),如使用了sleep方法。
- (2)使用while(!isInterrupted()){……}來判斷線程是否被中斷。
在第一種情況下使用interrupt方法,sleep方法將拋出一個(gè)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秒之內(nèi)按任意鍵中斷線程!"); System.in.read(); thread.interrupt(); thread.join(); System.out.println("線程已經(jīng)退出!"); } }以上代碼運(yùn)行輸出結(jié)果為:
在50秒之內(nèi)按任意鍵中斷線程!sleep interrupted 線程已經(jīng)退出!?
生產(chǎn)者/消費(fèi)者問題
生產(chǎn)者和消費(fèi)者問題是線程模型中的經(jīng)典問題:生產(chǎn)者和消費(fèi)者在同一時(shí)間段內(nèi)共用同一個(gè)存儲(chǔ)空間,如下圖所示,生產(chǎn)者向空間里存放數(shù)據(jù),而消費(fèi)者取用數(shù)據(jù),如果不加以協(xié)調(diào)可能會(huì)出現(xiàn)以下情況:
存儲(chǔ)空間已滿,而生產(chǎn)者占用著它,消費(fèi)者等著生產(chǎn)者讓出空間從而去除產(chǎn)品,生產(chǎn)者等著消費(fèi)者消費(fèi)產(chǎn)品,從而向空間中添加產(chǎn)品?;ハ嗟却?#xff0c;從而發(fā)生死鎖。
以下實(shí)例演示了如何通過線程解決生產(chǎn)者/消費(fèi)者問題:
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("消費(fèi)者 #" + 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("生產(chǎn)者 #" + this.number + " put: " + i);try {sleep((int)(Math.random() * 100));} catch (InterruptedException e) { }}} }以上代碼運(yùn)行輸出結(jié)果為:
消費(fèi)者 #1 got: 0 生產(chǎn)者 #1 put: 0 生產(chǎn)者 #1 put: 1 消費(fèi)者 #1 got: 1 生產(chǎn)者 #1 put: 2 消費(fèi)者 #1 got: 2 生產(chǎn)者 #1 put: 3 消費(fèi)者 #1 got: 3 生產(chǎn)者 #1 put: 4 消費(fèi)者 #1 got: 4 生產(chǎn)者 #1 put: 5 消費(fèi)者 #1 got: 5 生產(chǎn)者 #1 put: 6 消費(fèi)者 #1 got: 6 生產(chǎn)者 #1 put: 7 消費(fèi)者 #1 got: 7 生產(chǎn)者 #1 put: 8 消費(fèi)者 #1 got: 8 生產(chǎn)者 #1 put: 9 消費(fèi)者 #1 got: 9?
獲取線程狀態(tài)
Java 線程的生命周期中,在 Thread 類里有一個(gè)枚舉類型 State,定義了線程的幾種狀態(tài),分別有:
- New
- Runnable
- Blocked
- Waiting
- Timed Waiting
- Terminated
各個(gè)狀態(tài)說明:
1. 初始狀態(tài) - NEW
聲明:
public static final Thread.State NEW實(shí)現(xiàn) Runnable 接口和繼承 Thread 可以得到一個(gè)線程類,new 一個(gè)實(shí)例出來,線程就進(jìn)入了初始狀態(tài)。
2. RUNNABLE
聲明:
public static final Thread.State RUNNABLE2.1. 就緒狀態(tài)
就緒狀態(tài)只是說你資格運(yùn)行,調(diào)度程序沒有挑選到你,你就永遠(yuǎn)是就緒狀態(tài)。
調(diào)用線程的 start() 方法,此線程進(jìn)入就緒狀態(tài)。
當(dāng)前線程 sleep() 方法結(jié)束,其他線程 join() 結(jié)束,等待用戶輸入完畢,某個(gè)線程拿到對象鎖,這些線程也將進(jìn)入就緒狀態(tài)。
當(dāng)前線程時(shí)間片用完了,調(diào)用當(dāng)前線程的 yield() 方法,當(dāng)前線程進(jìn)入就緒狀態(tài)。
鎖池里的線程拿到對象鎖后,進(jìn)入就緒狀態(tài)。
2.2. 運(yùn)行中狀態(tài)
線程調(diào)度程序從可運(yùn)行池中選擇一個(gè)線程作為當(dāng)前線程時(shí)線程所處的狀態(tài)。這也是線程進(jìn)入運(yùn)行狀態(tài)的唯一一種方式。
3. 阻塞狀態(tài) - BLOCKED
聲明:
public static final Thread.State BLOCKED阻塞狀態(tài)是線程阻塞在進(jìn)入synchronized關(guān)鍵字修飾的方法或代碼塊(獲取鎖)時(shí)的狀態(tài)。
4. 等待 - WAITING
聲明:
public static final Thread.State WAITING處于這種狀態(tài)的線程不會(huì)被分配 CPU 執(zhí)行時(shí)間,它們要等待被顯式地喚醒,否則會(huì)處于無限期等待的狀態(tài)。
5. 超時(shí)等待 - TIMED_WAITING
聲明:
public static final Thread.State TIMED_WAITING處于這種狀態(tài)的線程不會(huì)被分配 CPU 執(zhí)行時(shí)間,不過無須無限期等待被其他線程顯示地喚醒,在達(dá)到一定時(shí)間后它們會(huì)自動(dòng)喚醒。
6. 終止?fàn)顟B(tài) - TERMINATED
聲明:
public static final Thread.State TERMINATED當(dāng)線程的 run() 方法完成時(shí),或者主線程的 main() 方法完成時(shí),我們就認(rèn)為它終止了。這個(gè)線程對象也許是活的,但是,它已經(jīng)不是一個(gè)單獨(dú)執(zhí)行的線程。線程一旦終止了,就不能復(fù)生。
在一個(gè)終止的線程上調(diào)用 start() 方法,會(huì)拋出 java.lang.IllegalThreadStateException 異常。
以下實(shí)例演示了如何獲取線程的狀態(tài):
class thread implements Runnable { public void run() { // thread2 - 超時(shí)等待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); // 創(chuàng)建 thread1,現(xiàn)在是初始狀態(tài)System.out.println("State of thread1 after creating it - " + thread1.getState()); thread1.start(); // thread1 - 就緒狀態(tài)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); // 創(chuàng)建 thread1,現(xiàn)在是初始狀態(tài)System.out.println("State of thread2 after creating it - "+ thread2.getState()); thread2.start(); // thread2 - 就緒狀態(tài)System.out.println("State of thread2 after calling .start() method on it - " + thread2.getState()); // moving thread1 to timed waiting state try{ //moving - 超時(shí)等待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()); } }以上代碼運(yùn)行輸出結(jié)果為:
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?
獲取所有線程
以下實(shí)例演示了如何使用 getName() 方法獲取所有正在運(yùn)行的線程:
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());} }以上代碼運(yùn)行輸出結(jié)果為:
線程號:0 = main 線程號:1 = thread1?
查看線程優(yōu)先級
以下實(shí)例演示了如何使用 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());} }以上代碼運(yùn)行輸出結(jié)果為:
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?
中斷線程
以下實(shí)例演示了如何使用interrupt()方法來中斷線程并使用 isInterrupted() 方法來判斷線程是否已中斷:
public class Main extends Object implements Runnable {public void run() {try {System.out.println("in run() - 將運(yùn)行 work2() 方法");work2();System.out.println("in run() - 從 work2() 方法回來");}catch (InterruptedException x) {System.out.println("in run() - 中斷 work2() 方法");return;}System.out.println("in run() - 休眠后執(zhí)行");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() - 離開");} }以上代碼運(yùn)行輸出結(jié)果為:
in run() - 將運(yùn)行 work2() 方法 in main() - 中斷其他線程 in main() - 離開 C isInterrupted()=true in run() - 中斷 work2() 方法?
總結(jié)
以上是生活随笔為你收集整理的Java 线程实例二(终止线程、生产者/消费者问题、获取线程状态、获取所有线程、查看线程优先级、中断线程)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python获取环境变量值
- 下一篇: Java 反射调用方法实例,动态动用方法