Thread 的start()与run()的区别与联系

本文详细解释了Java中进程与线程的概念、多线程机制、线程的创建与调用方式及其状态转换过程,对比了start()与run()方法的区别。

相关概念

  • 进程:进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动;进程是系统进行资源分配和调度的一个独立单位
  • 线程:线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源
  • 多线程:一个程序或进程中包含多个线程
  • 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时
  • 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时
  • 多线程机制:将CPU调度时间分为多个时间片,采用时间片轮询,即每个线程只运行一个时间片的时间,再调用下一个线程运行;即宏观上所有线程并发执行
  • java.lang.Thread:java 中通过 Thread 模拟线程实现,实现Runnable 接口
  • start():作用启动线程,实现多线程运行;线程启动后无需等待当前线程的方法体 run() 方法执行完毕,可继续执行 start() 后的代码;调用 start() 方法后线程处于就绪状态(可运行状态),并没有运行,等待VM调用,一旦得到时间片,开始执行 run() 方法体中的内容(线程需要完成的任务),直至线程运行结束(若出现阻塞,则等待唤醒再次进入就绪状态,等待CPU的再次调用)
  • run():线程的方法体,方法内容为线程需要执行的内容,线程运行时通过调用run()方法完成执行的内容;如果直接调用 run() 方法,程序中依然只有主线程这一个线程(方法在主线程中运行),其程序执行路径还是只有一条,还是要顺序执行,还是要等待run方法体执行完毕后才可继续执行下面的代码,这样就没有达到写线程的目的(线程的目的是并发而不是串行)
  • 联系:start()方法启动线程将自动调用 run()方法,这是由jvm的内存机制规定的。并且run()方法必须是public访问权限,返回值类型为void.
  • 线程的创建方式
// 1. 继承 Thread ,此处 Thread 是一个类,Thread 类实现 Runnable 接口:
// 子类通过覆盖重写父类中的 run 方法体中的内容实现当前写成需要完成的任务
public class ThreadTest extends Thread{

    @Override
    public void run() {
        super.run();
    }
}
// 2.实现 Runnable 接口,需实现 run () 方法
public class RunnableTest implements Runnable{

    public void run() {

    }
} 
  • 线程的调用方式
// 1.继承 Thread 类
    public static void main(String[] args) {
        ThreadTest test = new ThreadTest();
        test.start();

    }
// 2.实现 Runnable 接口
    public static void main(String[] args) {
        RunnableTest test = new RunnableTest();
        Thread thread = new Thread(test);
        thread.start();
    }
  • 线程的状态及线程状态间的转换
    创建(new Thread()) –>
    就绪(执行start()方法后,等待CPU调度)–>
    运行 ( CPU执行)–>
    阻塞 ( sleep wait 等,等待资源唤醒,重进进入就绪队列)–>
    结束(运行结束)

线程间状态切换

为什么不直接运行run()方法,而要执行start()方法

一、从多线程的实现原理分析
  • 多线程是为了实现线程间并发,提高CPU的使用率
  • 直接运行 run() 方法,在主线程中调用 Thread 的 run() 方法,等该 Thread 的 run() 方法执行完毕后才会继续执行之后的方法,是逻辑上的串行,而没有实现线程的并发
  • 执行 start() 则是启动当前的线程,不是立即执行线程中的内容,而是让线程处于就绪状态,等VM(CPU的调度),线程得到时间片会自动运行 run() 方法中的内容;执行线程的 start() 可以继续执行调用位置之后的代码,从而实现启动多个线程的目的,实现并发
二、从源码实现中分析
    /**
     * Thread start() jdk.1.8.0 源码
     */
    /**
     * 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 */
            }
        }
    }
    // 调用了 native 的 start0 方法启动线程
    private native void start0(); // native 本地方法
方法注释
  • start 是线程开始执行的原因;JVM 调用当前线程的 run 方法
  • 结果是两个线程同时运行:
  • 当前线程(调用 start方法获取响应 )
  • 另一个线程(执行当前线程的run方法 )
    /**
     * Thread run() jdk.1.8.0 源码
     */
    /**
     * 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();
        }
    }
    /* What will be run. */
    private Runnable target;
    // 从源码上只是执行了当前 target 对象的run() ,而没有并发的相关实现
方法注释
  • 如果该线程是使用独立的 Runnable 的 run 对象,那么 Runnable对象的run方法被调用;
  • 否则,当前的方法什么都不做,直接返回;
  • 子类必须重写 run 方法;
总结
  • target是一个Runnable对象;
  • run()就是直接调用Thread线程的Runnable成员的run()方法,并不会新建一个线程
    即 start 方法新建一个线程来调用当前线程的run方法

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值