java多线程之Thread类剖析

版权声明:转载请注明:beOkWithAnything总结 https://blog.csdn.net/swq463/article/details/85138070

这篇文章的代码都是不完整的伪代码,只是为了说明问题截取出来的,切记切记!!!


实现线程的两种方式:

  • class MyThread extends Thread类 { }
class MyThread extends Thread {
    @Override
    public void run() {
        //自己写代码
    }
}
  • class MyThread implements Runnable { }
class MyThread implements Runnable {
    @Override
    public void run() {
        //自己写代码  
    }
}
  • 用 main()函数测试多线程:
public class Demo {
    public static void main(String[] args) {  
        Thread t = new Thread( new MyThread() ); //只是为了说明问题,这里就不创建两个对象了
        t.start(); // 调用start()方法
    } 
}

不管用哪种办法实现多线程,都是调用了Thread类的start()方法,然后我 Ctrl + 左键单击 查看了 start()方法的实现

下面列出了部分我觉得重要的属性和方法:

// Runnable接口的内容:只有一个abstract的run()方法等待实现了此接口的类去具体书写
public interface Runnable {
    public abstract void run();
}

// Thread类的部分内容:

public class Thread implements Runnable { // 首先Thread类实现了Runnable接口,则必有run()方法的实现

    private volatile String name; // 线程的name属性
    
    /* What will be run. */
    private Runnable target; // Runnable类型的target属性???干什么用的呢???

    /* The group of this thread */
    private ThreadGroup group; // 线程组group属性

    public Thread(String name) { // 其中一个构造方法,发现创建一个线程时,调用了init()方法
        init(null, null, name, 0);
    }

    private void init(ThreadGroup g, Runnable target, String name.....) { // init()方法的部分内容

        this.name = name; // 把线程的名字赋给name属性

        ........

        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();

        ........
        this.target = target; // 把传入的new MyThread()赋给target???
    }

    public synchronized void start() { // 找到了Thread对象调用的start()方法

        group.add(this); // group属性在这里使用,把当前对象加入到线程组

        boolean started = false; // 标记线程的一个状态
        try {
            start0();  // start0()方法用来启动线程
            started = true;
        } finally {
            .............
        }
    }

    private native void start0(); // start0()在这里,为什么是这样的?native是与C++联合开发的时候用的(下面解释)

    @Override
    public void run() { // 实现了Runnable接口的唯一run()方法
        if (target != null) {
            target.run(); // 如果target属性不为空,就调用target的run()方法。???
        }
    }

    public final String getName() {
        return name; // 用getName()能得到线程名字
    }
}

native 关键字 表示这个方法是原生函数: native关键字的函数都是操作系统实现的

也就是说native 后的函数的实现不是用java写的。

也就是说这个方法是用C/C++语言实现的,并且被编译成了DLL,由java去调用。

Java无法直接访问到操作系统底层,可以将native方法比作Java程序同C程序的接口

native关键字详解的链接在这里!!!

读了Thread类的内容后我还是很迷糊:

我们在main函数中调用的一直都是Thread类的start()方法啊,这个run()方法是怎么工作的呢?

既然start0()是c/c++写的,那也不容易去研究这个方法的实现了,可是

既然Thread类中重写了Runnable接口的run()方法,但他是怎么调用的呢?


分析:

  • 自己创建的MyThread类要么直接实现Runnable接口,要么继承Thread类间接实现Runnable接口
class MyThread extends Thread {
    @Override
    public void run () {
        //自己写代码
    }
}
  • main函数创建Thread对象时 有时会传入一个 实现了Runnable接口并重写了run()方法 的实例对象

public static void main(String[] args) {  
        Thread t = new Thread( new MyThread( ) );
}

  • 但不论哪种构造方法都会调用init()函数

public Thread(String name) {
        init(null, null, name, 0); // 这个构造函数没有传入参数 target,给init()函数传值为null
}

public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0); // 构造函数会把target对象传给init()函数
}

  • 在init()函数中会把传入的Runnable对象赋给 this.target 属性

private void init(ThreadGroup g, Runnable target, String name.....) {
        this.target = target;
}

  • start()方法实际上是通过本地方法start0()方法启动线程的

public synchronized void start() {
            start0();  // start0()会新运行一个线程,新线程会调用run()方法。
}

  • run()方法会直接调用Thread线程的Runnable成员的run()方法,并不会新建一个线程。

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

  • 调用start()方法和直接调用run()方法的区别: 

Thread.currentThread().getName()是用于获取“当前线程”的名字。当前线程 是指正在cpu中调度执行的线程。

单独调用run()的话:会在当前线程中执行run()方法(主线程main),并不会启动新线程:

调用start()方法会启动一个新线程:"t2"线程,并在新线程"t2"中运行run()方法:

  • 新建线程应该是 start0()函数完成的操作!!!

猜你喜欢

转载自blog.csdn.net/swq463/article/details/85138070