日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java 切换主线程_Java线程状态及切换、关闭线程的正确姿势分享

發布時間:2024/7/19 java 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 切换主线程_Java线程状态及切换、关闭线程的正确姿势分享 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

在講線程之前有必要討論一下進程的定義:進程是程序在一個數據集合上運行的過程,它是系統進行資源分配和調度的一個獨立單位。進程實體由程序段, 數據段 PCB(進程控制塊)組成。線程又是什么?線程可以看做輕量級進程,線程是進程的執行單元,是進程調度的基本單位

本文將詳細介紹關于Java線程狀態及切換、關閉線程的相關內容,下面話不多說了,來一起看看詳細的介紹吧

1、線程狀態及切換

Java中的線程有六種狀態,使用線程Thread內的枚舉類來實現,如下,我對每個狀態都進行了一定的解釋。

public enum State {

/** 表示一個線程還沒啟用(即未調用start方法)*/

NEW,

/**

* JVM中執行的線程都是處于這個狀態的,但是處于這個狀態不一定在JVM中執行,

* 也就是說,只有這個狀態有資格被JVM調度從而獲得時間片執行。

*/

RUNNABLE,

/**

* 線程在等待獲取鎖資源從而進入阻塞狀態,

* 在這個狀態中,其一直監視鎖的動態,隨時準備搶占鎖

* 若獲得鎖資源,重新進入RUNNABLE狀態

*/

BLOCKED,

/**

* 當調用Object.wait、Thread.join或者LockSupport類的park方法的時候,線程進入此狀態,

* 該狀態若無其他線程主動喚醒,則無期限的等待。

* 喚醒的方法包括:Object.notify(喚醒隨機一個)、Object.notifyAll(喚醒全部線程),

* 被喚醒的線程重新進入RUNNABLE狀態

*/

WAITING,

/**

* 同WAITING狀態,不過不同的是調用的方法加上了時間的限制,

* 例如:Object.wait(10)、Thread.sleep(10)、Thread.join(10)、LockSupport.parkNanos(10)、LockSupport.parkUntil(10)這些方法

* 喚醒的方法有兩種:

* 1、時間過期。

* 2、其他線程調用了notify或者notifyAll

* 喚醒之后同樣進入RUNNABLE狀態

*/

TIMED_WAITING,

/** 線程的終點(正常死亡或者被終止)*/

TERMINATED;

}

除了NEW和TERMINATED之外,其他的狀態都是可以相互轉換的,其轉換過程如下圖所示

這里特別講一下RUNNABLE狀態,在這個狀態中線程并不一定在執行程序,只有被JVM調度的線程才能獲得執行的時間片,并且只有這個狀態的線程才能夠獲得時間片,換句話說,被JVM調度并且獲得時間片是只屬于處于RUNNABLE狀態線程的權利。為了便于理解,可以將RUNNABLE分成Runnable和Running兩個狀態(當然,你也可以換成其他的,這里我只是自己好理解),那么上面的線程轉換圖就轉變成了下面這樣(參考《Java并發編程的藝術》中的線程狀態圖):

關于線程狀態轉換的例子,可以通過下面的代碼加深理解

public class Test {

public static void main(String[] args) {

Test test = new Test();

// 1.NEW狀態

Thread thread = new Thread(() -> {

// 3.進行test對象鎖的爭奪,若搶到鎖則繼續執行,否則進入BLOCKED狀態監控該鎖,重新獲得后進入RUNNABLE

synchronized (test) {

try {

// 4.進入TIMED_WAITING狀態,100ms后重新進入RUNNABLE狀態爭奪時間片

Thread.sleep(100);

// 5.重新獲得時間片之后,進入WAITING狀態

test.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

// 6.正常run()方法執行完畢后線程結束,進入TERMINATED

});

// 2.調用start()方法,線程進入RUNNABLE狀態

thread.start();

}

}

注:代碼執行的順序為注釋的序號

2、正確的結束一個線程

在上面的例子中我們看到線程的run方法正常執行完畢之后線程就正常死亡進入TERMINATED狀態了,那么如果我們有中途停止線程的需求,我們應該如何正確的結束一個線程呢?

使用interrupt()方法:在線程內部,其定義了一個變量來標識當前線程是否處于被打斷狀態,調用interrupt()方法則使這個狀態變為true。我們采用這個方法加異常處理的方式來結束一個線程。

public static void main(String[] args) {

Thread thread = new Thread(() -> {

try {

Thread.sleep(1);

} catch (InterruptedException e) {

e.printStackTrace();

// 這里的return是必須的,原因后面說明

return;

}

System.err.println("thread interrupt test...");

});

thread.start();

thread.interrupt();

System.out.println("main thread end...");

}

// 結果圖:異常后面的語句不會打印

這里關于線程中的打斷標識變量(之后以interrupt稱)需要說明的是,在特定的情況下其狀態會被重置。

1、線程內部在catch了異常了之后interrupt的狀態會被重置為false。

2、線程調用了Thread.interrupted()方法之后,interrupt的狀態會被重置為false。如果需要判斷線程是否中斷的話可以使用對象方法isInterrupted(),此方法不會重置。

所以在剛才的代碼中需要加入return來結束線程,否則的話線程還是會繼續往下執行,如下圖

使用isInterrupted()實現:

public static void main(String[] args) throws InterruptedException {

Thread thread = new Thread(() -> {

while (!Thread.currentThread().isInterrupted()) {

int k = 0;

while (k++ < 10) {

System.out.println("do something..." + k);

}

}

System.err.println("thread end...");

});

thread.start();

Thread.sleep(1);

// 主線程流程執行完了,需要停止線程

thread.interrupt();

}

使用標識位來實現:定義一個變量標識線程是否終止,若終止了則退出run方法。跟上面isInterrupted()的實現一樣,不過換成了volatile變量而已。

public class Test {

public static volatile boolean interrupted = false;

public static void main(String[] args) throws InterruptedException {

Thread thread = new Thread(() -> {

while (!interrupted) {

int k = 0;

while (k++ < 10) {

if (interrupted) {

System.err.println("thread invoke end....");

return;

}

System.out.println("do something..." + k);

}

}

System.err.println("thread end...");

});

thread.start();

Thread.sleep(1);

// 主線程流程執行完了,需要停止線程

interrupted = true;

}

}

// 結果圖

stop()方法——不正確的線程中斷方法

在線程提供的方法中還有一個方法可以強制關閉線程——stop()。這個方法可以說是相當的霸道,給人一種“我不管,我就是要你現在立刻死亡(指線程)”的感覺,并且其還會釋放線程所有的鎖資源,這樣可能會導致出現數據不一致從而出現線程不安全的情況,如下面例子。

public class Test {

public static volatile boolean flag = false;

public int state = 0;

public static void main(String[] args) throws InterruptedException {

Test test = new Test();

Thread thread = new Thread(() -> {

synchronized (test) {

try {

test.state = 1;

Thread.sleep(100);

if (flag) {

test.state = 2;

}

System.err.println("thread execute finished...");

} catch (InterruptedException e) {

e.printStackTrace();

}

}

});

thread.start();

Thread.sleep(1);

thread.stop();

flag = true;

System.out.println("state狀態:" + test.state);

}

}

// 在這段代碼中,進入線程時默認將state賦為1,接著過一段時間后如果觸發了特定條件則把state賦為2,但是在特定條件觸發之前,線程就被終止掉了,這個特定條件雖然符合但卻沒辦法執行,從而導致數據的不一致。

// 結果圖

所以,我們應該采用上面兩種正確的方式而不是stop()來中止線程。此外,stop()方法若在線程start()之前執行,那么在線程啟動的時候就會立即死亡。

若有不對之處,望各位不吝指教(反正免費,對吧)。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。

總結

以上是生活随笔為你收集整理的java 切换主线程_Java线程状态及切换、关闭线程的正确姿势分享的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。