java中Thread类的源码_JavaSE第九十九讲:Thread类源码深度剖析

在上一讲内容中,我们已经学习了实现线程的两种方式,但是到底这两种方式有什么关系?为什么实现线程的两种方式中继承Thread类的那个类必须要重写run()方法?为什么用start()方法来启动线程?基于这些问题我们必须去研究线程Thread类的源代码,这样才能只其然且知其所以然,这一讲我们就来讲解Thread类源代码。

1.查看Thread类的源代码可以发现它也实现了Runnable接口

public

class Thread implements Runnable

1) 因为Runnable接口有一个run()方法,所以Thread类实现了run()方法

查看Thread类的关键代码:Thread类的构造方法:public Thread()和 public Thread(Runnable target)

public Thread() {

init(null, null, "Thread-" + nextThreadNum(), 0);

}

public Thread(Runnable target) {

init(null, target, "Thread-" + nextThreadNum(), 0);

}

比较这两个构造方法可以发现,不带参数的构造方法其实是接受一个Runnable类型的 target 参数为空。

继续跟踪nextThreadNum()方法

private static int threadInitNumber;

private static synchronized int nextThreadNum() {

return threadInitNumber++;

}

返回threadInitNumber++,threadInitNumber是一个什么东西呢?

写一个段代码,在上一讲中程序ThreadTest2的main方法中打印出两个线程的名字,用getName()方法

Thread t1 = new Thread(new MyThread());

System.out.println(t1.getName());

t1.start();

Thread t2 = new Thread(new MyThread2());

System.out.println(t2.getName());

t2.start();

输出:Thread-0

Thread-1

继续Thread类的跟踪getName()方法

public final String getName() {

return String.valueOf(name);

}

private charname[];

name是一个char类型的数组

private void init(ThreadGroup g, Runnable target, String name,

long stackSize)

this.name = name.toCharArray();

name是init()方法中被赋值的

所以,在Thread()的构造方法中 "Thread-" + nextThreadNum() 这个参数会赋给name,由于nextThreadNum()是一个静态的成员变量,所以会被所有的线程所共享,所以会输出Thrad-0,从0开始标记一个线程的名称。

2. 查看Thread类的其他构造方法:

1). public Thread(String name)

Allocates a new Thread object. This constructor has the same effect as Thread(null, null, name).

[分配一个新的线程对象,name是新线程的名字]

写一个这种构造方法的Demo

package com.ahuier.thread;

public class ThreadTest {

public static void main(String[] args) {

Thread1 t1 = new Thread1("first Thread");

Thread2 t2 = new Thread2("second Thread");

System.out.println(t1.getName());

System.out.println(t2.getName());

t1.start();

t2.start();

}

}

class Thread1 extends Thread{

public Thread1(String name){

super(name);

}

@Override

public void run() {

for(int i = 0; i < 100; i++){

System.out.println("hello world:" + i);

}

}

}

class Thread2 extends Thread{

public Thread2(String name){

super(name);

}

@Override

public void run() {

for(int i = 0; i < 100; i++){

System.out.println("welcome" + i);

}

}

}

编译执行结果不全贴出来了:

first Thread

second Thread

welcome0

welcome1

...

3.  为什么要用start()方法来启动线程,查看他们的源代码

查看Thread类的start()方法:

public synchronized void start() {

/**

* This method is not invoked for the main method thread or "system"

* group threads created/set up by the VM. Any new functionality added

* to this method in the future may have to also be added to the VM.

*

* A zero status value corresponds to state "NEW".

*/

if (threadStatus != 0)

throw new IllegalThreadStateException();

group.add(this);

start0();

if (stopBeforeStart) {

stop0(throwableFromStop);

}

}

private native void start0();直接查看start0()方法是一个本地的方法: private native void start0();看不到start()方法调用run()方法了,所以它是交给底层C语言去实现了,底层CPU帮我们启动一个线程,并且帮我们分配线程资源,

所以线程一旦启动我们是没有办法将其关闭等操纵它的。

4. 查看Thread类的run()

public void run() {

if (target != null) {

target.run();

}

}

private Runnable target;target是Runnable对象,它是通过Thread的构造方法给其赋值的,

public Thread(Runnable target) {

init(null, target, "Thread-" + nextThreadNum(), 0);

}查看init方法中target的操纵

this.target = target;所以可以确定它是target是通过 new Thread(Runnable target) 的方式传递过来的。

当我们使用第一种生成线程对象方式的时候,它里面所维护的Runnable对象是为空的,此时run()中的if()语句是不执行的,所以想要启动线程我们必须重写run()方法,所以当我们使用第二种生成线程对象的方式的时候,它里面所维护的就是我们传过去的Runnable对象。此时if语句执行,调用了run()方法。

5. 总结

1) Thread类也实现了Runnable接口,因此实现了Runnable接口中的run方法;

2) 当生成一个线程对象时,如果没有为其设定名字,那么线程对象的名字将使用如下形式:Thread-number,该number将是自动增加的,并被所有的Thread对象所共享(因为它是static的成员变量)。

3) 当使用第一种方式来生成线程对象时,我们需要重写run方法,因为Thread类的run方法此时什么事情也不做。

4) 当使用第二种方式来生成线程对象时,我们需要实现Runnable接口的run方法,然后使用new Thread(new MyThread())(假如MyThread已经实现了Runnable接口)来生成线程对象,这时的线程对象的run方法就会调用MyThread类的run方法,这样我们自己编写的run方法就执行了。

6. 掌握了以上的知识,现在我们接下来就来研究一下线程中的一些特性,线程的特性主要是由于线程的不确定性引起的:一旦线程启动,则它能操纵和停止它

未完待续,持续更新中......

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值