线程的创建与启动和线程的生命周期

一、线程的创建和启动
Java使用Thread类代表线程,所有的线程对象都必须是Thread类或者Thread子类的实例,每条线程的作用是完成一定的任务,实际上就是执行一段程序流。java使用run方法来封装这样的一段程序流。

(一)、继承Thread类创建线程类

通过继承Thread类来创建并启动多线程
1、定义Thread类的子类,并重写该类的run方法,该run方法的方法体就是代表了线程需要完成的任务。因此,我们经常把run方法称为线程执行体。
2、创建Thread子类的实例,即使创建了线程对象。
3、用线程对象的start方法来启动该线程。

继承Thread类创建线程和启动线程
public class ThreadSub  extends Thread{//线程类必须是Thread或者Thread的子类的实例
    @Override
    public void run() {//重写run方法   run方法的方法体就是线程的执行体。
        for (int i = 0;i < 10 ; i++){
            System.out.println(this.getName()+" "+i);//当前线程继承了thread类  可以直接调用其方法,
            //getName  获取当前线程名
        }
        System.out.println("执行线程"+this.getName()+"实例的run方法!");
    }
}

public static void main(String[] args) {
//currentThread是Thread类的静态方法,该方法总是返回当前正在执行线程对象
    System.out.println(Thread.currentThread().getName());
    ThreadSub sub = new ThreadSub();
    sub.start();
    new ThreadSub().start();
}
注意:使用继承Thread类的方法来创建线程类,多条线程之间无法共享线程类的实例变量。

(二)、实现runnable接口创建线程类

实现Runnable接口来创建并启动多条线程的步骤如下:
1、定义类并实现Runnable接口,重写run方法,run方法的方法体是线程的执行体。
2、创建Runnable实现类的实例,并以此实例作为Thread的targer来创建Thread对象,该Thread对象才是真正的线程对象。

启动线程是调用start()方法而不是run方法,请记住永远不要调用线程对象的run方法。 调用start()方法来启动线程,系统会把该run方法当成线程执行体来处理。 如果我们调用run方法,那么其他线程都无法执行,系统会把这个线程对象当做普通对象来操作。


实现runnable接口创建线程和启动线程
public class RunnableSubs implements Runnable {
    public void run() {//重写run方法   run方法的方法体就是线程的执行体。
        for (int i = 0;i < 10 ; i++){
            System.out.println(Thread.currentThread().getName()+" "+i);//当前线程继承了thread类  可以直接调用其方法,
            //getName  获取当前线程名
        }
        System.out.println("执行线程"+Thread.currentThread().getName()+"实例的run方法!");
    }
}

public static void main(String[] args) {
//currentThread是Thread类的静态方法,该方法总是返回当前正在执行线程对象
    System.out.println(Thread.currentThread().getName());
    RunnableSubs rs = new RunnableSubs();
     new Thread(rs,"线程1").start();
     new Thread(rs,"线程2").start();
}




两种创建线程实例和启动线程对比:
1、采用实现Runnable接口方式创建线程
(1)线程只是实现了Runnable接口还可以继承其他类。
(2)可以多个线程共享一个target对象,非常适合多个线程词处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰地模型,较好的体现了面向对象的思维。
(3)劣势:编程稍微有点复杂,访问当前线程必须使用 Thread.currentThread()。
2、采用继承Thread类来创建线程
(1)劣势:继承Thread类就不能在去继承其他父类;
(2)优势:就是编写相对简单,访问当前线程只需要this.currenrtThread();

我自己一般是采用的实现Runnable接口的方式来创建线程的.


二、线程的生命周期
当前线程被创建并启动以后,它既不是已启动就进入了执行状态,也不是一直就处于执行状态,在线程的生命周期中,它要经过新建(New)、就绪(Runnale)、运行(Running)、阻塞(Bloched)和死亡五种状态。尤其是当线程在启动以后,他不可能一直都在独自占用cpu,所以CPU需要在多线程之间切换,于是线程状态也会多次在运行、阻塞之间切换。

1、新建状态(New) : 程序使用new关键字来新建一个线程对象,该线程对象就处于新建状态,并且他和其他新建对象一样,java许你举为其分配内存空间,初始化成员变量的值。
ThreadSub sub = new ThreadSub();

2、就绪状态 : 当线程调用了start()方法之后,该线程就会进入就绪状态。这是虚拟机就会为该线程对象,创建方法调用栈和程序计数器。在这种状态线程并没有开始运行,只是表示出可以运行了。至于何时运行,取决于JVM里现成调度器的调度。

注意:不要对已经启动状态的线程对象再次调用start方法,否则将引发IllegalThreadStateException异常


3、运行状态
如果处于就绪状态的线程获得了CPU,开始执行run方法的线程执行体,则该线程处于运行状态。如果计算机只有一个CPU,在任何时刻只有一条线程处于运行状态。
现在系统都是采用的抢占式策略的,系统会分配给每一个可执行的线程一小段时间来执行处理任务,当时间用完时,系统会剥夺该线程所占据的资源,让其他线程获得执行的机会,当然在选择线程是系统会考虑线程的优先级。

4、阻塞状态
线程进入阻塞状态的场景:
(1)线程调用sleep方法啊主动放弃所占有的处理器资源。
(2)线程调用了一个阻塞式的IO方法,在该方法返回前,该线程被阻塞。
(3)线程获取同步监控器,但是同步监控器被其他线程所使用。
(4)线程在等待某个通知(notify)
(5)程序调用了线程的suspend方法将该线程挂起。不过这个方法容易导致死锁,所以程序应该尽量避免使用该方法。

被阻塞的线程在适当的时机进入就绪状态,并不是马上进入运行状态,而是重新等待县城调度器再次调度它才能进入运行状态。

5、线程死亡状态
(1)run()方法执行结束,线程正常结束。
(2)线程抛出异常Exception或者错误Error
(3)直接调用该程序的stop()方法来结束该线程--该方法容易导致死锁,不推荐使用。

线程状态转换图



本文章参考书籍:疯狂java

版权声明:【分享也是一种提高】个人转载请在正文开头明显位置注明出处
https://blog.csdn.net/java_student_x/article/details/80626226



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值