欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java 控制線程的方法

 更新時(shí)間:2020年06月22日 10:04:52   作者:認(rèn)真對待世界的小白  
這篇文章主要介紹了Java 控制線程的方法,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

Java 的線程支持提供了一些便捷的工具方法,通過這些便捷的工具方法可以很好地控制線程的執(zhí)行。

join 線程

Thread 提供了讓一個(gè)線程等待另一個(gè)線程完成的方法—— join() 方法。當(dāng)在某個(gè)程序執(zhí)行流中調(diào)用其他線程的 join() 方法時(shí),調(diào)用線程將被阻塞,直到被 join() 方法加入的 join 線程執(zhí)行完為止。

join() 方法通常由使用線程的程序調(diào)用,以將大問題劃分成許多小問題,每個(gè)小問題分配一個(gè)線程。當(dāng)所有的小問題都得到處理后,再調(diào)用主線程來進(jìn)一步操作。

public class JoinThread extends Thread{
  // 提供一個(gè)有參數(shù)的構(gòu)造器,用于設(shè)置該線程的名字
  public JoinThread(String name) {
    super(name);
  }
  //重寫run()方法,定義線程執(zhí)行體
  public void run() {
    for (int i=0 ; i < 100; i++) {
      System.out.println(this.getName() + " " + i);
    }
  }
  public static void main(String[] args) throws Exception {
    //啟動子線程
    new JoinThread("新線程").start();
    for(int i=0 ; i < 100; i++) {
      if(i==20) {
        JoinThread jt = new JoinThread("被Join的線程");
        jt.start();
        // main線程調(diào)用了 jt 線程的 join() 方法
        // main線程必須等jt執(zhí)行結(jié)束后才會向下執(zhí)行
        jt.join();
      }
      System.out.println(Thread.currentThread().getName() + " " + i);
    }
  }
}

上面程序中一共有3個(gè)線程,主方法開始時(shí)就啟動了名為“新線程”的子線程,該子線程將會和 main 線程并發(fā)執(zhí)行。當(dāng)主線程的循環(huán)變量 i 等于20時(shí),啟動了名為“被 Join 的線程”的線程,該線程不會和 main 線程并發(fā)執(zhí)行 , main 線程必須等該線程執(zhí)行結(jié)束后才可以向下執(zhí)行。在名為“被 Join 的線程”的線程執(zhí)行時(shí),實(shí)際上只有2個(gè)子線程并發(fā)執(zhí)行,而主線程處于等待狀態(tài)。運(yùn)行上面程序,會看到如下圖所示的運(yùn)行效果。

主線程執(zhí)行到 i == 20時(shí),程序啟動并 join 了名為“被 Join 的線程”的線程,所以主線程將一直處于阻塞狀態(tài),直到名為“被 Join 的線程”的線程執(zhí)行完成。

join() 方法有如下三種重載形式:

  • join():等待被 join 的線程執(zhí)行完成。
  • join(long  millis):等待被 join 的線程的時(shí)間最長為 millis 毫秒。如果在 millis 毫秒內(nèi)被 join 的線程還沒有執(zhí)行結(jié)束,則不再等待。
  • join(long millis, int nanos):等待被 join 的線程的時(shí)間最長為 millis 毫秒加 nanos 毫微秒。

提示:通常很少使用第三種形式,原因有兩個(gè):程序?qū)r(shí)間的精度無須精確到毫微秒;計(jì)算機(jī)硬件、操作系統(tǒng)本身也無法精確到毫微秒。

后臺線程

有一種線程,它是在后臺運(yùn)行的,它的任務(wù)是為其他的線程提供服務(wù),這種線程被稱為“后臺線程(Daemon Thread)”,又稱為“守護(hù)線程”或“精靈線程”。 JVM 的垃圾回收線程就是典型的后臺線程。

后臺線程有個(gè)特征:如果所有的前臺線程都死亡,后臺線程會自動死亡。

調(diào)用 Thread 對象的 setDaemon(true) 方法可將指定線程設(shè)置成后臺線程。下面程序?qū)?zhí)行線程設(shè)置成后臺線程,可以看到當(dāng)所有的前臺線程死亡時(shí),后臺線程隨之死亡。當(dāng)整個(gè)虛擬機(jī)中只剩下后臺線程時(shí),程序就沒有繼續(xù)運(yùn)行的必要了,所以虛擬機(jī)也就退出了。

public class DaemonThread extends Thread {
  // 定義后臺線程的線程執(zhí)行體與普通線程沒有任何區(qū)別
  public void run() {
    for (int i=0 ; i < 1000; i++) {
      System.out.println(this.getName() + " " + i);
    }
  }
  
  public static void main(String[] args) {
    DaemonThread t = new DaemonThread();
    // 將此線程設(shè)置為后臺線程
    t.setDaemon(true);
    // 啟動后臺線程
    t.start();
    for (int i=0; i < 100; i++) {
      System.out.println(Thread.currentThread().getName() + " " + i);
    }
    // ---------程序執(zhí)行到此處,前臺線程(main線程)結(jié)束----------
    // 后臺線程也應(yīng)該隨之結(jié)束      
  }
}

上面程序中的粗體字代碼先將t線程設(shè)置成后臺線程,然后啟動該線程,本來該線程應(yīng)該執(zhí)行到 i 等于999時(shí)才會結(jié)束,但運(yùn)行程序時(shí)不難發(fā)現(xiàn)該后臺線程無法運(yùn)行到999,因?yàn)楫?dāng)主線程也就是程序中唯一的前臺線程運(yùn)行結(jié)束后,JVM 會主動退出,因而后臺線程也就被結(jié)束了。

Thread 類還提供了一個(gè) isDaemon() 方法,用于判斷指定線程是否為后臺線程。

從上面程序可以看出,主線程默認(rèn)是前臺線程,t線程默認(rèn)也是前臺線程。并不是所有的線程默認(rèn)都是前臺線程,有些線程默認(rèn)就是后臺線程——前臺線程創(chuàng)建的子線程默認(rèn)是前臺線程,后臺線程創(chuàng)建的子線程默認(rèn)是后臺線程。

注意:前臺線程死亡后, JVM 會通知后臺線程死亡,但從它接收指令到做出響應(yīng),需要一定時(shí)間。而且要將某個(gè)線程設(shè)置為后臺線程,必須在該線程啟動之前設(shè)置,也就是說,setDaemon(true) 必須在 start() 方法之前調(diào)用,否則會引發(fā) IllegalThreadStateException異常。

線程睡眠:sleep

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

  • static void sleep(long millis):讓當(dāng)前正在執(zhí)行的線程暫停millis毫秒,并進(jìn)入阻塞狀態(tài),該方法受到系統(tǒng)計(jì)時(shí)器和線程調(diào)度器的精度與準(zhǔn)確度的影響。
  • static void sleep(long millis, int nanos):讓當(dāng)前正在執(zhí)行的線程暫停 millis 毫秒加 nanos 毫微秒,并進(jìn)入阻塞狀態(tài),該方法受到系統(tǒng)計(jì)時(shí)器和線程調(diào)度器的精度與準(zhǔn)確度的影響。

與前面類似的是,程序很少調(diào)用第二種形式的 sleep() 方法。

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

下面程序調(diào)用 sleep() 方法來暫停主線程的執(zhí)行,因?yàn)樵摮绦蛑挥幸粋€(gè)主線程,當(dāng)主線程進(jìn)入睡眠后,系統(tǒng)沒有可執(zhí)行的線程,所以可以看到程序在 sleep() 方法處暫停。

public class SleepTest {
  public static void main(String[] args) throws Exception {
    for(int i=0;i<10;i++) {
      System.out.println("當(dāng)前時(shí)間:"+new Date());
      // 調(diào)用sleep() 方法讓當(dāng)前線程暫停1s
      Thread.sleep(1000);
    }
  }
}

上面程序中的粗體字代碼將當(dāng)前執(zhí)行的線程暫停 1 秒,運(yùn)行上面程序,看到程序依次輸出10條字符串,輸出2條字符串之間的時(shí)間間隔為1秒。

線程讓步: yield

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

實(shí)際上,當(dāng)某個(gè)線程調(diào)用了 yield() 方法暫停之后,只有優(yōu)先級與當(dāng)前線程相同,或者優(yōu)先級比當(dāng)前線程更高的處于就緒狀態(tài)的線程才會獲得執(zhí)行的機(jī)會。下面程序使用 yield() 方法來讓當(dāng)前正在執(zhí)行的線程暫停。

public class YieldTest extends Thread{
  public YieldTest(String name) {
    super(name);
  }
  // 定義run()方法作為線程執(zhí)行體
  public void run() {
    for(int i=0;i<50;i++) {
      System.out.println(getName()+"  "+i);
      // 當(dāng) i等于20時(shí),使用 yield() 方法讓當(dāng)前線程讓步
      if(i==20) {
        Thread.yield();
      }
    }
  }
  public static void main(String[] args) {
    // 啟動兩個(gè)并發(fā)線程 
    YieldTest yt1 = new YieldTest("高級");
    // 將yt1線程設(shè)置成最高優(yōu)先級
    // yt1.setPriority(Thread.MAX_PRIORITY);
    yt1.start();
    YieldTest yt2 = new YieldTest("低級");
    // 將yt2線程設(shè)置成最低優(yōu)先級
    // yt2.setPriority(Thread.MIN_PRIORITY);
    yt2.start();
  }
}

注意:在多 CPU 并行的環(huán)境下, yield() 方法的功能有時(shí)候并不明顯。

關(guān)于 sleep() 方法和 yield() 方法的區(qū)別如下。

  • sleep() 方法暫停當(dāng)前線程后,會給其他線程執(zhí)行機(jī)會,不會理會其他線程的優(yōu)先級;但 yield() 方法只會給優(yōu)先級相同,或優(yōu)先級更高的線程執(zhí)行機(jī)會。
  • sleep() 方法會將線程轉(zhuǎn)入阻塞狀態(tài),直到經(jīng)過阻塞時(shí)間才會轉(zhuǎn)入就緒狀態(tài);而 yield() 不會將線程轉(zhuǎn)入阻塞狀態(tài),它只是強(qiáng)制當(dāng)前線程進(jìn)入就緒狀態(tài)。因此完全有可能某個(gè)線程調(diào)用 yield() 方法暫停之后,立即再次獲得處理器資源被執(zhí)行。
  • sleep() 方法聲明拋出了 InterruptedException 異常,所以調(diào)用 sleep() 方法時(shí)要么捕捉該異常,要么顯式聲明拋出該異常;而 yield ()方法則沒有聲明拋出任何異常。
  • sleep() 方法比 yield() 方法有更好的可移植性,通常不建議使用 yield() 方法來控制并發(fā)線程的執(zhí)行。

改變線程優(yōu)先級

每個(gè)線程執(zhí)行時(shí)都具有一定的優(yōu)先級,優(yōu)先級高的線程獲得較多的執(zhí)行機(jī)會,而優(yōu)先級低的線程則獲得較少的執(zhí)行機(jī)會。

每個(gè)線程默認(rèn)的優(yōu)先級都與創(chuàng)建它的父線程的優(yōu)先級相同,在默認(rèn)情況下, main 線程具有普通優(yōu)先級,由 main 線程創(chuàng)建的子線程也具有普通優(yōu)先級。

Thread 類提供了 setPriority(int newPriority)、 getPriority() 方法來設(shè)置和返回指定線程的優(yōu)先級,其中 setPriority() 方法的參數(shù)可以是一個(gè)整數(shù),范圍是1~10之間,也可以使用 Thread 類的如下三個(gè)靜態(tài)常量。

  • MAX _ PRIORITY:其值是 10。
  • MIN _ PRIORITY:其值是 1 。
  • NORM _ PRIORITY:其值是 5。

下面程序使用了 setPriority() 方法來改變主線程的優(yōu)先級,并使用該方法改變了兩個(gè)線程的優(yōu)先級,從而可以看到高優(yōu)先級的線程將會獲得更多的執(zhí)行機(jī)會。

public class PriorityTest extends Thread{
  public PriorityTest(String name) {
    super(name);
  }
  public void run() {
    for(int i=0;i<50;i++) {
      System.out.println(getName()+",其優(yōu)先級是:"+getPriority()+",循環(huán)變量的值為:"+i);
    }
  }
  public static void main(String[] args) {
    // 改變主線程的優(yōu)先級
    Thread.currentThread().setPriority(6);
    for(int i=0;i<30;i++) {
      if(i==10) {
        PriorityTest low = new PriorityTest("低級");
        low.start();
        System.out.println("創(chuàng)建之初的優(yōu)先級:"+low.getPriority());
        // 設(shè)置該線程為最低優(yōu)先級
        low.setPriority(Thread.MIN_PRIORITY);
      }
      if(i==20) {
        PriorityTest high = new PriorityTest("高級");
        high.start();
        System.out.println("創(chuàng)建之初的優(yōu)先級:"+high.getPriority());
        // 設(shè)置該線程為最高優(yōu)先級
        high.setPriority(Thread.MAX_PRIORITY);
      }
    }
  }
}

上面程序中的第一行粗體字代碼改變了主線程的優(yōu)先級為6,這樣由main線程所創(chuàng)建的子線程的優(yōu)先級默認(rèn)都是6,所以程序直接輸出 low、high 兩個(gè)線程的優(yōu)先級時(shí)應(yīng)該看到6。接著程序?qū)?low 線程的優(yōu)先級設(shè)為 Priority.MIN_PRIORITY,將 high 線程的優(yōu)先級設(shè)置為 Priority.MAX_PRIORITY。

運(yùn)行上面程序,會看到如下圖所示的效果。

值得指出的是,雖然 Java 提供了 10 個(gè)優(yōu)先級級別,但這些優(yōu)先級級別需要操作系統(tǒng)的支持。遺憾的是,不同操作系統(tǒng)上的優(yōu)先級并不相同,而且也不能很好地和 Java 的10個(gè)優(yōu)先級對應(yīng),例如 Windows 2000 僅提供了 7個(gè)優(yōu)先級。因此應(yīng)該盡量避免直接為線程指定優(yōu)先級,而應(yīng)該使用 MAX_PRIORITY、MIN_PRIORITY 和 NORM_PRIORITY 三個(gè)靜態(tài)常量來設(shè)置優(yōu)先級,這樣才可以保證程序具有最好的可移植性。

以上就是Java 控制線程的方法的詳細(xì)內(nèi)容,更多關(guān)于Java 控制線程的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • java中l(wèi)ong(Long)與int(Integer)之間的轉(zhuǎn)換方式

    java中l(wèi)ong(Long)與int(Integer)之間的轉(zhuǎn)換方式

    這篇文章主要介紹了java中l(wèi)ong(Long)與int(Integer)之間的轉(zhuǎn)換方式,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-10-10
  • Java保留兩位小數(shù)的幾種寫法總結(jié)

    Java保留兩位小數(shù)的幾種寫法總結(jié)

    相信大家在平時(shí)做項(xiàng)目時(shí),可能會有這樣的業(yè)務(wù)需求: 頁面或界面上展示的數(shù)據(jù)保留小數(shù)點(diǎn)后兩位。 那么這篇文章小編就和大家分享了利用Java保留兩位小數(shù)的幾種寫法,文章給出了詳細(xì)的示例代碼,對大家的學(xué)習(xí)和理解很有幫助,有需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)下吧。
    2016-11-11
  • 詳解jeefast和Mybatis實(shí)現(xiàn)二級聯(lián)動的問題

    詳解jeefast和Mybatis實(shí)現(xiàn)二級聯(lián)動的問題

    這篇文章主要介紹了詳解jeefast和Mybatis實(shí)現(xiàn)二級聯(lián)動的問題,本文通過圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Java多線程的原子性,可見性,有序性你都了解嗎

    Java多線程的原子性,可見性,有序性你都了解嗎

    這篇文章主要為大家詳細(xì)介紹了Java多線程的原子性,可見性,有序性,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • Java利用for循環(huán)輸出空心菱形的實(shí)例代碼

    Java利用for循環(huán)輸出空心菱形的實(shí)例代碼

    這篇文章主要介紹了Java利用for循環(huán)輸出空心菱形的實(shí)例代碼,需要的朋友可以參考下
    2014-02-02
  • java基礎(chǔ)之Collection與Collections和Array與Arrays的區(qū)別

    java基礎(chǔ)之Collection與Collections和Array與Arrays的區(qū)別

    這篇文章主要介紹了java基礎(chǔ)之Collection與Collections和Array與Arrays的區(qū)別的相關(guān)資料,本文主要說明兩者的區(qū)別以防大家混淆概念,需要的朋友可以參考下
    2017-08-08
  • Mybatis實(shí)現(xiàn)查詢相冊數(shù)據(jù)列表流程講解

    Mybatis實(shí)現(xiàn)查詢相冊數(shù)據(jù)列表流程講解

    這篇文章主要介紹了Mybatis實(shí)現(xiàn)查詢相冊數(shù)據(jù)列表流程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-12-12
  • Java中forEach使用lambda表達(dá)式,數(shù)組和集合的區(qū)別說明

    Java中forEach使用lambda表達(dá)式,數(shù)組和集合的區(qū)別說明

    這篇文章主要介紹了Java中forEach使用lambda表達(dá)式,數(shù)組和集合的區(qū)別說明,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Spring使用AOP完成統(tǒng)一結(jié)果封裝實(shí)例demo

    Spring使用AOP完成統(tǒng)一結(jié)果封裝實(shí)例demo

    這篇文章主要介紹了Spring使用AOP完成統(tǒng)一結(jié)果封裝,本文通過實(shí)現(xiàn)demo給大家詳細(xì)講解,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-02-02
  • java實(shí)現(xiàn)紙牌游戲之小貓釣魚算法

    java實(shí)現(xiàn)紙牌游戲之小貓釣魚算法

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)紙牌游戲之小貓釣魚算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-01-01

最新評論