最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java線程編程中Thread類的基礎學習教程

 更新時間:2015年12月07日 17:25:58   作者:海子  
這篇文章主要介紹了Java線程編程中Thread類的基礎學習教程,Thread類包含諸多操作線程的方法,非常重要,需要的朋友可以參考下

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

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

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

  當需要新起一個線程來執(zhí)行某個子任務時,就創(chuàng)建了一個線程。但是線程創(chuàng)建之后,不會立即進入就緒狀態(tài),因為線程的運行需要一些條件(比如內(nèi)存資源,在前面的JVM內(nèi)存區(qū)域劃分一篇博文中知道程序計數(shù)器、Java棧、本地方法棧都是線程私有的,所以需要為線程分配一定的內(nèi)存空間),只有線程運行需要的所有條件滿足了,才進入就緒狀態(tài)。

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

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

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

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

2015127171725022.jpg (778×492)

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

二.上下文切換

  對于單核CPU來說(對于多核CPU,此處就理解為一個核),CPU在一個時刻只能運行一個線程,當在運行一個線程的過程中轉(zhuǎn)去運行另外一個線程,這個叫做線程上下文切換(對于進程也是類似)。

  由于可能當前線程的任務并沒有執(zhí)行完畢,所以在切換時需要保存線程的運行狀態(tài),以便下次重新切換回來時能夠繼續(xù)切換之前的狀態(tài)運行。舉個簡單的例子:比如一個線程A正在讀取一個文件的內(nèi)容,正讀到文件的一半,此時需要暫停線程A,轉(zhuǎn)去執(zhí)行線程B,當再次切換回來執(zhí)行線程A的時候,我們不希望線程A又從文件的開頭來讀取。

  因此需要記錄線程A的運行狀態(tài),那么會記錄哪些數(shù)據(jù)呢?因為下次恢復時需要知道在這之前當前線程已經(jīng)執(zhí)行到哪條指令了,所以需要記錄程序計數(shù)器的值,另外比如說線程正在進行某個計算的時候被掛起了,那么下次繼續(xù)執(zhí)行的時候需要知道之前掛起時變量的值時多少,因此需要記錄CPU寄存器的狀態(tài)。所以一般來說,線程上下文切換過程中會記錄程序計數(shù)器、CPU寄存器狀態(tài)等數(shù)據(jù)。

  說簡單點的:對于線程的上下文切換實際上就是 存儲和恢復CPU狀態(tài)的過程,它使得線程執(zhí)行能夠從中斷點恢復執(zhí)行。

  雖然多線程可以使得任務執(zhí)行的效率得到提升,但是由于在線程切換時同樣會帶來一定的開銷代價,并且多個線程會導致系統(tǒng)資源占用的增加,所以在進行多線程編程時要注意這些因素。

三.Thread類中的方法

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

2015127171921431.jpg (666×732)

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

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

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

  1)start方法

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

  2)run方法

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

  3)sleep方法

  sleep方法有兩個重載版本:


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

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

  但是有一點要非常注意,sleep方法不會釋放鎖,也就是說如果當前線程持有對某個對象的鎖,則即使調(diào)用sleep方法,其他線程也無法訪問這個對象??聪旅孢@個例子就清楚了:


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()+"進入睡眠狀態(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é)果:

2015127171957572.jpg (625×214)

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

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

  4)yield方法

  調(diào)用yield方法會讓當前線程交出CPU權(quán)限,讓CPU去執(zhí)行其他的線程。它跟sleep方法類似,同樣不會釋放鎖。但是yield不能控制具體的交出CPU的時間,另外,yield方法只能讓擁有相同優(yōu)先級的線程有獲取CPU執(zhí)行時間的機會。

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

  5)join方法

  join方法有三個重載版本:

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

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

  看下面一個例子:

public class Test {
   
  public static void main(String[] args) throws IOException {
    System.out.println("進入線程"+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("進入線程"+Thread.currentThread().getName());
      try {
        Thread.currentThread().sleep(5000);
      } catch (InterruptedException e) {
        // TODO: handle exception
      }
      System.out.println("線程"+Thread.currentThread().getName()+"執(zhí)行完畢");
    }
  }
}

   輸出結(jié)果:

 2015127172052230.jpg (656×155)

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

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

2015127172222602.jpg (649×517)  

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

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

  6)interrupt方法

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

  下面看一個例子:

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("進入睡眠狀態(tài)");
        Thread.currentThread().sleep(10000);
        System.out.println("睡眠完畢");
      } catch (InterruptedException e) {
        System.out.println("得到中斷異常");
      }
      System.out.println("run方法執(zhí)行完畢");
    }
  }
}

輸出結(jié)果:

2015127172256485.jpg (624×115)

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

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<Integer.MAX_VALUE){
        System.out.println(i+" while循環(huán)");
        i++;
      }
    }
  }
}

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

  但是如果配合isInterrupted()能夠中斷正在運行的線程,因為調(diào)用interrupt方法相當于將中斷標志位置為true,那么可以通過調(diào)用isInterrupted()判斷中斷標志是否被置位來中斷線程的執(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<Integer.MAX_VALUE){
        System.out.println(i+" while循環(huán)");
        i++;
      }
    }
  }
}

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

  但是一般情況下不建議通過這種方式來中斷線程,一般會在MyThread類中增加一個屬性 isStop來標志是否結(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)stop方法

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

  8)destroy方法

  destroy方法也是廢棄的方法?;静粫皇褂玫健?/p>

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

  1)getId

  用來得到線程ID

  2)getName和setName

  用來得到或者設置線程名稱。

  3)getPriority和setPriority

  用來獲取和設置線程優(yōu)先級。

  4)setDaemon和isDaemon

  用來設置線程是否成為守護線程和判斷線程是否是守護線程。

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

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

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

2015127172336080.jpg (778×531)

相關(guān)文章

  • JAVA關(guān)鍵字及作用詳解

    JAVA關(guān)鍵字及作用詳解

    本文主要介紹了Java關(guān)鍵字及作用,具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • java的線程池框架及線程池的原理

    java的線程池框架及線程池的原理

    這篇文章主要介紹了java的線程池框架及線程池的原理的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • JavaWeb實現(xiàn)上傳文件功能

    JavaWeb實現(xiàn)上傳文件功能

    這篇文章主要為大家詳細介紹了JavaWeb實現(xiàn)上傳文件功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • Mybatis調(diào)用SQL?Server存儲過程的實現(xiàn)示例

    Mybatis調(diào)用SQL?Server存儲過程的實現(xiàn)示例

    在軟件開發(fā)過程中,經(jīng)常會使用到存儲過程,本文就來介紹一下Mybatis調(diào)用SQL?Server存儲過程的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • Java?IO與NIO高效的輸入輸出操作深入探究

    Java?IO與NIO高效的輸入輸出操作深入探究

    這篇文章主要為大家介紹了Java?IO與NIO高效的輸入輸出操作深入探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • SpringBoot+MinIO實現(xiàn)對象存儲方式

    SpringBoot+MinIO實現(xiàn)對象存儲方式

    這篇文章主要介紹了SpringBoot+MinIO實現(xiàn)對象存儲方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Java語法基礎之函數(shù)的使用說明

    Java語法基礎之函數(shù)的使用說明

    函數(shù)就是定義在類中的具有特定功能的一段小程序,函數(shù)也稱為方法
    2013-07-07
  • BaseDao封裝增刪改查的代碼詳解

    BaseDao封裝增刪改查的代碼詳解

    本篇文章主要介紹對數(shù)據(jù)庫中表中的數(shù)據(jù)進行增改刪查詢,封裝一個工具類(BaseDao)的詳細使用以及部分理論知識,并通過代碼示例給大家介紹的非常詳細,需要的朋友可以參考下
    2024-03-03
  • java實現(xiàn)九宮格游戲

    java實現(xiàn)九宮格游戲

    這篇文章主要為大家詳細介紹了java實現(xiàn)九宮格游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • Spring Cloud Stream 高級特性使用詳解

    Spring Cloud Stream 高級特性使用詳解

    這篇文章主要為大家介紹了Spring Cloud Stream 高級特性使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09

最新評論

剑河县| 寻乌县| 乌拉特中旗| 额济纳旗| 华容县| 察雅县| 皮山县| 灵寿县| 万源市| 乌恰县| 博野县| 独山县| 特克斯县| 余干县| 宣城市| 霍州市| 乾安县| 玉山县| 吉首市| 太和县| 崇左市| 三门峡市| 常熟市| 安龙县| 德清县| 黄陵县| 绿春县| 炉霍县| 建德市| 涟源市| 新化县| 博乐市| 临沂市| 油尖旺区| 安顺市| 石景山区| 舟山市| 全州县| 梁山县| 阿城市| 新郑市|