线程的生命周期

写在前面

线程的相关内容还是好久好久之前看过,现在又特地回头看看,并整理整理相关的笔记了。不过,重新回头来看,认识又将不一样。

线程的生命周期会经历以下几个状态:

新建new创建线程对象时

就绪:调用 start()方法时
运行:调用 run()方法时
阻塞: 多种原因可导致阻塞
死亡:多种原因

线程状态转换图:
这里写图片描述
由图可看出,解除阻塞后会重新进入就绪状态

新建、就绪状态

  1. 使用new 关键字创建一个线程时,该线程处于新建状态
  2. 线程对象调用 start()方法时,该线程处于就绪状态(线程获得CPU,等待执行)
  3. 线程的启动是从调用start()方法开始的,而不是run()方法
  4. 永远不要调用线程对象的run()方法
    • 如果直接调用 run() 方法,系统会把该线程对象当成普通对象,run()方法也将变成一个普通方法(而不是线程执行体)而立即执行。
    • 如果直接调用了 run() 方法,则该线程不再处于新建状态,不能再次调用 start()方法,否则会报IllegalThreadStateException异常
    • 如果直接调用了 run() 方法,则在run() 方法里不能直接通过this.getName() 方法获得线程名(此时获取的是对象名,因为此时已经没有线程体了,线程对象变成了普通对象),而是通过Thread.currentThread().getName() 获得。
  5. 如果希望线程对象调用start() 方法后立即执行run() 方法(线程体),可通过Thread.sleep(1)让主线程睡眠1毫秒,而给其他线程执行机会。

运行、阻塞状态

  1. 如果CPU是单核,则在任一时刻都只有一个线程在执行。当线程数据大于核数时,就会出现线程轮换。

  2. 所有桌面和服务器系统都采用的是抢占式调度策略,即当前线程在系统允许的执行时间之后,就给其他线程获得执行机会,且优先给优化级高的线程。

  3. 有些小型系统如手机会采用协作式调度策略,即只能当前线程主动放弃所占资源(调用sleep()或yield()方法)

  4. 线程从阻塞状态解除后只能转变为就绪状态,而就绪状态变为运行状态只能由系统线程调度转换。

  5. 线程调用了yield()方法也会重新进入就绪状态

发生以下情况时,线程将进入 阻塞状态
调用sleep()方法时。此时会放弃它所占用的处理器资源。【过了sleep指定时间不再阻塞】
调用一个阻塞式IO方法还没有返回之前,该线程被阻塞。【阻塞IO方法返回后不再阻塞】
试图获取一个正被其他线程所持有的同步监视器。【拿到监听器不再阻塞】
等待通知时(notify)。【其他线程调用了notify时不再阻塞】
调用suspend()方法将程序挂起时。【线程调用resume()方法时撤销挂起时不再阻塞】

线程死亡

线程死亡情况:

线程正常结束(run或call方法执行完)

线程抛出一个未捕获的Exception或Error

线程自己调用stop()方法(该方法容易导致死锁)

  1. 一旦子线程启动后,它就拥有和主线程相同的地位,不受主线程的影响。

  2. 线程对象只能调用一次start()方法,且只能在新建状态时才能调用。否则会抛出IllegalThreadStateException异常

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页