一、前言
之前本人寫了一篇防止Controller中的線程被重複調用的文章,大概代碼如下:
public final static HashMap<String,Thread> threadMap = new HashMap<>();Thread nowThread = threadMap.get("nowThread");if(nowThread != null && nowThread.isAlive()){ LOG.info("當前存在正在執行的線程,本次線程不執行,請稍後再試"); return;}
else{ threadMap.put("nowThread",Thread.currentThread());}.
threadMap.put("nowThread",null);後來,由於擔心這個線程會卡死,導致後續正常調用該線程的操作無法進行,因此加了個手動停止線程運行的方法(interrupt):
if(type == 3){ try{ Thread nowThread = threadMap.get("nowThread"); nowThread.interrupt(); threadMap.put("nowThread",null); String backMsg = "線程interrupt成功!"; LOG.info(backMsg); return; }catch(Exception e){ threadMap.put("nowThread",null); String backMsg = "線程interrupt失敗,只將map置空!"; LOG.error(backMsg,e); return; }}然而,僅僅這樣並不能停止線程運行。
二、停止線程運行的方法
使用標誌位停止線程,還行,但是遇到sleep時的線程就無法停止了,必須等線程sleep結束、運行到判斷標誌位步驟時才行。
使用stop()停止線程,不安全,已不推薦使用。會立即停止線程運行,會使一些清理性的工作的得不到完成,如文件,資料庫等的關閉;會立即釋放該線程所持有的所有的鎖,導致數據得不到同步,出現數據不一致的問題。
使用interrupt()中斷線程,需要配合代碼邏輯實現停止線程。
需要注意,調用 interrupt() 方法僅僅是在當前線程中打一個停止的標記,並不是真的停止線程;如果直接將線程停止,就會和stop一樣出現問題。
因此還需要配合代碼邏輯實現。
三、正確使用interrupt停止線程運行
先看下例子:
public static void main(String[] args) throws InterruptedException{ Thread t1 = new Thread(){ @Override public void run(){ while(true){ if(this.currentThread().isInterrupted()){ System.out.println("線程被打斷,停止運行"); break; }else{ System.out.println("線程在運行"); try{ Thread.sleep(1000L); }catch(InterruptedException e){ System.out.println("線程睡眠時被打斷,停止運行"); break; } } } } }; t1.start(); Thread.sleep(5000L); t1.interrupt(); System.out.println("主線程打斷t1完成");}上方的代碼中,先啟動一個線程,然後主線程在5秒後打斷它,它有兩種停止情況:
執行if判斷時,發現標誌位為true,因此執行break,之後停止運行。
線程還在sleep,此時發現被打斷,會拋出InterruptedException,然後被catch到,執行break,之後停止運行。
結合實際代碼,如果線程中不需要sleep,則判斷isInterrupted()即可;
如果線程中存在sleep,則catch中使用break、return之類的停止線程即可;
當然也可以兩種都寫。
本人的代碼中有sleep,因此只在catch中加了break,沒有判斷標誌位。
四、總結
使用interrupt停止線程比標誌位停止線程的好處在於,它不僅能通過標誌判斷是否要停止線程,而且當線程處於sleep狀態時,使用interrupt就可以停止線程,而標誌位不行。
使用interrupt停止線程比stop停止線程的好處在於,stop不安全,會產生難以預料的後果,而interrupt不會。
停止線程時,不僅要直接調用interrupt(),還要寫好相應的代碼邏輯,一種邏輯與標誌位停止線程類似,另一種邏輯要注意在try中寫Thread.sleep(當你的線程需要sleep時),在catch中寫break、return之類的方法。
PS:之前寫sleep時,都是這麼寫的:
try{ Thread.sleep(5000L);}catch(Exception e){}現在終於知道應該怎麼寫了