线程start() 和 run()的区别

start() 和 run()的区别:

首先需要知道线程的几个状态以及多线程工作方式。

  • new 一个Thread,线程进入了新建状态,调用start() 方法,会启动一个线程并使线程进入了就绪状态,当分配到 时间片 后就可以开始运行了。start() 会执行线程的相应准备工作,然后自动执行run() 方法的内容,这是真正的多线程工作。
  • 而直接执行run() 方法,会把run 方法当成一个main 线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。

总的来说:调用start 方法方可启动线程并使线程进入就绪状态,而run 方法只是thread 的一个普通方法调用,还是在主线程里执行。

线程生命周期(状态):

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
Java中线程状态6种:
NEW:新建
RUNNABLE:可运行/就绪
BLOCKED :阻塞
WAITING :等待/不见不散
TIMED_WAITING :超时等待/过时不候
TERMINATED:终止

注意
BLOCKED/WAITING/TIMED_WAITING 这三种状态都不会获得CPU使用权

  1. 新建(new):新创建了一个线程对象。

  2. 可运行(runnable):线程对象创建后,当调用线程对象的 start()方法,该线程处于就绪状态,等待被线程调度选中,获取cpu的使用权。

  3. 运行(running):可运行状态(runnable)的线程获得了cpu时间片(timeslice),执行程序代码。注:就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;

  4. 阻塞(block):处于运行状态中的线程由于某种原因,暂时放弃对 CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被 CPU 调用以进入到运行状态。

阻塞的情况分三种:

阻塞状态(BLOCKED)
阻塞状态是指线程因为某种原因释放 cpu 使用权,也即让出了 cpu timeslice时间片,暂时停止运行。 直到线程进入可运行(runnable)状态,才有机会再次获得 cpu timeslice 转到运行(running)状 态。阻塞的情况分三种:

  • 等待阻塞(o.wait->等待队列)
    运行(running)的线程执行 o.wait()方法,JVM 会把该线程放入等待队列(waitting queue) 中。

  • 同步阻塞(lock->锁池)
    运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则 JVM 会把该线 程放入锁池(lock pool)中。

  • 其他阻塞(sleep/join)
    运行(running)的线程执行 Thread.sleep(long ms)或 t.join()方法,或者发出了 I/O 请求时, JVM 会把该线程置为阻塞状态。当 sleep()状态超时、join()等待线程终止或者超时、或者 I/O 处理完毕时,线程重新转入可运行(runnable)状态。

  1. 死亡(dead):线程run()、main()方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。

深入理解start方法:

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();

        /* 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方法,是一个本地方法,底层是c实现的===============
 private native void start0();

从整个方法上的注释看,start()使得该线程开始执行,Java虚拟机调用这个线程的run()方法,结果是两个线程会并发的运行:当前线程(调用start()方法的"主线程")与另一个线程(执行其run方法)

start()之后的代码的核心就是其中调用的start0()方法,下面看看start0()的定义:
private native void start0();
很明显这是一个只声明而未实现的方法,native表示调用本机的原⽣系统函数,native 方法往往意味着这个方法无法使用平台无关的手段来实现。所以,还是那句话,实际上线程的实现与 Java 无关,由平台所决定.

总结:

1、start()方法的具体流程:start方法(判断当前线程是不是首次创建,Java方法)->调用start0()方法(JVM)->通过JVM进行资源调度,系统分配->回调run()方法(Java方法)执行线程的具体操作任务
2、由于start()方法调用了JVM进行系统调度、系统分配等一系列操作,因此创建一个线程只能由start()来完成,而若直接调用run()方法,相当于是在调用一个普通方法

  • 9
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值