线程的本质(Java 层实现)

关于上下文请看 线程本质,下面我们直接进入正题。

使用

先看看我们平时使用的方式,使用线程常见的代码如下:

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

然后我们知道里边的代码不会阻塞当前的执行流,而是新开一个异步线程去执行 while 循环,但是,为什么呢?
为什么就不会阻塞 UI 线程?
以及它到底是如何调度系统资源的?
或者直接一点,这货到底是怎么实现的?

代码

带着上边的问题,我们先来看一下 java 端的代码Thread.java,Java 层的线程实现自然是最简单的,搞 Android 或者 java 的对这个应该也很熟悉。这里我们简要介绍一下:
为了方便,我们先把 Runnable 贴一下,因为 Thread implements Runnable

// 就是一个接口定义了一个 run 方法,这里不多说
public interface Runnable {
    public abstract void run();
}

然后我们在把 Thread 的几个主要属性及函数列一下(不关主线的代码就都删掉了):

package java.lang;

public class Thread implements Runnable {

  // 先执行 native 函数来做一些注册相关的东西
  private static native void registerNatives();
  static {
    registerNatives();
  }

  private Runnable target;

  // 优先级
  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;
  }



  // 以下几个变量会在 native 层 classloader 时被调用,这里不做过多解释(这里其实也是应该删掉的)
  private Thread      threadQ;
  private long        eetop;
  private boolean     single_step;
  private boolean     stillborn = false;
  private long nativeParkEventPointer;



  // ThreadGroup 相关
  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 相关(就是日志中打印出来的线程名字),当线程初始化时,会根据 threadInitNumber 来自动生成线程名字
  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 相关(线程 id),通过 threadSeqNumber 的累加来赋值 tid(与 native 层的线程 id 没有一毛钱关系)
  private long tid;
  private static long threadSeqNumber;

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

  public long getId() {
    return tid;
  }



  // ThreadLocal,主要用来存储线程独有的变量,如果想了解的话可以参考 [ThreadLocal 框架](http://www.jianshu.com/p/e34ec28bf7a4)
  ThreadLocal.ThreadLocalMap threadLocals = null;
  ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;



  //线程状态
  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();
  }

  // 构造函数,有多个,为了方便展示框架,这里只贴了一个
  public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
  }

  // 开始真正执行此线程
  public synchronized void start() {
    ...
    start0();
    ...
  }

  // 没什么好说的,直接执行了 Runnable 的 run 函数
  public void run() {
    if (target != null) {
      target.run();
    }
  }

  // 判断当前线程是否中断
  public void interrupt() {
    ...
    interrupt0();
  }
  
  public static boolean interrupted() {
    return currentThread().isInterrupted(true);
  }

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

  // 阻塞调用此函数的线程,直到 join 归属的 Thread 实例执行完。核心就是执行了 wait,而 wait 这个函数其实也是 native 实现
  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 相关函数
  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();
}

总结

不多说,其实 Java 层的线程就是一层皮,没有什么实质性的逻辑,没有任何申请内存等相关的逻辑,就连 tid 都是根据 ++threadInitNumber 叠加出来的,与 native 层的完全没有关系。
我们发现我们上边的疑惑仍然没有得到解答,那我们接下来就看一下 native 层的实现。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,402评论 6 499
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,377评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,483评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,165评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,176评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,146评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,032评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,896评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,311评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,536评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,696评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,413评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,008评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,815评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,698评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,592评论 2 353

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,622评论 18 399
  • 本文主要讲了java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的一些线程函数用法、概述等。 首先讲...
    李欣阳阅读 2,454评论 1 15
  • Java多线程学习 [-] 一扩展javalangThread类 二实现javalangRunnable接口 三T...
    影驰阅读 2,957评论 1 18
  • 该文章转自:http://blog.csdn.net/evankaka/article/details/44153...
    加来依蓝阅读 7,350评论 3 87
  • “人生就像在打扑克牌,如果不足够幸运,总会抓到几张烂牌。” 今天是我和小猴子结婚一周年纪念日,同时也是我们认识的第...
    流浪的流浪的面包树阅读 402评论 3 5