JAVA多線程(三)

線程Sleep方法介紹

sleep是一個(gè)靜態(tài)方法,有兩個(gè)重載參數(shù),一個(gè)需要轉(zhuǎn)入毫秒數(shù),另一個(gè)需要傳入毫秒和納秒數(shù)。

public static void sleep(long millis) throws InterruptedException;
public static void sleep(long millis,int nanos) throws InterruptedException;

sleep方法會(huì)使當(dāng)前線程進(jìn)入指定方法的休眠,暫停執(zhí)行,其中有一個(gè)很重要的屬性,那就是不會(huì)放棄monitor鎖 ,每個(gè)線程的休眠互不影響。

使用TimeUnit代替Thread.sleep
TimeUnit.Hour.sleep(long millis)
TimeUnit.SECONDS.sleep(long millis)
TimeUnit.MINUTES.sleep(long millis)

顯然TimeUnit比sleep清楚很多。

yield方法

yield方法屬于一種啟發(fā)式的方法,豈會(huì)提醒調(diào)度器我愿意放棄當(dāng)前CPU資源,如果CPU資源不緊張,則會(huì)忽略這種題型。
調(diào)用yield方法會(huì)使當(dāng)前線程RUNNING狀態(tài)切換到RUNNABLE狀態(tài),

yield和sleep方法的區(qū)別

  • sleep會(huì)導(dǎo)致當(dāng)前線程暫停到指定的時(shí)間,沒有CPU時(shí)間片的消耗。
  • yield只是對(duì)CPU調(diào)度器的一個(gè)提示,如果CPU忽略掉這個(gè)提示,他會(huì)導(dǎo)致線程上下文切換。
  • 線程sleep會(huì)導(dǎo)致短暫block,會(huì)再給定時(shí)間內(nèi)釋放CPU資源。
  • yield會(huì)使RUNNING 狀態(tài)進(jìn)入RUNNABLE狀態(tài)(如果CPU沒有忽略掉這個(gè)提示的話)
  • sleep幾乎百分之百的完成了給定時(shí)間的睡眠,而yield則不一定能擔(dān)保
  • 一個(gè)線程sleep另個(gè)線程interrupt會(huì)捕獲中斷信號(hào),而yield不能。
線程的優(yōu)先級(jí)
public final void setPriority(int priority) 為線程設(shè)定優(yōu)先級(jí)
public final int getPriority()獲取線程的優(yōu)先級(jí)

如果指定的線程優(yōu)先級(jí)大于ThreadGroup的優(yōu)先級(jí),那么指定線程的優(yōu)先級(jí)則失效,取而代之的是ThreadGroup的優(yōu)先級(jí)。

獲取線程的ID
public long getId();//獲取線程的ID

線程的Id在整個(gè)JVM是惟一的

獲取當(dāng)前線程

public static Thread currentThread();用于返回當(dāng)前執(zhí)行線程的引用,

設(shè)置線程上下文類加載器

public ClassLoader getContextClassLoader();獲取線程的上下文加載器,簡(jiǎn)單來說這個(gè)線程是由那個(gè)類加載的,如果沒有修改,那么則與父線程保持一致.
public void setContextClassLoader(ClassLoader cl)設(shè)置該線程的類加載,這個(gè)方法可以打破父委托機(jī)制。

線程的interrupt
public void interrupt();
public static boolean interruped();
public boolean isInterrupted();

1.interrupt
當(dāng)前Thread調(diào)用以下方法會(huì)進(jìn)入阻塞狀態(tài),而調(diào)用interrupt方法會(huì)打斷阻塞,

object的wait方法
Thread的Sleep方法
Thread的Join方法
Selector的wakeup方法

調(diào)用上述方法 都會(huì)使得當(dāng)前線程進(jìn)入阻塞狀態(tài),若另外一個(gè)線程調(diào)用被阻塞線程的interrupt方法,則會(huì)打斷這種阻塞,打斷一個(gè)線程的阻塞,并不意味著當(dāng)前線程的生命周期結(jié)束,僅僅是打斷了當(dāng)前的阻塞狀態(tài)。
一個(gè)線程在阻塞的情況下被打斷,則會(huì)跑出interruptedException的異常,

  Thread thread = new Thread(){
    try{
         TimeUnit.MINUTES.Sleep(2);
   }catch(interruptedException e){
        System.out.println("i 'am be interrupted");
   }
   }
    
thread.start();
TimeUnit.MIllISECONDS.Sleep(2);
thread.interrupt();

上述線程 啟動(dòng)的時(shí)候 企圖休眠2分鐘 但是在2毫秒之后,被主線程調(diào)用interrupt打斷了。在線程內(nèi)部存在這命名為interrupt flag 的標(biāo)識(shí),如果一個(gè)線程被interrupt,那么它的flag將被設(shè)置。如果一個(gè)線程在調(diào)用可中斷方法時(shí) 被阻塞,調(diào)用Interrupt 被打斷,那么他的flag將被擦除。

2.isInterrupted
isInterrupted是Thread成員的一個(gè)方法,它判斷當(dāng)前線程是否被打斷,

3.interrupted
interrupted 是一個(gè)靜態(tài)方法,調(diào)用該方法,會(huì)直接擦除掉線程的interrupt標(biāo)識(shí),如果當(dāng)前線程被打斷了,那么第一次調(diào)用interrupt返回true,并且立即擦除了interupt標(biāo)識(shí),第二次以后的調(diào)用永遠(yuǎn)都返回false,

   public boolean isInterrupted() {
        return isInterrupted(false);
    }

 public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

其實(shí)不難發(fā)現(xiàn),isInterrupted和interrupted 會(huì)調(diào)用同一個(gè)方法,區(qū)別在于是否擦除interrupt標(biāo)識(shí),

線程join

Thread的join方法是一個(gè)非常重要的方法,與sleep一樣,它也是一個(gè)可中斷的方法。

public final void join() throws InteruptedException
public final synchronized void join(long mills,int nanos);
public final synchronized void join (long mills) throws InteruptedException;

線程join的基本用法
join線程A,線程B會(huì)進(jìn)入等待,知道線程A結(jié)束聲明周期,或者到達(dá)給定的時(shí)間,那么再次期間B線程是處于BlOCKED的,而不是線程A.

線程的Join方法會(huì)使當(dāng)前永遠(yuǎn)等待下去,知道期間被另外的線程中斷,或者線程join的線程執(zhí)行之后,當(dāng)然你也可以使用Join的重載方法,指定毫秒數(shù),在指定的時(shí)間到達(dá)之后,當(dāng)前線程也會(huì)阻塞。

如何關(guān)閉一個(gè)線程

1.正常關(guān)閉
線程正常結(jié)束生命周期,完成了自己的使命之后,就會(huì)正常的退出。
2.捕獲中斷信號(hào)線程關(guān)閉

Thread thread = new Thread(){
  run(){
  System.out.println("i will start work");
 while(!isInterupted()){
    //working
}
}
}
thread.start();
TimeUnit.MINUTES.Sleep(1);
thread.interrupt();

刪除代碼是通過檢查線程Interrupt的標(biāo)識(shí)來決定是否退出的,如果在線程中執(zhí)行某個(gè)可中斷的方法,則可以通過捕獲中斷信號(hào)的方式來退出。
3.使用volatile開關(guān)
由于線程的interupt標(biāo)識(shí)很有可能被擦除,或者邏輯單元中不會(huì)調(diào)用任何可中斷的方法,所以使用volatile修飾開關(guān)flag關(guān)閉線程也是一種方法。

static class MyTask extends Thread{
  private volatile boolean closed = false;
  void run(){
    while(!false && !isInterrupted()){
          //working
   }
  }
}
進(jìn)程假死

所謂假死就是進(jìn)程雖然存在,但是沒有日志輸出,程序不進(jìn)行任何的工作,看起來就想死了一樣,但是事實(shí)上 他并沒有死,絕大部分的原因是因?yàn)槟硞€(gè)線程阻塞了,或者線程出現(xiàn)了死鎖的情況??山柚鷍ava jdk 的bin目錄下的java visual等工具。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容