關(guān)于Java的線程

最近工作中遇到了一個(gè)需要將main job拆分成多個(gè)sub job并發(fā)跑的需求,想想自己之前Java里面零零散散看的多線程也基本上忘光了,于是順手拿了本手邊上厚得和磚頭一樣的《Java編程思想》開始從線程開始看。為了防止自己又變成小金魚,還是記下一點(diǎn)吧。

定義任務(wù)

  1. 實(shí)現(xiàn)Runnable接口
    需要實(shí)現(xiàn)該接口的run()方法。
public class Liftoff implements Runnable {
  private int countDown = 10;
  private static int taskCount = 0;
  private final int id = taskCount++;

  public Liftoff() {}
  public Liftoff(int countDown) {
    this.countDown = countDown;
  }
  private void status() {
    System.out.println("#" + id + "(" + (countDown > 0? countDown : "LiftOff") + ")");
  }
  @Override
  public void run() {
    while (countDown-- > 0) {
      status();
      Thread.yield();
    }
  }

上述代碼中,run()方法通常會(huì)有某種形式的循環(huán)。一般會(huì)寫成無限循環(huán)的模式知道滿足某個(gè)條件使run()終止。
這里只是定義了任務(wù),還未最終執(zhí)行。

public static void main(String[] args) {
    LiftOff launch = new LiftOff();
    launch.run();
}

這段代碼并未啟動(dòng)一個(gè)新的線程,它只是在main線程中調(diào)用了LiftOff類的run()方法。要實(shí)現(xiàn)線程行為,需要將該任務(wù)顯示地附著在線程之上。

Thread.yield() 該方法的意思是建議線程調(diào)度器切換至另一線程執(zhí)行,只是建議,并不能保證該線程會(huì)被切換。

  1. Thread類
    我們改變main()方法。
  public static void main(String[] args) {
    for (int i = 0; i < 2; i++) {
      Thread thread = new Thread(new Liftoff());
      thread.start();
    }
    System.out.println("This should appear first");
}

可能出現(xiàn)的output如下

#0(9)  #1(9)  This should appear first
#0(8)  #1(8)  #0(7)  #1(7)  #0(6)  #1(6)  #1(5)  #0(5)  #1(4)  #0(4)  #1(3)  #0(3)  #1(2)  #0(2)  #1(1)  #0(1)  #1(LiftOff)  #0(LiftOff)  

可以看出main thread 和 new 出來的threads『并發(fā)』地執(zhí)行了。并且new出來的兩個(gè)threads之間也是『并發(fā)』執(zhí)行的。不同任務(wù)的執(zhí)行在線程換進(jìn)換出時(shí)混在了一起。

Thread中的run()和start()
在上面的代碼中,我們使用了start()方法。start()方法會(huì)創(chuàng)建新的線程,然后調(diào)用任務(wù)中的run()方法。而Thread()中的run()方法并不會(huì)創(chuàng)建新的線程,只是簡(jiǎn)單地調(diào)用任務(wù)中的run()方法。

  1. Executor
    Executor可以管理Thread對(duì)象,從而簡(jiǎn)化了并發(fā)編程。
    (1) FixedThreadPool
  public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(2);
    for (int i = 0; i < 5; i++) {
      executorService.execute(new Liftoff());
    }
    executorService.shutdown();
  }

始終固定地只有n個(gè)線程,如果已經(jīng)有了n個(gè)線程在執(zhí)行,則別的任務(wù)需要等待。
如上代碼的輸出可能為

#0(9)  #1(9)  #0(8)  #1(8)  #0(7)  #1(7)  #0(6)  #1(6)  #0(5)  #1(5)  #0(4)  #1(4)  #0(3)  #1(3)  #0(2)  #1(2)  #0(1)  #1(1)  #0(LiftOff)  #1(LiftOff)  #2(9)  #3(9)  #2(8)  #3(8)  #2(7)  #3(7)  #2(6)  #3(6)  #2(5)  #3(5)  #2(4)  #3(4)  #2(3)  #3(3)  #2(2)  #3(2)  #2(1)  #3(1)  #2(LiftOff)  #3(LiftOff)  #4(9)  #4(8)  #4(7)  #4(6)  #4(5)  #4(4)  #4(3)  #4(2)  #4(1)  #4(LiftOff)  

可以看出始終只有兩個(gè)線程在「并發(fā)」地跑。0和1之間,2和3之間在不停切換。
(2) CachedThreadPool

  public static void main(String[] args) {
    ExecutorService executorService = Executors.newCachedThreadPool();
    for (int i = 0; i < 5; i++) {
      executorService.execute(new Liftoff());
    }
    executorService.shutdown();
  }

CacheThreadPool為每個(gè)任務(wù)都創(chuàng)建一個(gè)線程,如果正好某個(gè)線程空閑,則任務(wù)會(huì)利用之前的線程。
上述代碼的輸出可能如下。

#0(9)  #1(9)  #2(9)  #3(9)  #4(9)  #0(8)  #1(8)  #2(8)  #3(8)  #4(8)  #0(7)  #1(7)  #2(7)  #3(7)  #4(7)  #0(6)  #1(6)  #2(6)  #3(6)  #4(6)  #0(5)  #1(5)  #2(5)  #3(5)  #4(5)  #0(4)  #1(4)  #2(4)  #3(4)  #4(4)  #0(3)  #1(3)  #2(3)  #3(3)  #4(3)  #0(2)  #1(2)  #2(2)  #3(2)  #4(2)  #0(1)  #1(1)  #2(1)  #3(1)  #4(1)  #0(LiftOff)  #1(LiftOff)  #2(LiftOff)  #3(LiftOff)  #4(LiftOff)  

可以看出5個(gè)線程之間在不停地來回切換。
(3) SingleThreadPool
與名字的意思一致。

最后編輯于
?著作權(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)容