線程的本質(zhì)(Java 層實(shí)現(xiàn))

關(guān)于上下文請(qǐng)看 線程本質(zhì),下面我們直接進(jìn)入正題。

使用

先看看我們平時(shí)使用的方式,使用線程常見的代碼如下:

Thread thread = new Thread(new Runnable() {
      @Override
      public void run() {
        while (true) {
          // 噠噠噠噠
        }
      }
    });
thread.start();

然后我們知道里邊的代碼不會(huì)阻塞當(dāng)前的執(zhí)行流,而是新開一個(gè)異步線程去執(zhí)行 while 循環(huán),但是,為什么呢?
為什么就不會(huì)阻塞 UI 線程?
以及它到底是如何調(diào)度系統(tǒng)資源的?
或者直接一點(diǎn),這貨到底是怎么實(shí)現(xiàn)的?

代碼

帶著上邊的問(wèn)題,我們先來(lái)看一下 java 端的代碼Thread.java,Java 層的線程實(shí)現(xiàn)自然是最簡(jiǎn)單的,搞 Android 或者 java 的對(duì)這個(gè)應(yīng)該也很熟悉。這里我們簡(jiǎn)要介紹一下:
為了方便,我們先把 Runnable 貼一下,因?yàn)?Thread implements Runnable。

// 就是一個(gè)接口定義了一個(gè) run 方法,這里不多說(shuō)
public interface Runnable {
    public abstract void run();
}

然后我們?cè)诎?Thread 的幾個(gè)主要屬性及函數(shù)列一下(不關(guān)主線的代碼就都刪掉了):

package java.lang;

public class Thread implements Runnable {

  // 先執(zhí)行 native 函數(shù)來(lái)做一些注冊(cè)相關(guān)的東西
  private static native void registerNatives();
  static {
    registerNatives();
  }

  private Runnable target;

  // 優(yōu)先級(jí)
  public final static int MIN_PRIORITY = 1;
  public final static int NORM_PRIORITY = 5;
  public final static int MAX_PRIORITY = 10;
  private int         priority;

  public final void setPriority(int newPriority) {
    ...
    setPriority0(priority = newPriority);
  }

  public final int getPriority() {
    return priority;
  }



  // 以下幾個(gè)變量會(huì)在 native 層 classloader 時(shí)被調(diào)用,這里不做過(guò)多解釋(這里其實(shí)也是應(yīng)該刪掉的)
  private Thread      threadQ;
  private long        eetop;
  private boolean     single_step;
  private boolean     stillborn = false;
  private long nativeParkEventPointer;



  // ThreadGroup 相關(guān)
  private ThreadGroup group;

  public final ThreadGroup getThreadGroup() {
    return group;
  }

  public static int activeCount() {
    return currentThread().getThreadGroup().activeCount();
  }

  public static int enumerate(Thread tarray[]) {
    return currentThread().getThreadGroup().enumerate(tarray);
  }



  // name 相關(guān)(就是日志中打印出來(lái)的線程名字),當(dāng)線程初始化時(shí),會(huì)根據(jù) threadInitNumber 來(lái)自動(dòng)生成線程名字
  private char        name[];
  private static int threadInitNumber;

  private static synchronized int nextThreadNum() {
    return threadInitNumber++;
  }

  public final void setName(String name) {
    ...
    this.name = name.toCharArray();
  }

  public final String getName() {
    return String.valueOf(name);
  }



  // tid 相關(guān)(線程 id),通過(guò) threadSeqNumber 的累加來(lái)賦值 tid(與 native 層的線程 id 沒(méi)有一毛錢關(guān)系)
  private long tid;
  private static long threadSeqNumber;

  private static synchronized long nextThreadID() {
    return ++threadSeqNumber;
  }

  public long getId() {
    return tid;
  }



  // ThreadLocal,主要用來(lái)存儲(chǔ)線程獨(dú)有的變量,如果想了解的話可以參考 [ThreadLocal 框架](http://www.itdecent.cn/p/e34ec28bf7a4)
  ThreadLocal.ThreadLocalMap threadLocals = null;
  ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;



  //線程狀態(tài)
  private int threadStatus = 0;

  public enum State {
    NEW,
    RUNNABLE,
    BLOCKED,
    WAITING,
    TIMED_WAITING,
    TERMINATED;
  }

  public State getState() {
    return sun.misc.VM.toThreadState(threadStatus);
  }


  // 線程休眠
  public static void sleep(long millis, int nanos) throws InterruptedException {
    。。。
    sleep(millis);
  }

  // 初始化
  private void init(ThreadGroup g, Runnable target, String name,
                    long stackSize) {
    Thread parent = currentThread();
    ...
    this.group = g;
    this.priority = parent.getPriority();
    this.name = name.toCharArray();
    this.target = target;
    setPriority(priority);
    ....
    tid = nextThreadID();
  }

  // 構(gòu)造函數(shù),有多個(gè),為了方便展示框架,這里只貼了一個(gè)
  public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
  }

  // 開始真正執(zhí)行此線程
  public synchronized void start() {
    ...
    start0();
    ...
  }

  // 沒(méi)什么好說(shuō)的,直接執(zhí)行了 Runnable 的 run 函數(shù)
  public void run() {
    if (target != null) {
      target.run();
    }
  }

  // 判斷當(dāng)前線程是否中斷
  public void interrupt() {
    ...
    interrupt0();
  }
  
  public static boolean interrupted() {
    return currentThread().isInterrupted(true);
  }

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

  // 阻塞調(diào)用此函數(shù)的線程,直到 join 歸屬的 Thread 實(shí)例執(zhí)行完。核心就是執(zhí)行了 wait,而 wait 這個(gè)函數(shù)其實(shí)也是 native 實(shí)現(xiàn)
  public final synchronized void join(long millis) throws InterruptedException {
    long base = System.currentTimeMillis();
    long now = 0;

    ...
    if (millis == 0) {
      while (isAlive()) {
        wait(0);
      }
    } else {
      while (isAlive()) {
        long delay = millis - now;
        if (delay <= 0) {
          break;
        }
        wait(delay);
        now = System.currentTimeMillis() - base;
      }
    }
  }


  // native 相關(guān)函數(shù)
  public static native boolean holdsLock(Object obj);
  private native static StackTraceElement[][] dumpThreads(Thread[] threads);
  private native static Thread[] getThreads();

  public static native Thread currentThread();
  public static native void yield();
  public static native void sleep(long millis) throws InterruptedException;

  private native boolean isInterrupted(boolean ClearInterrupted);
  public final native boolean isAlive();
  private native void start0();
  private native void setPriority0(int newPriority);
  private native void stop0(Object o);
  private native void suspend0();
  private native void resume0();
  private native void interrupt0();
}

總結(jié)

不多說(shuō),其實(shí) Java 層的線程就是一層皮,沒(méi)有什么實(shí)質(zhì)性的邏輯,沒(méi)有任何申請(qǐng)內(nèi)存等相關(guān)的邏輯,就連 tid 都是根據(jù) ++threadInitNumber 疊加出來(lái)的,與 native 層的完全沒(méi)有關(guān)系。
我們發(fā)現(xiàn)我們上邊的疑惑仍然沒(méi)有得到解答,那我們接下來(lái)就看一下 native 層的實(shí)現(xiàn)。

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

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚_t_閱讀 34,633評(píng)論 18 399
  • 本文主要講了java中多線程的使用方法、線程同步、線程數(shù)據(jù)傳遞、線程狀態(tài)及相應(yīng)的一些線程函數(shù)用法、概述等。 首先講...
    李欣陽(yáng)閱讀 2,593評(píng)論 1 15
  • Java多線程學(xué)習(xí) [-] 一擴(kuò)展javalangThread類 二實(shí)現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 3,106評(píng)論 1 18
  • 該文章轉(zhuǎn)自:http://blog.csdn.net/evankaka/article/details/44153...
    加來(lái)依藍(lán)閱讀 7,465評(píng)論 3 87
  • “人生就像在打撲克牌,如果不足夠幸運(yùn),總會(huì)抓到幾張爛牌?!?今天是我和小猴子結(jié)婚一周年紀(jì)念日,同時(shí)也是我們認(rèn)識(shí)的第...
    流浪的流浪的面包樹閱讀 483評(píng)論 3 5

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