Java thread(2)

 

    这一块主要是从Thread类源码的角度来分析两种线程的实现方式,这里分析的也仅仅是最基本的部分。

    就从线程的启动函数 start方法开始分析 只是分析最主要的部分

    在start()方法中,除了group的相关操作(这个后面再分析),最核心的部分就是执行了start0方法这个start0方法是native方法,表示这里需要与操作系统进行交互,具体的还没有深入研究,貌似是申请一些资源,启动一个新的线程,并且在新的线程中会对run()方法进行调用。所以我们用到的start方法说白了就是以一个线程的方式来调用run方法。

    接下来再分析run()方法,这个要分两种情况来讨论了。

    1、 通过继承Thread类,重写run方法来生成一个线程的情况下,我们甚至都不用看thread中run方法的源码了,因为这个方法反正都是要被重写的,只要将其中的内容换成我们自己的内容就行。要是继承了Thread但没有重写run方法会怎样?那么这个线程什么都不会做。

    2、 为何什么都不会做?在第二种情况下,我们会通过实现一个Runnable接口然后将这个Runnable接口作为形参来初始化一个线程,我们具体来看run函数的源码:

public void run() {

if (target != null) {

target.run();

}

}

    这个很容易理解,如果target不为空的时候就执行target的run方法,如果target为空的时候就什么都不执行,构造函数为Thread(Runnable target),容易猜到,target实际就是一个Runnable接口。

    这个是target的定义部分private Runnable target;

    我们再看传入runnable接口生成线程对象所用到的构造方法:

public Thread(Runnable target) {

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

}

    这个方法主要是执行了init函数,具体的init函数的声明如下:

    private void init(ThreadGroup g, Runnable target, String name,long stackSize)

    只要看到其中的这句就ok了:this.target = target;

    将参数中传进来的Runnable接口赋值给本Thread类的target属性。那个String name是传递进来的线程的名称,默认是 Thread- +number的形式。

    这样以来我们回头看run方法也就很清楚了,采用这种方式的时候,run方法实际上执行的是我们传入的Runnnable接口中的run方法,也就是线程主要执行的任务。

采用第一种方法的时候,构造函数为

public Thread() {

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

}

    此时原本的Thread类中的target为null,要是我们不重写run方法的话,就会什么都不执行,有了上面的分析,对于两种方式的线程时间的原理,应该就比较清晰了。

    两种方式的比较:

    1 两种方法均需要执行start方法 为线程分配系统资源并执行run方法

    2 用哪种方式实现,要视具体情况而定,当一个线程已经继承了另一个类的时候(java中仅允许单继承)就要用实现一个Runnable接口的方式来生成线程。(多继承可能会引起语义的不明确 比如两个父类都有同名的方法 子类不知道调用的是哪个父类当中的 但是继承多个接口(接口 不是抽象类)的时候 由于方法只有在子类中的一种实现形式 因此不会引起语义的混乱)

    3 线程的消亡不能通过使用stop方法来结束(使用stop方法是不安全的),只能等run方法运行完线程才会自动结束。

    4 因为线程一旦运行起来,通常就不收控制了,用stop方法停止一个线程是不安全的方法,一般情况下不要使用,于是通常停止线程的方法是通过while循环,将run方法放在while循环中,一旦符合了某个条件,就通过break跳出循环,结束线程。

posted @ 2014-07-02 22:29  hessen  阅读(452)  评论(0编辑  收藏  举报