Java线程学习笔记(1)

对于一个从C#转到Kotlin的菜鸟,C#的时候只知道async和await Task这样的操作,Kotlin也是用着现成封装好的thread方法或者launch,从来没有好好研究现成具体的代码,最近终于有时间来好好看看Java平台的线程这个玩意儿了。

都知道看源码的效率是最高的,所以今天特意花了一天的时间看了一下源码,也了解到了线程的一些具体实现,大家不要觉得线程是个什么高端的玩意儿,看着各个博客中各位大神写的那个是眉飞色舞啊,今天我就另辟蹊径,从源码来看线程的实现。

相信大家用的最频繁的线程操作就是Thread.sleep()这个静态方法了,我相信是个程序员都知道有这么一个方法,说到这儿就不得不提到Thread这个类了。Thread这个类位于java.lang这个包下,打开这个class文件看到的类声明的第一行就写着 public class Thread implements Runnable{...},Thread类继承的这个接口看着好眼熟啊,定位到接口一看,果然是这个家伙。

public interface Runnable {
    public abstract void run();
}

相信大家在各位大神的文章中也经常看到这个对这个接口的描述,但我们是菜鸟,不能跟大神们相比,所以我们今天就从零开始,先从这个接口的注释信息开始看起,有三段注释,大概的意思是这个接口应该被想要被线程执行的类来实现巴拉巴拉(笔者就偷个懒了,说白了就是给线程设计的一个接口)。但注释中只说了应该,并不是说继承了这个接口的类就一定要跑在线程里面,完全可以是一个普通的类,可以正常的实例化并且调用run方法,希望大家不要陷入继承了Runnable接口就一定是要执行线程的操作了这样的误区中。
说完了这个接口我们回过头来看Thread这个类,这个类提供了很多的静态方法,比如sleep、currentThread等我们常用的一些方法,接着我们来看一下Thread类的构造方法,这个类提供了很多的构造方法,包括无参构造以及一个一下子映入我眼帘的构造方法:

public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
}

看到这儿总觉得自己明白了些什么,一个Runnable类型的参数,我迫不及待的点开init方法,这个方法是对Thread类中的一些私有变量进行初始化,特别是 private Runnable target 这个参数,将实现了Runnable的参数赋给target,接下来的大家猜都不用猜就知道是怎么回事了,对,就是start方法。

public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            }
        }
    }
private native void start0();

虽然大家都知道大概是怎么一回事儿了,但是对这个start0方法还是有很多疑问的,说好的调用run方法呢,怎么就变成了start0了!不要慌,虽然我的c没学好,但是我会百度啊,花了2分钟还是被我找到了!其实在Thread初始化的时候会注册一些native方法,比如start0、stop等

private static native void registerNatives();
  static {
        registerNatives();
    }

这些native方法定义在Thread.c 文件中的,Thread.c 是个很小的文件,它定义了各个操作系统平台都要用到的关于线程的公用数据和操作。如果会C的小伙伴可以去研究一下,学渣表示看不太懂,就能知道个大概,所以也就不深究了,具体参考和源码如下:
https://www.linuxidc.com/Linux/2016-03/128997.htm
http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/tip/src/share/vm/prims/jvm.cpp#l2951
大家只要知道这个start0其实调用的就是Thread实现了Runnable接口后重写的run方法

public void run() {
        if (target != null) {
            target.run();
        }
    }

最后其实就是调用了作为参数穿进去的Ruuable类型参数的run方法。
这就是线程的一个基本实现,其实非常简单,就是Thread类继承了Runnable接口,当调用Thread类的start方法时候就会起一个线程,然后在这个线程里面调用run方法,就是辣么的简单!
写的比较仓促也比较直白,有错误的地方还请大家指出,接下来会抽时间陆续的进行更新,希望和小伙伴们一起学习进步。

你可能感兴趣的:(Java线程学习笔记(1))