Java多线程(二)线程的生命周期、优先级和控制
Java多线程(二)线程的生命周期、优先级和控制
线程的生命周期:线程主要有以下状态
(1)创建
当实例化一个Thread对象并执行start()方法后,线程进入“可执行”状态,开始执行,虽然多线程给用户一种同时执行的感觉,但事实上在同一时间点上只有一个线程在执行,只是线程之间转换的动作很快,所以看起来好像同时在执行一样。
(2)可执行
当线程启用start()方法后,进入“可执行”状态,执行用户覆写的run()方法。一个线程进入可执行状态,并不代表它可以一直执行到run()结束为止,事实上它只是加入此应用程序执行安排的队列中。这个线程加入了进程的线程执行队列中,对于大多数计算机来说,只有一个处理器,无法使多个线程同时执行,这时需要合理安排线程执行计划,让那些处于“可执行”状态下的线程合理共享cpu资源。所以,一个处于“可执行”状态下的线程,实际上可能正在等待取得cpu实践,也就是等候执行权,在何时给予线程执行权,则有java虚拟机和现成的优先级来决定。
(3)非可执行
在“可执行”状态下,线程可能被执行完毕,也可能没有执行完毕,处于等待执行权的队列中,线程离开”可执行“状态下的等待队列时,线程进入”非可执行“状态。可以使用Thread类中的wait()、sleep()方法使线程进入“非可执行“状态。当线程进入”非可执行“状态下,cpu不分配时间片给这个线程,若希望线程回到”可执行“状态时,可以使用notify()方法或者是notifyAll()方法以及interrupt()方法。
(4)消亡
当run()方法执行完毕后,线程自动消亡,当Thread类调用start()方法时,java虚拟机自动调用它的run()方法,而当run()方法结束时,该Thread会自动终止。以前Thread类中存在一个停止线程的stop()方法,不过现在已经被废弃了,因为调用这个方法,很容易使程序进入不稳定状态。
线程的优先级:
在Java语言中,线程有执行的优先,优先级的范围是1~10,默认值为5,可以使用Thread类中的setPriority()方法来设置线程的优先级,但必须是1~10的范围内,否则会出现异常。优先级较高的线程会被提前执行,当它执行完毕才会轮到优先权较低的线程执行如果优先级相同,那么采用轮流执行的方式。
绝大多数操作系统都支持Time slicing, 简单地说就是操作系统会为每个线程分配一 小段CPU时间,时间一到就换下一个线程, 即便这个线程没有执行完毕。对于不支持 Time slicing的操作系统,每个线程必须执行完毕后,才轮到下一个线程,如果需要此线程礼让一下其他线程,可以使用Thread类中 的yield〇方法。
线程的控制:
线程的控制包括线程的启动、挂起、状态检查以及如何正确结束线程,由于在程序中使用多线程,为合理安排线程的执行顺序,可以对线程进行相应的控制。
1.线程的启动
一个新的线程被创建后处于初始状态,实际上并没有立刻进入运行状态,而是处理就绪状态,当轮到这个线程执行时,即进入“可执行”状态,开始执行线程run()方法中的代码。执行run()方法是通过调用Thread类中start()方法来实现的。调用start()方法启动线程的run()方法不同于一般的调用方法,一般方法必须等到方法执行完毕才能够返回。而对于start()方法来说,调用线程的start()方法后,startG方法告诉系统该线程准备就绪并可以启动run()方法后,就返回,并继续执行调用start()方法下面的语句,这时run()方法可能还在运行,这样,就实现了多任务操作。
2.线程的挂起
当一个线程进入“非可执行”状态,也就是挂起状态时,必然存在某种原因使其不能继续运行,这些原因可能是如下几种情况。
(1)通过调用sleep()方法使线程进入休眠状态,线程在指定时间内不会运行。
(2)通过调用join()方法使线程挂起,如果线程A调用线程B的join()方法,那么线程A将被挂起,直到线程B执行完毕为止。
(3)通过调用wait()方法使线程挂起,直到线程得到了notify()和notifyAll()消息,线程才会进入“可执行”状态。
(4)线程在等待某个输入/输出完成。
3.线程状态检查
一般情况下无法确定一个线程的运行状态,对于这些处于未知状态的线程,可以通过isAlive()方法来确定一个线程是否仍处在活动状态。当然即使处于活动状态的线程也并不意味着这个线程一定正在运行,对于一个已开始运行但还没有完成任务的线程,这个方法返回值为true。isAlive()方法用于测试线程是否处于活动状态。如果线程已经启动且尚未终止,则为活动状态。
4.结束线程
结束线程有两种情况:
(1)自然消亡:一个线程从run()方法的结尾处返回,自然消亡且不能再被运行;
(2)强制死亡:调用Thread类中stop()方法强制停止,不过该方法已经被废弃。
虽然这两种情况都可以停止一个线程,但最好的方式是自然消亡,简单地说,如果要停止一个线程的执行,最好提供一个方式让线程可以完成run()的流程。
5.后台线程
后台线程,即Daemon(英文意思:守护神; (希腊神话中) 半人半神的精灵; [计] 守护进程;)线程,它是一个在后台执行服务的线程。例如操作系统中的隐藏线程和Java语言中的垃圾自动回收线程等。如果所有的非后台线程都结束了,则后台线程也会自动终止。可以使用Thread类中的setDaemon()方法来设置一个线程为后台线程。但是有一点值得注意:必须在线程启动之前调用setDaemon()方法,这样才能将这个线程设置为后台线程。当设置完成一个后台线程后,可以使用Thread类中的isDaemon()方法来判断线程是否是后台线程。
本文内容多参考书本知识,随笔记下来学习分享且方便以后查看。