Java終止線(xiàn)程實(shí)例和stop()方法源碼閱讀
了解線(xiàn)程
概念
線(xiàn)程 是程序中的執(zhí)行線(xiàn)程。Java 虛擬機(jī)允許應(yīng)用程序并發(fā)地運(yùn)行多個(gè)執(zhí)行線(xiàn)程。
線(xiàn)程特點(diǎn)
擁有狀態(tài),表示線(xiàn)程的狀態(tài),同一時(shí)刻中,JVM中的某個(gè)線(xiàn)程只有一種狀態(tài);
·NEW
尚未啟動(dòng)的線(xiàn)程(程序運(yùn)行開(kāi)始至今一次未啟動(dòng)的線(xiàn)程)
·RUNNABLE
可運(yùn)行的線(xiàn)程,正在JVM中運(yùn)行,但它可能在等待其他資源,如CPU。
·BLOCKED
阻塞的線(xiàn)程,等待某個(gè)鎖允許它繼續(xù)運(yùn)行
·WAITING
無(wú)限等待(再次運(yùn)行依賴(lài)于讓它進(jìn)入該狀態(tài)的線(xiàn)程執(zhí)行某個(gè)特定操作)
·TIMED_WAITING
定時(shí)等待(再次運(yùn)行依賴(lài)于讓它進(jìn)入該狀態(tài)的線(xiàn)程在指定等待時(shí)間內(nèi)某個(gè)特定操作)
·TERMINATED
已退出的線(xiàn)程
擁有優(yōu)先級(jí),決定線(xiàn)程的執(zhí)行順序;
1至10之間的整數(shù),默認(rèn)數(shù)值為5。數(shù)值越高,執(zhí)行的幾率越高,優(yōu)先級(jí)并不能決定線(xiàn)程的執(zhí)行順序。
子線(xiàn)程的優(yōu)先級(jí)默認(rèn)同父線(xiàn)程的一樣。
注意,當(dāng)以下情況發(fā)生時(shí),JVM將停止執(zhí)行所有線(xiàn)程:
Runtime(運(yùn)行時(shí))的exit ()方法被調(diào)用并且該方法的調(diào)用被Security Manager所允許;
所有的“非守護(hù)線(xiàn)程”都已停止運(yùn)行(無(wú)論時(shí)正常停止還是一場(chǎng)停止);
可以被標(biāo)記為守護(hù)程序(Daemon)
守護(hù)線(xiàn)程的子線(xiàn)程仍是守護(hù)線(xiàn)程;
守護(hù)線(xiàn)程也就是“后臺(tái)線(xiàn)程”,一般用來(lái)執(zhí)行后臺(tái)任務(wù),而用戶(hù)線(xiàn)程一般用戶(hù)執(zhí)行用戶(hù)級(jí)任務(wù)。
終止線(xiàn)程的方法
1.使用退出標(biāo)志,使線(xiàn)程正常退出,也就是當(dāng)run方法完成后線(xiàn)程終止。
當(dāng)run方法執(zhí)行完后,線(xiàn)程就會(huì)退出。但有時(shí)run方法是永遠(yuǎn)不會(huì)結(jié)束的。如在服務(wù)端程序中使用線(xiàn)程進(jìn)行監(jiān)聽(tīng)客戶(hù)端請(qǐng)求,或是其他的需要循環(huán)處理的任務(wù)。在這種情況下,一般是將這些任務(wù)放在一個(gè)循環(huán)中,如while循環(huán)。如果想讓循環(huán)永遠(yuǎn)運(yùn)行下去,可以使用while(true){……}來(lái)處理。但要想使while循環(huán)在某一特定條件下退出,最直接的方法就是設(shè)一個(gè)boolean類(lèi)型的標(biāo)志,并通過(guò)設(shè)置這個(gè)標(biāo)志為true或false來(lái)控制while循環(huán)是否退出。下面給出了一個(gè)利用退出標(biāo)志終止線(xiàn)程的例子。
FlagExitThread.java
package com.rainmonth; /** * Created by RandyZhang on 2017/3/23. */ public class FlagExitThread extends Thread { public volatile Boolean isExit = false; public FlagExitThread(String name) { super(name); } @Override public void run() { while (!isExit) { System.out.println("I'm running"); } } }
DemoClient.java
package com.rainmonth; /** * Created by RandyZhang on 2017/3/23. */ public class DemoClient { public static void main(String[] args) { System.out.println("優(yōu)雅的終止線(xiàn)程實(shí)例"); exitByFlag(); // exitByInterrupt(); } private static void exitByFlag() { FlagExitThread flagExitThread = new FlagExitThread(FlagExitThread.class.getSimpleName()); flagExitThread.start(); try { Thread.sleep(1000); flagExitThread.isExit = true; flagExitThread.join(); System.out.println("線(xiàn)程退出"); } catch (InterruptedException e) { e.printStackTrace(); } } private static void exitByInterrupt() { FlagExitThread flagExitThread = new FlagExitThread(FlagExitThread.class.getSimpleName()); System.out.println("flagExitThread running..."); flagExitThread.start(); try { Thread.sleep(1500); System.out.println("flagExitThread interrupted..."); flagExitThread.interrupt(); Thread.sleep(1500); System.out.println("stop application..."); } catch (InterruptedException e) { e.printStackTrace(); } } }
輸出結(jié)果:
打印了一大堆I'm running之后線(xiàn)程退出。
2.使用stop方法強(qiáng)行終止線(xiàn)程(這個(gè)方法不推薦使用,因?yàn)閟top和suspend、resume一樣,也可能發(fā)生不可預(yù)料的結(jié)果)。
顯示調(diào)用stop()方法。源碼中關(guān)于stop() 的描述如下:
/* * This method is inherently unsafe. Stopping a thread with * Thread.stop causes it to unlock all of the monitors that it * has locked (as a natural consequence of the unchecked * <code>ThreadDeath</code> exception propagating up the stack). If * any of the objects previously protected by these monitors were in * an inconsistent state, the damaged objects become visible to * other threads, potentially resulting in arbitrary behavior. Many * uses of <code>stop</code> should be replaced by code that simply * modifies some variable to indicate that the target thread should * stop running. The target thread should check this variable * regularly, and return from its run method in an orderly fashion * if the variable indicates that it is to stop running. If the * target thread waits for long periods (on a condition variable, * for example), the <code>interrupt</code> method should be used to * interrupt the wait. */
大意就是說(shuō),該方法的不安全性時(shí)固有的。調(diào)用stop()終止一個(gè)線(xiàn)程會(huì)釋放它已經(jīng)鎖定的所有監(jiān)視器(這將導(dǎo)致沿堆棧向上傳播為檢查的ThreadDeath異常被拋出),若此時(shí)之前受這些被釋放的監(jiān)視器保護(hù)的對(duì)象存在不一致性,并且這些對(duì)象對(duì)其他線(xiàn)程可見(jiàn),這就會(huì)導(dǎo)致一些意想不到的后果。stop操作應(yīng)該有哪些僅僅只需要修改某些代碼就可以指示目標(biāo)線(xiàn)程應(yīng)該停止運(yùn)行的代碼來(lái)取代(方法一就是這種方式)。如果目標(biāo)線(xiàn)程由于等待某一條件(如某個(gè)條件變量)等待很長(zhǎng)時(shí)間,我們應(yīng)該使用interrupt方法來(lái)中斷該等待(方法三就是這種方式)。
3.使用interrupt方法中斷線(xiàn)程。
interrupt字面上是終止的意思,但不要試圖通過(guò)調(diào)用interrupt來(lái)終止線(xiàn)程,因?yàn)橛袝r(shí)即使你調(diào)用了該方法,線(xiàn)程仍然會(huì)繼續(xù)執(zhí)行,可以注釋掉上面的exitByFlag(),開(kāi)啟exitByInterrupt() 方法,發(fā)現(xiàn)及時(shí)調(diào)用了interrupt()方法,仍在一直輸出I'm running…(不同系統(tǒng)及CPU結(jié)果可能有所不同),可見(jiàn)采用interrupt方式也是不安全的。
總結(jié)
根據(jù)以上的分析,最值得推薦的方式是第一種,我們可以用共享變量(shared variable)的方式來(lái)設(shè)置標(biāo)志,并發(fā)出信號(hào),通知線(xiàn)程必須終止。當(dāng)然對(duì)這個(gè)共享變量的操作我們必須保證是同步的。
以上就是本文關(guān)于Java終止線(xiàn)程實(shí)例和stop()方法源碼閱讀的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專(zhuān)題,如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!
- Java如何使用interrupt()終止線(xiàn)程
- Java實(shí)現(xiàn)終止線(xiàn)程池中正在運(yùn)行的定時(shí)任務(wù)
- Java語(yǔ)言多線(xiàn)程終止中的守護(hù)線(xiàn)程實(shí)例
- interrupt()和線(xiàn)程終止方式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
- Java中終止線(xiàn)程的方法詳解
- Java 并發(fā)編程之線(xiàn)程掛起、恢復(fù)與終止
- Java中終止線(xiàn)程的三種方法
- 詳解Java多線(xiàn)程編程中線(xiàn)程的啟動(dòng)、中斷或終止操作
- 詳解Java編程中線(xiàn)程的掛起、恢復(fù)和終止的方法
- Java并發(fā)編程示例(六):等待線(xiàn)程執(zhí)行終止
- Java 正確終止線(xiàn)程的方法
相關(guān)文章
Java getParameter()獲取數(shù)據(jù)為空的問(wèn)題
這篇文章主要介紹了Java getParameter()獲取數(shù)據(jù)為空的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03Java調(diào)用ChatGPT(基于SpringBoot和Vue)實(shí)現(xiàn)可連續(xù)對(duì)話(huà)和流式輸出的ChatGPT API
這篇文章主要介紹了Java調(diào)用ChatGPT(基于SpringBoot和Vue),實(shí)現(xiàn)可連續(xù)對(duì)話(huà)和流式輸出的ChatGPT API(可自定義實(shí)現(xiàn)AI助手),文中代碼示例介紹的非常詳細(xì),感興趣的朋友可以參考下2023-04-04Spring Boot實(shí)現(xiàn)簡(jiǎn)單的定時(shí)任務(wù)
這篇文章主要給大家介紹了關(guān)于利用Spring Boot實(shí)現(xiàn)簡(jiǎn)單的定時(shí)任務(wù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07通過(guò)FeignClient調(diào)用微服務(wù)提供的分頁(yè)對(duì)象IPage報(bào)錯(cuò)的解決
這篇文章主要介紹了通過(guò)FeignClient調(diào)用微服務(wù)提供的分頁(yè)對(duì)象IPage報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03eclipse/intellij idea 查看java源碼和注釋方法
下面小編就為大家?guī)?lái)一篇eclipse/intellij idea 查看java源碼和注釋方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05MyBatis一級(jí)與二級(jí)緩存相關(guān)配置
mybatis-plus是一個(gè)Mybatis的增強(qiáng)工具,在Mybatis的基礎(chǔ)上只做增強(qiáng)不做改變,為簡(jiǎn)化開(kāi)發(fā)、提高效率而生,這篇文章帶你了解Mybatis的一級(jí)和二級(jí)緩存2023-01-01Java數(shù)據(jù)結(jié)構(gòu)之簡(jiǎn)單的連接點(diǎn)(link)實(shí)現(xiàn)方法示例
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)之簡(jiǎn)單的連接點(diǎn)(link)實(shí)現(xiàn)方法,涉及java指針指向節(jié)點(diǎn)的相關(guān)使用技巧,需要的朋友可以參考下2017-10-10