首页 >> 方法大全

深入线程Thread类的start()方法和run()方法

2022-05-21 方法大全 313 作者:考证青年

一、初识

Java 线程是通过 java.lang 实现的。班级。当VM启动时,main方法定义了一个线程。可以通过创建实例来创建新线程。每个线程通过特定对象对应的方法run()来完成自己的操作,方法run()称为线程体。通过调用类的 start() 方法启动线程。

在Java中,线程通常有五种状态,创建、就绪、运行、阻塞和死亡。

首先是创建一个状态。线程对象生成时,并没有调用该对象的start方法,也就是正在创建的线程。

第二个是就绪状态。当调用线程对象的start方法时,线程进入就绪状态,但是线程调度器此时还没有将线程设置为当前线程,此时处于就绪状态。线程运行后,从等待或休眠返回后也处于就绪状态。

第三个是运行状态。线程调度器将处于就绪状态的线程设置为当前线程。此时线程进入运行状态方法,开始运行run函数中的代码。

第四是阻塞状态。当一个线程在运行时,它会被挂起,通常是等待一定的时间发生(例如,一个资源准备好),然后再继续运行。 sleep、wait等方法都会导致线程阻塞。

第五个是死亡状态。如果一个线程的 run 方法结束或 stop 方法被调用,线程就会死掉。对于已经死亡的线程,不能再使用 start 方法使其准备就绪。

二、start() 方法

1、为什么需要start方法;它有什么作用?

start()方法启动线程,真正实现了多线程操作。

角色

start方法是将线程从NEW状态改变为状态。当线程创建成功时,线程处于NEW(新)状态。如果不调用 start() 方法,线程始终处于 NEW 状态。调用start()后,变为状态,线程可以运行了。

2、调用start()方法后,线程是否立即执行?

线程不会立即执行;准确的说,调用start()方法后,线程的状态是“READY(就绪)”状态,而不是“(运行)”状态(具体说下线程的状态。等待CPU调度,不同JVM有不同的调度算法,线程什么时候被调度是未知的,所以start()方法的调用顺序不能决定线程的执行顺序

注意:

因为在线程的生命周期中,线程的状态只会发生一次NEW ---->,因此,一个线程只能调用一次start()方法,启动一个线程是非法的线程多次。特别是当线程执行完毕后,就无法重新启动了。

三、run()方法

1、run方法是什么方法? run方法和start方法有什么关系?

run() 方法作为普通方法调用

run()其实是一个常用的方法,但是当线程调用start()方法时,一旦线程被CPU调度并运行,线程就会调用run()方法;

2、run()方法的执行是否需要线程调用start()方法?

如前所述,run()方法是一个普通的对象方法,所以可以在没有线程调用start()的情况下调用它。线程对象可以随时随地调用run方法。

#:

  Thread t1 = new Thread(new MyTask(1));
  Thread t2 = new Thread(new MyTask(2));
     t1.run();
     t2.run();

复制

上面的输出是固定的:

计数值:1

计数值:2

再看一个例子:

 Thread t1 = new Thread(new MyTask());
 Thread t2 = new Thread(new MyTask());
     t1.start();
     t2.start();

复制

这个输出不是固定的方法,因为线程的执行是不可预测的。运行结果可能不同。

类:

//实现Runnable接口
class MyTask implements Runnable{
    int count;
    public MyTask(int count) {
        this.count=count;
    }
    @Override
    public void run() {
        System.out.println("count的值:"+count);
    }
}

复制

#:

1、使用start方法启动线程

    public class Main {  
      
        public static void main(String[] args) {  
            Thread t1 = new Thread(new T1());  
            Thread t2 = new Thread(new T2());  
            t1.start();  
            t2.start();  
        }  
      
    }  
      
    class T1 implements Runnable {  
        public void run() {  
            try {  
                for(int i=0;i<10;i++){  
                    System.out.println(i);  
                    Thread.sleep(100);  //模拟耗时任务  
                }  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
      
    class T2 implements Runnable {  
        public void run() {  
            try {  
                for(int i=0;i>-10;i--){  
                    System.out.println(i);  
                    Thread.sleep(100);  //模拟耗时任务  
                }  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
    }  

复制

结果:

在这里写图片说明

龟背竹图片和养殖方法方法_方法_流产方法有几种方法

表示两个线程同时执行。

2、使用run方法先启动线程

把上面的start()改成run()

    public class Main {  
      
        public static void main(String[] args) {  
            Thread t1 = new Thread(new T1());  
            Thread t2 = new Thread(new T2());  
            t1.run();  
            t2.run();  
        }  
      
    }  

复制

在这里写图片说明

表示这两个线程实际上是按顺序执行的。

总结:

通过 1和 sum可以知道start方法是用来启动线程的,可以实现并发,而run方法只是一个普通的方法,不能实现并发,但是会在并发执行的时候被调用。

说到这里,不知道各位朋友是否明白这两种方式的区别。有问题可以留言交流。

四、start()方法和run()方法源码分析(基于JDK1.7.0_40)

    public synchronized void start() {  
        // 如果线程不是"就绪状态",则抛出异常!  
        if (threadStatus != 0)  
            throw new IllegalThreadStateException();  
        // 将线程添加到ThreadGroup中  
        group.add(this);  
        boolean started = false;  
        try {  
            // 通过start0()启动线程,新线程会调用run()方法  
            start0();  
            // 设置started标记=true  
            started = true;  
        } finally {  
            try {  
                if (!started) {  
                    group.threadStartFailed(this);  
                }  
            } catch (Throwable ignore) {  
            }  
        }  
    }  

复制

public void run() {  
    if (target != null) {  
        target.run();  
    }  
} 

复制

五、真正懂类

类的对象其实是一个java对象,但是类的每个对象都对应一个线程。类的对象是提供给用户操作线程和获取线程的信息。真正的低级线程用户是不可见的。

因此,当一个线程结束并死亡时,仍然可以调用对应的对象,除了start()方法(死掉的线程不能再次启动),例如run()、()、()等。

//简单起见,使用匿名内部类的方法来创建线程
    Thread thread = new Thread(){
        @Override
        public void run() {
            System.out.println("Thread对象的run方法被执行了");
        }
    };
    //线程启动
    thread.start();
    
    //用循环去监听线程thread是否还活着,只有当线程thread已经结束了,才跳出循环
    while(thread.isAlive()){}
    //线程thread结束了,但仍能调用thread对象的大部分方法
    System.out.println("线程"+thread.getName()+"的状态:"+thread.getState()+"---优先级:"+thread.getPriority());
    //调用run方法
    thread.run();
    //当线程结束时,start方法不能调用,下面的方法将会抛出异常
    thread.start();

复制

参考文献

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了