首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java--五态模型&控制线程

Java--五态模型&控制线程

作者头像
SuperHeroes
发布2018-05-22 16:15:07
8870
发布2018-05-22 16:15:07
举报
文章被收录于专栏:云霄雨霁云霄雨霁

上一篇----线程的创建和启动

五态模型:在线程的生命周期中,有五种状态,分别是新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)。

新建和就绪态:

当程序使用new关键字创建一个线程后,该线程就处于新建状态;当调用start()方法后,该线程就处于就绪态。

启用线程使用start()方法,不能使用run()方法!如果直接调用run()方法,系统把线程对象当作普通对象,run()方法当作普通方法而不是线程执行体。

只能对处于就绪态的线程调用start()方法,否则将引发IllegalThreadStateException异常。

如果希望调用子程序的start()方法后子线程立即执行,可以使用Thread.sleep(1)让当前运行的线程睡眠1毫秒。因为这一毫秒CPU不会空闲,它会去执行另一个就绪的线程。

运行态和阻塞态:

处于就绪态的线程获得CPU进入运行态。但一个线程一般不会一直处于运行态,当发生下面的情况时,线程将进入阻塞态:

· 线程调用sleep()方法主动放弃所占用的处理器资源。

· 线程调用一个阻塞式IO方法,在该方法返回前该线程被阻塞。

· 线程试图获得一个同步监视器,但该监视器正被其他线程所持有。

· 线程在等待某个通知(notify)。

· 程序调用了线程的suspend()方法将线程挂起。但这个方法容易导致死锁,不建议使用。

针对上面的几种情况,当发生一下情况时线程会解除阻塞态重新进入就绪态:

· 调用sleep()方法经过了指定时间。

· 线程调用的阻塞式IO已经返回。

· 线程成功地获取了试图取得的同步监视器。

· 线程正在等待某个通知时,其他线程发出了通知。

· 处于挂起的线程被调用了resume()恢复方法。

注意:线程从阻塞态只能进入就绪态,不能直接进入运行态。调用yield()方法可以让运行态的线程进入就绪态。

线程死亡:

线程会以下面三种方式结束,进入死亡状态:

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

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

· 直接调用stop()方法结束线程----该方法容易导致死锁,不建议使用。

注意:

当主线程死亡时,其他线程不受影响,并不会随之结束。一旦子线程启动后,它就和主线程有着相同的地位,不受主线程影响。

可以用isAlive()方法测试一个线程是否死亡。当线程处于就绪、运行、阻塞时返回true,处于新建、死亡时,返回false。

不要对处于死亡状态的线程调用start()方法,对新建状态的线程调用两次start()方法也是错误的。都会引发IllegalThreadStateException异常。

控制线程:

join线程:

Thread提供了一个让一个线程等待另一个线程完成的方法----join()方法。当某个程序执行流中调用其他线程的join()方法时,调用线程就会阻塞,直到被join线程执行完毕为止。

join()方法有以下三种重载形式:

1. join():等待被join线程执行完成。

2. join(long millis):等待被join线程的时间最长为millis毫秒,超出时间则不再等待。

3. join(long millis, int nanos):等待被join线程最长为millis毫秒加nanos毫微秒。一般不使用该形式,一则程序对时间的精度无需精确到毫微秒;二则计算机硬件、操作系统无法精确到毫微秒。

后台线程:

这种线程在后台运行,为其他线程提供服务。也叫“守护线程”、“精灵线程”。JVM的垃圾回收线程就是典型的后台线程。

后台线程有个特征:如果所有前台线程死亡,后台线程会自动死亡。

调用Thread对象的setDaemon(true)方法可以将线程指定为后台线程,注意,该设置必须在线程启动之前设置,也就是说setDaemon(true)必须在start()方法之前调用,否则会引发IllegalThreadStateException异常。判断一个线程是否为后台线程用Thread类的isDaemon()。

前台线程创建的子线程默认是前台线程,后台线程创建的子线程默认是后台线程。

线程睡眠:sleep

如果需要让当前正在执行的线程暂停一段时间并进入阻塞状态,可以调用Thread对象的sleep()方法来实现。sleep()方法有两种重载方式。

· static void sleep(long millis): 让当前正在执行的线程暂停millis毫秒并进入阻塞状态。

· static void sleep(long millis,int nanos): 让当前正在执行的线程暂停millis毫秒加nanos毫微秒并进入阻塞状态。同样的原因不建议使用第二种形式。

当一个线程调用sleep()进入阻塞状态后,在其睡眠时间内不会获得执行机会,即使当前系统中没有其他可执行线程。因此sleep()常用来暂停程序的执行。

线程让步:yield

yield()和sleep()有点类似,它也可以让当前正在执行的线程暂停,但它不会阻塞线程,只是将该线程转入就绪态。yield()只是让线程暂停一下,让系统重新调度一下。完全有可能一个线程调用yield()后又立即被调度出来执行。

sleep()和yield()的区别:

· sleep()方法暂停当前线程后会给其他线程机会,不理会其他线程的优先级;yield()只会给优先级相同或更高的线程机会。

· sleep()方法会将线程转入阻塞态,而yield()方法不会阻塞线程。

· sleep()方法声明抛出了InterruptedException异常,所以调用sleep()方法要么捕捉异常要么显式声明抛出异常;而yield()方法没有声明抛出任何异常。

· sleep()方法比yield()方法有更好的移植性,通常不建议使用yield()方法控制并发线程的执行。

改变线程优先级:

每个线程默认的优先级都和它的父线程相同。一般情况下main()具有一般优先级,由它创建的子线程也具有一般优先级。

Thread类提供了setPriority(int newPriority)、getPriority()方法来设置和获取优先级。setPriority()方法参数是一个1~10的整数,也可以使用Thread类的三个静态常量:

· MAX_PRIORITY: 其值为10;

· MIN_PRIORITY: 其值为1;

· NORM_PRIORITY: 其值为5;

因为有些操作系统不支持10个这么多的优先级,所以为了程序的兼容性最好使用三个静态常量。

下一篇--线程同步&线程通信

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 上一篇----线程的创建和启动
  • 新建和就绪态:
  • 运行态和阻塞态:
  • 线程死亡:
  • 控制线程:
    • join线程:
      • 后台线程:
        • 线程睡眠:sleep
          • 线程让步:yield
            • 改变线程优先级:
            • 下一篇--线程同步&线程通信
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档