倫敦政治經(jīng)濟學(xué)院(英國)校訓(xùn):“了解萬物發(fā)生之緣由?!?/em>
在實際工作中,當(dāng)看到代碼中有直接new使用線程的話,這是需要警惕的,你手動創(chuàng)建了線程,自然要管理線程的生命周期,這其中必然包含著線程的結(jié)束。這是一個容易被忽略的小點,也是面試中高頻點,更是實際工作中推薦使用線程池的方式管理線程的緣由。
線程終止有很多方式,這里會介紹工作中推薦使用的終止方式和廢棄的方式,以及廢棄的原因,了解了這些,才能更好地管理線程。
一 推薦方式
常用方式主要有設(shè)置退出標(biāo)識和設(shè)置中斷標(biāo)識,有時線程在sleep/join等阻塞的情況下無法根據(jù)退出標(biāo)識進行終止的,這時就需要利用線程的中斷機制來優(yōu)雅地終止線程。具體看下演示demo:
/**
* @author 阿倫故事
* @Description:
* 描述線程安全終止的方式
* 1 設(shè)置exit標(biāo)識
* 2 設(shè)置中斷標(biāo)識
* */
@Slf4j
public class ThreadStop {
//聲明內(nèi)存可見性全局變量
private volatile boolean flag = false;
public static void main(String[] args) throws Exception{
ThreadStop threadStop = new ThreadStop();
//設(shè)置exit標(biāo)識
//threadStop.terminByExit();
//設(shè)置中斷標(biāo)識
threadStop.terminByInter();
}
/**
* way1 :
* 設(shè)置exit標(biāo)識
* */
public void terminByExit() throws InterruptedException {
ThreadExit threadExit = new ThreadExit();
log.info("--開啟子線程--");
threadExit.start();
Thread.currentThread().sleep(2000);
flag = true;
threadExit.join();
log.info("--stop the world--");
}
public class ThreadExit extends Thread{
@Override
public void run(){
while(!flag);
log.info("--子線程執(zhí)行完畢--");
}
}
/**
* way2 :
* 設(shè)置中斷標(biāo)識
* */
public void terminByInter() throws InterruptedException {
ThreadInter threadInter = new ThreadInter();
log.info("--開啟子線程--");
threadInter.start();
Thread.currentThread().sleep(2000);
flag = true;
Thread.currentThread().sleep(2000);
//此時子線程并不會終止,只能通過中斷終止
threadInter.interrupt();
log.info("--stop the world--");
}
public class ThreadInter extends Thread{
@Override
public void run(){
while(!flag){
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
flag = true;
}
}
log.info("--子線程執(zhí)行完畢--");
}
}
}
二 廢棄方式
1 Thread.stop
此方法已經(jīng)廢棄,主要是因為不安全,它是強行終止線程,非常暴力,可能會帶來不可預(yù)知的后果;另調(diào)用stop之后,創(chuàng)建該子線程的線程就會拋出ThreadDeath的error,具體看下源碼:
@Deprecated
public final void stop() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
checkAccess();
if (this != Thread.currentThread()) {
security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
}
}
// A zero status value corresponds to "NEW", it can't change to
// not-NEW because we hold the lock.
if (threadStatus != 0) {
resume(); // Wake up thread if it was suspended; no-op otherwise
}
// The VM can handle all thread states
stop0(new ThreadDeath());
}
2 suspend & resume
這是必須成對使用的方法,要不很容易造成死鎖,在底層都是依賴native方法實現(xiàn)線程的暫停和恢復(fù)。如果該線程沒有被suspend暫停,則無法通過resume恢復(fù)的。
舉例一個死鎖的場景:線程A持有一把鎖,然后A被suspend(不會釋放鎖),線程A等待被resume;線程B的執(zhí)行流程是先獲取這把鎖,再resume線程A,這樣就會造成死鎖。
3 Runtime.runFinalizersOnExit
此方法是線程不安全的,它是依賴Shutdown設(shè)置終結(jié)器(Finalizer),想深入了解的,具體看下源碼:
@Deprecated
public static void runFinalizersOnExit(boolean var0) {
SecurityManager var1 = System.getSecurityManager();
if (var1 != null) {
try {
var1.checkExit(0);
} catch (SecurityException var3) {
throw new SecurityException("runFinalizersOnExit");
}
}
Shutdown.setRunFinalizersOnExit(var0);
}
特此聲明:
分享文章有完整的知識架構(gòu)圖,將從以下幾個方面系統(tǒng)展開:
1 基礎(chǔ)(Linux/Spring boot/并發(fā))
2 性能調(diào)優(yōu)(jvm/tomcat/mysql)
3 高并發(fā)分布式
4 微服務(wù)體系
如果您覺得文章不錯,請關(guān)注阿倫故事,您的支持是我堅持的莫大動力,在此受小弟一拜!
每篇福利:
