真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

java中線程狀態(tài)與方法的示例分析

這篇文章將為大家詳細(xì)講解有關(guān)java中線程狀態(tài)與方法的示例分析,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。

創(chuàng)新互聯(lián)于2013年成立,先為徐州等服務(wù)建站,徐州等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為徐州企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。

一、線程的狀態(tài)

正式學(xué)習(xí)Thread類中的具體方法之前,我們先來了解一下線程有哪些狀態(tài),這個(gè)將會(huì)有助于后面對(duì)Thread類中的方法的理解。

線程從創(chuàng)建到最終的消亡,要經(jīng)歷若干個(gè)狀態(tài)。一般來說,線程包括以下這幾個(gè)狀態(tài):創(chuàng)建(new)、就緒(runnable)、運(yùn)行(running)、阻塞(blocked)、time waiting、waiting、消亡(dead)。

當(dāng)需要新起一個(gè)線程來執(zhí)行某個(gè)子任務(wù)時(shí),就創(chuàng)建了一個(gè)線程。但是線程創(chuàng)建之后,不會(huì)立即進(jìn)入就緒狀態(tài),因?yàn)榫€程的運(yùn)行需要一些條件(比如內(nèi)存資源,譬如程序計(jì)數(shù)器、Java棧、本地方法棧都是線程私有的,所以需要為線程分配一定的內(nèi)存空間),只有線程運(yùn)行需要的所有條件滿足了,才進(jìn)入就緒狀態(tài)。

當(dāng)線程進(jìn)入就緒狀態(tài)后,不代表立刻就能獲取CPU執(zhí)行時(shí)間,也許此時(shí)CPU正在執(zhí)行其他的事情,因此它要等待。當(dāng)?shù)玫紺PU執(zhí)行時(shí)間之后,線程便真正進(jìn)入運(yùn)行狀態(tài)。

線程在運(yùn)行狀態(tài)過程中,可能有多個(gè)原因?qū)е庐?dāng)前線程不繼續(xù)運(yùn)行下去,比如用戶主動(dòng)讓線程睡眠(睡眠一定的時(shí)間之后再重新執(zhí)行)、用戶主動(dòng)讓線程等待,或者被同步塊給阻塞,此時(shí)就對(duì)應(yīng)著多個(gè)狀態(tài):time waiting(睡眠或等待一定的事件)、waiting(等待被喚醒)、blocked(阻塞)。

當(dāng)由于突然中斷或者子任務(wù)執(zhí)行完畢,線程就會(huì)被消亡。

下面這副圖描述了線程從創(chuàng)建到消亡之間的狀態(tài):

java中線程狀態(tài)與方法的示例分析

在有些教程上將blocked、waiting、time waiting統(tǒng)稱為阻塞狀態(tài),這個(gè)也是可以的,只不過這里我想將線程的狀態(tài)和Java中的方法調(diào)用聯(lián)系起來,所以將waiting和time waiting兩個(gè)狀態(tài)分離出來。

二、Thread類中的方法

通過查看java.lang.Thread類的源碼可知:

java中線程狀態(tài)與方法的示例分析

Thread類實(shí)現(xiàn)了Runnable接口,在Thread類中,有一些比較關(guān)鍵的屬性,比如name是表示Thread的名字,可以通過Thread類的構(gòu)造器中的參數(shù)來指定線程名字,priority表示線程的優(yōu)先級(jí)(最大值為10,最小值為1,默認(rèn)值為5),daemon表示線程是否是守護(hù)線程,target表示要執(zhí)行的任務(wù)。

下面是Thread類中常用的方法:

以下是關(guān)系到線程運(yùn)行狀態(tài)的幾個(gè)方法:

1)start方法


start()用來啟動(dòng)一個(gè)線程,當(dāng)調(diào)用start方法后,系統(tǒng)才會(huì)開啟一個(gè)新的線程來執(zhí)行用戶定義的子任務(wù),在這個(gè)過程中,會(huì)為相應(yīng)的線程分配需要的資源。

2)run方法


run()方法是不需要用戶來調(diào)用的,當(dāng)通過start方法啟動(dòng)一個(gè)線程之后,當(dāng)線程獲得了CPU執(zhí)行時(shí)間,便進(jìn)入run方法體去執(zhí)行具體的任務(wù)。注意,繼承Thread類必須重寫run方法,在run方法中定義具體要執(zhí)行的任務(wù)。

3)sleep方法


sleep方法有兩個(gè)重載版本:

sleep(long millis)     //參數(shù)為毫秒
sleep(long millis,int nanoseconds)    //第一參數(shù)為毫秒,第二個(gè)參數(shù)為納秒

sleep相當(dāng)于讓線程睡眠,交出CPU,讓CPU去執(zhí)行其他的任務(wù)。

如果需要讓當(dāng)前正在執(zhí)行的線程暫停一段時(shí)間,并進(jìn)入阻塞狀態(tài),則可以通過調(diào)用Thread類的靜態(tài)sleep()方法來實(shí)現(xiàn)。

當(dāng)當(dāng)前線程調(diào)用sleep()方法進(jìn)入阻塞狀態(tài)后,在其睡眠時(shí)間內(nèi),該線程不會(huì)獲得執(zhí)行機(jī)會(huì),即使系統(tǒng)中沒有其他可執(zhí)行線程,處于sleep()中的線程也不會(huì)執(zhí)行,因此sleep()方法常用來暫停程序的執(zhí)行

但是有一點(diǎn)要非常注意,sleep方法不會(huì)釋放鎖,也就是說如果當(dāng)前線程持有對(duì)某個(gè)對(duì)象的鎖,則即使調(diào)用sleep方法,其他線程也無法訪問這個(gè)對(duì)象。看下面這個(gè)例子就清楚了:

public class Test {
     
    private int i = 10;
    private Object object = new Object();
     
    public static void main(String[] args) throws IOException  {
        Test test = new Test();
        MyThread thread1 = test.new MyThread();
        MyThread thread2 = test.new MyThread();
        thread1.start();
        thread2.start();
    } 
     
     
    class MyThread extends Thread{
        @Override
        public void run() {
            synchronized (object) {
                i++;
                System.out.println("i:"+i);
                try {
                    System.out.println("線程"+Thread.currentThread().getName()+"進(jìn)入睡眠狀態(tài)");
                    Thread.currentThread().sleep(10000);
                } catch (InterruptedException e) {
                    // TODO: handle exception
                }
                System.out.println("線程"+Thread.currentThread().getName()+"睡眠結(jié)束");
                i++;
                System.out.println("i:"+i);
            }
        }
    }
}

輸出結(jié)果:

java中線程狀態(tài)與方法的示例分析

從上面輸出結(jié)果可以看出,當(dāng)Thread-0進(jìn)入睡眠狀態(tài)之后,Thread-1并沒有去執(zhí)行具體的任務(wù)。只有當(dāng)Thread-0執(zhí)行完之后,此時(shí)Thread-0釋放了對(duì)象鎖,Thread-1才開始執(zhí)行。

注意,如果調(diào)用了sleep方法,必須捕獲InterruptedException異常或者將該異常向上層拋出。當(dāng)線程睡眠時(shí)間滿后,不一定會(huì)立即得到執(zhí)行,因?yàn)榇藭r(shí)可能CPU正在執(zhí)行其他的任務(wù)。所以說調(diào)用sleep方法相當(dāng)于讓線程進(jìn)入阻塞狀態(tài)。

4)yield方法


yield()方法和sleep()方法有點(diǎn)相似,它也是Thread類提供的一個(gè)靜態(tài)方法,它也可以讓當(dāng)前正在執(zhí)行的線程暫停,但它不會(huì)阻塞該線程,它只是將該線程轉(zhuǎn)入到就緒狀態(tài)。即讓當(dāng)前線程暫停一下,讓系統(tǒng)的線程調(diào)度器重新調(diào)度一次,完全可能的情況是:當(dāng)某個(gè)線程調(diào)用了yield()方法暫停之后,線程調(diào)度器又將其調(diào)度出來重新執(zhí)行。

調(diào)用yield方法會(huì)讓當(dāng)前線程交出CPU權(quán)限,讓CPU去執(zhí)行其他的線程。它跟sleep方法類似,同樣不會(huì)釋放鎖。但是yield不能控制具體的交出CPU的時(shí)間,另外,當(dāng)某個(gè)線程調(diào)用了yield()方法之后,只有優(yōu)先級(jí)與當(dāng)前線程相同或者比當(dāng)前線程更高的處于就緒狀態(tài)的線程才會(huì)獲得執(zhí)行機(jī)會(huì)。

注意,調(diào)用yield方法并不會(huì)讓線程進(jìn)入阻塞狀態(tài),而是讓線程重回就緒狀態(tài),它只需要等待重新獲取CPU執(zhí)行時(shí)間,這一點(diǎn)是和sleep方法不一樣的。

5)join方法


join方法有三個(gè)重載版本:

join()
join(long millis)     //參數(shù)為毫秒
join(long millis,int nanoseconds)    //第一參數(shù)為毫秒,第二個(gè)參數(shù)為納秒

假如在main線程中,調(diào)用thread.join方法,則main方法會(huì)等待thread線程執(zhí)行完畢或者等待一定的時(shí)間。如果調(diào)用的是無參join方法,則等待thread執(zhí)行完畢,如果調(diào)用的是指定了時(shí)間參數(shù)的join方法,則等待一定的事件。

看下面一個(gè)例子:

public class Test {
     
    public static void main(String[] args) throws IOException  {
        System.out.println("進(jìn)入線程"+Thread.currentThread().getName());
        Test test = new Test();
        MyThread thread1 = test.new MyThread();
        thread1.start();
        try {
            System.out.println("線程"+Thread.currentThread().getName()+"等待");
            thread1.join();
            System.out.println("線程"+Thread.currentThread().getName()+"繼續(xù)執(zhí)行");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    } 
     
    class MyThread extends Thread{
        @Override
        public void run() {
            System.out.println("進(jìn)入線程"+Thread.currentThread().getName());
            try {
                Thread.currentThread().sleep(5000);
            } catch (InterruptedException e) {
                // TODO: handle exception
            }
            System.out.println("線程"+Thread.currentThread().getName()+"執(zhí)行完畢");
        }
    }
}

輸出結(jié)果:

java中線程狀態(tài)與方法的示例分析

可以看出,當(dāng)調(diào)用thread1.join()方法后,main線程會(huì)進(jìn)入等待,然后等待thread1執(zhí)行完之后再繼續(xù)執(zhí)行。

實(shí)際上調(diào)用join方法是調(diào)用了Object的wait方法,這個(gè)可以通過查看源碼得知:

java中線程狀態(tài)與方法的示例分析

wait方法會(huì)讓線程進(jìn)入阻塞狀態(tài),并且會(huì)釋放線程占有的鎖,并交出CPU執(zhí)行權(quán)限。

由于wait方法會(huì)讓線程釋放對(duì)象鎖,所以join方法同樣會(huì)讓線程釋放對(duì)一個(gè)對(duì)象持有的鎖。具體的wait方法使用在后面文章中給出。

6)interrupt方法


interrupt,顧名思義,即中斷的意思。單獨(dú)調(diào)用interrupt方法可以使得處于阻塞狀態(tài)的線程拋出一個(gè)異常,也就說,它可以用來中斷一個(gè)正處于阻塞狀態(tài)的線程;另外,通過interrupt方法和isInterrupted()方法來停止正在運(yùn)行的線程。

下面看一個(gè)例子:

public class Test {
   
  public static void main(String[] args) throws IOException  {
      Test test = new Test();
      MyThread thread = test.new MyThread();
      thread.start();
      try {
          Thread.currentThread().sleep(2000);
      } catch (InterruptedException e) {
           
      }
      thread.interrupt();
  } 
   
  class MyThread extends Thread{
      @Override
      public void run() {
          try {
              System.out.println("進(jìn)入睡眠狀態(tài)");
              Thread.currentThread().sleep(10000);
              System.out.println("睡眠完畢");
          } catch (InterruptedException e) {
              System.out.println("得到中斷異常");
          }
          System.out.println("run方法執(zhí)行完畢");
      }
  }
}

輸出結(jié)果:

java中線程狀態(tài)與方法的示例分析

從這里可以看出,通過interrupt方法可以中斷處于阻塞狀態(tài)的線程。那么能不能中斷處于非阻塞狀態(tài)的線程呢?看下面這個(gè)例子:

public class Test {
    
   public static void main(String[] args) throws IOException  {
       Test test = new Test();
       MyThread thread = test.new MyThread();
       thread.start();
       try {
           Thread.currentThread().sleep(2000);
       } catch (InterruptedException e) {
            
       }
       thread.interrupt();
   } 
    
   class MyThread extends Thread{
       @Override
       public void run() {
           int i = 0;
           while(i

運(yùn)行該程序會(huì)發(fā)現(xiàn),while循環(huán)會(huì)一直運(yùn)行直到變量i的值超出Integer.MAX_VALUE。所以說直接調(diào)用interrupt方法不能中斷正在運(yùn)行中的線程。

但是如果配合isInterrupted()能夠中斷正在運(yùn)行的線程,因?yàn)檎{(diào)用interrupt方法相當(dāng)于將中斷標(biāo)志位置為true,那么可以通過調(diào)用isInterrupted()判斷中斷標(biāo)志是否被置位來中斷線程的執(zhí)行。比如下面這段代碼:

public class Test {
   
  public static void main(String[] args) throws IOException  {
      Test test = new Test();
      MyThread thread = test.new MyThread();
      thread.start();
      try {
          Thread.currentThread().sleep(2000);
      } catch (InterruptedException e) {
           
      }
      thread.interrupt();
  } 
   
  class MyThread extends Thread{
      @Override
      public void run() {
          int i = 0;
          while(!isInterrupted() && i

運(yùn)行會(huì)發(fā)現(xiàn),打印若干個(gè)值之后,while循環(huán)就停止打印了。

但是一般情況下不建議通過這種方式來中斷線程,一般會(huì)在MyThread類中增加一個(gè)屬性 isStop來標(biāo)志是否結(jié)束while循環(huán),然后再在while循環(huán)中判斷isStop的值。

class MyThread extends Thread{
      private volatile boolean isStop = false;
      @Override
      public void run() {
          int i = 0;
          while(!isStop){
              i++;
          }
      }
       
      public void setStop(boolean stop){
          this.isStop = stop;
      }
  }

那么就可以在外面通過調(diào)用setStop方法來終止while循環(huán)。

7)interrupted方法


  interrupted()函數(shù)是Thread靜態(tài)方法,用來檢測(cè)當(dāng)前線程的interrupt狀態(tài),檢測(cè)完成后,狀態(tài)清空。通過下面的interrupted源碼我們能夠知道,此方法首先調(diào)用isInterrupted方法,而isInterrupted方法是一個(gè)重載的native方法private native boolean isInterrupted(boolean ClearInterrupted) 通過方法的注釋能夠知道,用來測(cè)試線程是否已經(jīng)中斷,參數(shù)用來決定是否重置中斷標(biāo)志。

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

  /**
   * Tests if some Thread has been interrupted.  The interrupted state
   * is reset or not based on the value of ClearInterrupted that is
   * passed.
   */
  private native boolean isInterrupted(boolean ClearInterrupted);

8)stop方法


stop方法已經(jīng)是一個(gè)廢棄的方法,它是一個(gè)不安全的方法。因?yàn)檎{(diào)用stop方法會(huì)直接終止run方法的調(diào)用,并且會(huì)拋出一個(gè)ThreadDeath錯(cuò)誤,如果線程持有某個(gè)對(duì)象鎖的話,會(huì)完全釋放鎖,導(dǎo)致對(duì)象狀態(tài)不一致。所以stop方法基本是不會(huì)被用到的。

9)destroy方法


destroy方法也是廢棄的方法?;静粫?huì)被使用到。

以下是關(guān)系到線程屬性的幾個(gè)方法:


1)getId用來得到線程ID

2)getName和setName用來得到或者設(shè)置線程名稱。

3)getPriority和setPriority用來獲取和設(shè)置線程優(yōu)先級(jí)。

4)setDaemon和isDaemon用來設(shè)置線程是否成為守護(hù)線程和判斷線程是否是守護(hù)線程。

守護(hù)線程和用戶線程的區(qū)別在于:守護(hù)線程依賴于創(chuàng)建它的線程,而用戶線程則不依賴。舉個(gè)簡(jiǎn)單的例子:如果在main線程中創(chuàng)建了一個(gè)守護(hù)線程,當(dāng)main方法運(yùn)行完畢之后,守護(hù)線程也會(huì)隨著消亡。而用戶線程則不會(huì),用戶線程會(huì)一直運(yùn)行直到其運(yùn)行完畢。在JVM中,像垃圾收集器線程就是守護(hù)線程。

Thread類有一個(gè)比較常用的靜態(tài)方法currentThread()用來獲取當(dāng)前線程。

在上面已經(jīng)說到了Thread類中的大部分方法,那么Thread類中的方法調(diào)用到底會(huì)引起線程狀態(tài)發(fā)生怎樣的變化呢?下面一幅圖就是在上面的圖上進(jìn)行改進(jìn)而來的:

java中線程狀態(tài)與方法的示例分析

關(guān)于“java中線程狀態(tài)與方法的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。


本文標(biāo)題:java中線程狀態(tài)與方法的示例分析
本文路徑:http://weahome.cn/article/pjppci.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部