java线程之start方法与run方法解析以及currentThread与this解析

java线程之start方法与run方法解析以及currentThread与this解析

  1. start方法与run方法
  2. currentThread与this

    提示
    博主:来自火星的萨满_906285288
    博客地址:http://blog.csdn.net/qq_29924041


start方法与run方法解析

众所周知线程一般情况下都是通过start方法来进行执行的,只有调用了start方法之后,才会生成一个线程,在这里去源码里面查看一下start方法到底走了哪一步

/**
     * Causes this thread to begin execution; the Java Virtual Machine
     * calls the <code>run</code> method of this thread.
     * <p>
     * The result is that two threads are running concurrently: the
     * current thread (which returns from the call to the
     * <code>start</code> method) and the other thread (which executes its
     * <code>run</code> method).
     * <p>
     * It is never legal to start a thread more than once.
     * In particular, a thread may not be restarted once it has completed
     * execution.
     *
     * @exception  IllegalThreadStateException  if the thread was already
     *               started.
     * @see        #run()
     * @see        #stop()
     */
    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();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

这里我们可以看到解释部分,调用此方法的时候,会调用一个start0方法,这是一个native方法,native方法也就是jni接口,在方法头部分解释的很清楚,调用此方法的时候会让java虚拟机调用这个线程的run方法,如果我没有猜错的话,虚拟机在底层同样是调用了类似c中的pthread这样一个东西才能得以创建线程。但是在这个方法里面有一点需要注意的地方,就是在start方法里面其实是有状态标志位进行判断的,如果进行了多次start方法之后,会抛出异常。

下面在展示下run方法:

/**
     * If this thread was constructed using a separate
     * <code>Runnable</code> run object, then that
     * <code>Runnable</code> object's <code>run</code> method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of <code>Thread</code> should override this method.
     *
     * @see     #start()
     * @see     #stop()
     * @see     #Thread(ThreadGroup, Runnable, String)
     */
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }

run方法就比较简单,只是对一个target的判空和调用的过程,这个target事什么呢?

 /* What will be run. */
    private Runnable target;

在前面有一个局部变量,target原来是一个接口类型,这个Runable接口中有且只有一个方法,也就是run方法,在前面关于线程构造函数的博客中可以看到,线程在调用的时候可以通过构造参数讲Runable传进去,所以才会有在run方法中调用Runable的run方法。
看到这里就很明显了,run方法其实就是普通的类方法调用。

那么问题来了,如果new Thread().start();和new Thread().run();是都在主线程中还是一个是在主线程中,一个在子线程中???
简单测试一下

package com.zzf.java.charpter1.part3;

import java.util.Random;

public class MyThread extends Thread{
    @Override
    public void run() {
        // TODO Auto-generated method stub
        super.run();
        for (int i = 0; i < 10; i++) {
            int time = (int) (Math.random()*1000);
            try {
                sleep(time);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"\t:"+i);
        }
    }
}
package com.zzf.java.charpter1.part3;
/**
 * 
 * @author zhouzhangfei
 * 在多线程中,既然封装了run方法,又封装了start方法,那么这两者之间是有什么区别和联系的呢??
 * start方法是去启动异步的过程,实际上也会去调用run方法,只是异步
 * 但是如果直接去调用run方法的话,这个时候就不是异步调用,也就是还是在主线程中去调用run方法
 * 并且start的调用顺序其实并不是线程执行的调用顺序
 */
public class MyThreadTestMain_run {
    public static void main(String[] args) {
        MyThread myThread2 = new MyThread();
        myThread2.setName("MyThread2");
        myThread2.start();
        MyThread myThread = new MyThread();
        myThread.setName("MyThread");
        myThread.run();

//      for (int i = 0; i < 10; i++) {
//          int time = (int) (Math.random()*1000);
//          try {
//              Thread.sleep(time);
//          } catch (InterruptedException e) {
//              // TODO Auto-generated catch block
//              e.printStackTrace();
//          }
//          System.out.println(Thread.currentThread().getName()+"\t:"+i);
//      }
    }
}

输出的结果为:

MyThread2   :0
main    :0
main    :1
MyThread2   :1
MyThread2   :2
main    :2
main    :3
MyThread2   :3
main    :4
MyThread2   :4
MyThread2   :5
main    :5
main    :6
MyThread2   :6
MyThread2   :7
main    :7
main    :8
MyThread2   :8
main    :9
MyThread2   :9

可能会很奇怪,为毛线没有MyThread打印啊。MyThread调用的是run,而MyThread调用的是start。而调用了run方法的可以看到,其线程名字为main,因此它压根就没有创建子线程,仅仅是创建了一个对象,调用了一个普通的方法。
所以总结一下:
1:调用了start的方法的线程:start—->native层创建一个线程—->通过jni接口在去回调run方法以及其他相关的属性设置
2:调用了run的方法:run—–>主线程中去执行
所以千万要注意什么是线程,哪一个是线程。


currentThread与this解析

先上一段代码:

public class MyThread extends Thread {
    @Override
    public void run() {
        // TODO Auto-generated method stub
        super.run();
        System.out.println(Thread.currentThread().getName());
    }
}

这里的currentThead肯定是当前的线程,但是这个当前的线程指的是什么状态的当前???当前对象的线程??当前调用此方法的线程??
那在看一下下面这个方法:

public class MyThread extends Thread {
    @Override
    public void run() {
        // TODO Auto-generated method stub
        super.run();
        System.out.println(this.getName());
    }
}

有很多同学说,对!这两个方法在这里是一样的。那么我想问,在别的地方还会一样么???

不多谈!先来波概念:currentThread返回的是代码段正在被哪一个线程调用,而this指的是当前的线程的对象,所以要进行区分
currentThread指的是当前的这段代码段是被谁在调用,那么就是哪一个线程的,而this仅仅指的的当前的对象的,我们指的在线程创建的时候就是会默认去创建一个类似Thread-0这样的格式的名字的。this.getName指的就是这个名字

package com.zzf.java.charpter1.part9;
/**
 * 
 * @author zhouzhangfei
 *
 */
public class MyThread extends Thread{
    @Override
    public void run() {
        // TODO Auto-generated method stub
        super.run();
        System.out.println();  //当前线程对象的名字,一般情况下,名字都是固定的,但是调用的对象就可以不一样
        System.out.println("this.name:"+this.getName()+"\t"+"currentThread.getName:"+Thread.currentThread().getName());  //当前代码段被哪一个线程调用的名字
        System.out.println("this.id:"+this.getId()+"\t"+"currentThread.getId:"+Thread.currentThread().getId());
    }

}
package com.zzf.java.charpter1.part9;
/**
 * 了解一下currentThread与this的区别
 * currentThread返回的是代码段正在被哪一个线程调用,而this指的是当前的线程的对象,所以要进行区分
 * @author zhouzhangfei
 *
 */
public class Main {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName());
        System.out.println("=======");
        MyThread myThread = new MyThread();
        Thread thread = new Thread(myThread,"A");
        Thread thread2 = new Thread(myThread,"B");
        Thread thread3 = new Thread(myThread,"C");
        thread.start();
        thread2.start();
        thread3.start();
        myThread.start();
    }
}

输出的结果为:

main
=======

this.name:Thread-0  currentThread.getName:A
this.id:9   currentThread.getId:10

this.name:Thread-0  currentThread.getName:B
this.id:9   currentThread.getId:11

this.name:Thread-0  currentThread.getName:C
this.id:9   currentThread.getId:12

this.name:Thread-0  currentThread.getName:Thread-0
this.id:9   currentThread.getId:9

从上面的输出结果中可以看到,对于new出来的对象的话,这个时候其ID和name都是固定下来的为9和Thread-0;
但是如果它没有调用start方法的话,这个就时候就不能把它当做线程来看,只能当做一个普通的对象来看,它拥有一个很平凡的run方法,没有任何奇异之处。
而在后面new出了几个线程来调用这个myThread对象,这个时候currentThread很明显,对应的是其他的名字,ID对应的也是不同的,因此只有当自己的线程对象start方法调用的时候,currentThread与this才会指向同一个对象,如果被别的线程去调用的话,其currentThread与this不会去指向同一个线程对象。
注意:
使用的时候千万注意判别哦。很多时候搞不好就会出现错误的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值