JAVA多线程编程学习笔记(二)- 线程生命周期及控制线程

1.线程的生命周期

线程的生命周期有新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)、和死亡(Dead)5种状态


JAVA多线程编程学习笔记(二)- 线程生命周期及控制线程_第1张图片
线程状态转换

1.1新建和就绪状态

  • 当程序使用new关键字创建线程后,该线程处理新建状态,java虚拟机为其分配内存并初始化变量。
  • 当线程对象调用了start()方法后,该线程处于就绪状态,但是线程并未运行,等待Java虚拟机线程调度器的调度。==启动线程使用的是start()方法,而不是run()方法!== 如调用的某线程对象的run()方法,则该线程不再处于新建(new)状态。 start()方法只适用于处于新建状态的线程,不然会引发IllegalThreadStateException异常。

1.2运行和阻塞状态

  • 当处于就绪(Runnable)状态的线程获取了CPU资源,开始执行run()方法的线程执行体,则该线程处于运行状态,但该线程一般不会一直处于运行状态,系统会在一定时间后剥夺线程占用的资源,让其他线程获得执行的机会。
  • 当发生如下情况时线程会进入阻塞状态。
    • 线程调用sleep()方法主动放弃所有占用的处理器资源。
    • 线程调用了一个阻塞式IO方法,方法返回之前,该线程被阻塞。
    • 线程试图获得一个同步监视器,但该同步监视器正在被其他线程所持有,后面会详细介绍同步监视器。
    • 线程在等待某个通知(notify)。
    • 程序调用了线程的suspend()方法将线程挂起。但这个方法容易导致死锁,所以应该尽量避免使用该方法。
  • 当正在执行的线程被阻塞时,其他线程会获得被执行的机会。==被阻塞的线程会在合适的时候重新进入就绪(Runable)状态,而不是运行(Running)状态。==
    -发生以下特定的情况时可以解除线程的阻塞状态,让线程进入就绪状态。
    • 调用sleep()方法的线程经过了指定的时间。
    • 线程调用的阻塞式IO方法已经返回。
    • 线程成功地获得了试图取得的同步监视器。
    • 线程正在等待某个通知时,其他线程发出了一个通知。
    • 处于挂起状态的线程被调用了resume()恢复方法。
  • 调用yield()方法可以让运行的线程转入就绪状态。

1.3线程死亡

  • 线程结束后会处于死亡状态。以下是线程结束的三种方法
    • run()或call()方法执行完成,线程正常结束。
    • 线程抛出一个未捕获的Exception 或 Rrror。
    • 直接调用该线程的stop()方法结束线程,容易导致死锁,不推荐使用。
  • 检测某线程是否死亡,可以使用线程对象的 isAlive()方法,当线程处于就绪(Runnable)、运行(Running)、阻塞(Blocked)时,返回true;当线程处于新建(New)和死亡(Dead)状态时返回false。

2.控制线程

2.1 join线程

  • join()方法是由Thread类提供的让一个线程等待另一个线程完全完成的方法。当在某个程序执行流中调用其他线程的join()方法时,调用线程会被阻塞,直到join方法加入的join线程执行完为止。join()方法有以下三种重载形式:
    • join():等待被join的线程执行完成。
    • join(long millis):等待被join线程时间最长为millis毫秒。如果在mills毫秒内被join的线程还没执行结束,则不再等待

2.2 后台线程

  • 在后台运行,为其他线程提供服务,这种线程被称为"后台线程“(Daemon Thread)”,又成为“守护进程”,“精灵线程”。后台线程特点是如果所有的前台线程都死亡,后台线程会自动死亡。
    • setDaemon(true):该方法将指定的线程设置成后台线程。必须在start()方法前执行,否则会返回IllegalThreadStateException异常。
    • isDaemon():该方法用于判断指定线程是否为后台线程。

2.3 线程睡眠:sleep

  • Thread类的静态方法sleep(),可以让当前执行的进程暂停一段时间,并进入阻塞状态。
    • static void sleep(long millis):让当前执行的线程暂停mills毫秒,并进入阻塞状态。

2.4 线程让步:yield

  • yield()方法和sleep()方法有点相似,同样是由Thread类提供的静态方法,它可以让当前执行的线程暂停,但他不会阻塞该线程,只是将该线程转入就绪状态,从而让系统的线程调度器重新调度一次。当某个线程调用了yield()方法暂停后,只有与当前线程相同或者更高优先级的线程才会重新获得执行的机会。
  • yield()方法和sleep()方法的差异:
    • sleep()方法暂停当前线程后,会给其他线程执行的机会,不会理会其他线程的优先级;但yield()方法只会给优先级相同,或优先级更高的线程执行机会。
    • sleep()方法会将线程转为阻塞状态,直到经过阻塞时间会转入就绪状态;而yield()不会将线程转入阻塞状态,它只是强制将当前线程进入就绪状态。
    • sleep()方法声明抛出了InterruptedException异常,所以调用sleep()方法要么捕捉该异常,要么显示抛出该异常;yield()方法没有抛出任何异常。
    • sleep()方法比yield()方法有更好的可移植性,通常不建议使用yield()方法来控制并发线程的执行。

2.5 改变线程优先级

  • 每个线程执行的时候都具有一定的优先级,优先级较高的线程获得较多的执行机会
  • 每个线程默认的优先级都与它的父线程的优先级相同。
  • Thread类提供了 setPriority(int newPriority)、getPriority()方法来设置和返回指定线程的优先级,其中setPriority()方法的参数可以是一个整数,范围是1~10之间,但是优先级的级别需要操作系统的支持,比如windows 2000仅提供了7个优先级,所以应该使用如下三个静态常量代表优先级,来确保程序可移植性。
    • MAX_PRIORITY:其值为 10。
    • MIN_PRIORITY:其值为 1。
    • NORM_PRIORITY:其值为 5。

你可能感兴趣的:(JAVA多线程编程学习笔记(二)- 线程生命周期及控制线程)