线程的生命周期

来源:互联网 发布:北京大学安金鹏 知乎 编辑:程序博客网 时间:2024/06/01 09:31

线程的生命周期:
(1)在线程的生命周期中,他要经过新建(new) 就绪(Runnable) 运行(Running) 阻塞(Blocked)和死亡(Dead)5种状态。
(2)新建和就绪状态:
当程序使用了New关键字创建了一个线程之后,该线程就处于新建状态,此时他和其他的Java对象一样,仅仅由Java虚拟机为其分配内存,并初始化成员变量的值。此时的线程对象没有表现出任何线程的动态特征,程序也不会执行线程的线程执行体。

当程序调用了start()方法之后,该线程就处于了就绪状态,Java虚拟机会为其创建方法调用栈和程序计数器,处于这个状态中的线程并没有开始运行,只是表示该线程可以运行了,至于该线程何时开始运行,取决于JVM里线程调度器的调度。

(3)启动线程使用start()方法,而不是run()方法。

public class InvokeRun extends Thread {     private  int i;     //重写run()方法,run()方法的主体就是线程执行体     public  void run(){           for(  ; i<100;i++){                System.out.println(Thread.currentThread().getName()+""+i);           }     }     public static void main(String[] args) {           for(int i=0;i<100;i++){                //调用Thread的currentThread()方法获取当前线程                System.out.println(Thread.currentThread().getName()+""+i);                if(i == 20){                     //直接调用线程对象的run()方法,系统会把线程对象当成普通对象,把run()方法当成普通方法                     //所以下面的代码并不会启动两个线程,而是依次执行run()方法                     new  InvokeRun().run();                     new InvokeRun().run();                }           }     }}

**上面程序创建线程对象后直接调用了线程的run()方法,程序运行的结果是只有一个线程:主线程。
**在调用了线程的run()方法后,该线程不再处于新建状态,不要再次调用该线程的对象的start()方法。
**只能对新建状态的线程调用start()方法,否则将引发IllegalThreadStateException异常。

——++————————————————————————————————————————————

运行和阻塞状态:
(1)如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态,如果计算机只有一个CPU,那么在任何时刻只有一个线程处于运行状态,当然,在一个多处理的机器上,将会有多个线程并行执行(parallel);当线程数大于处理器数时,依然会有多个线程在一个处理器上轮换的现象。
(2)当一个线程开始运行后,它不可能一直处于运行状态,线程在执行过程中需要中断,目的是使其他线程获得执行机会,线程调度的细节取决于底层平台所采用的策略。对于抢占式策略的系统而言,系统会给每个执行的线程一个小的时间段来处理任务,当该时间段用完之后,系统就会剥夺该系统所占用的资源,让其他线程获得执行的机会。在选择下一个线程时,系统会考虑线程的优先级。
(3)所有现代的桌面和服务器操作系统都采用抢占式的调度策略,但一些小型设备如手机则可能采用协作式的调度策略,在这样的系统中,只有当一个线程调用了它的sleep()和yield()方法后才会放弃所占用的资源,也就是必须由该线程主动放弃自己的资源。

(4)当发生如下情况时,线程将会进入阻塞状态:
*线程调用sleep()方法主动放弃所占有的系统资源
*线程调用了一个阻塞式IO方法,在该方法返回之前,该线程被阻塞。、
*线程试图获得一个同步监视器,但该同步监视器被其他线程所持有。
*线程在等待某个通知(notify)
*程序调用了线程的suspend()方法将该线程挂起。但这个方法容易导致死锁,所以应该尽量避免使用该方法。
(5)当发生如下特定的情况时可以解除上面的阻塞,让该线程重新进入就绪状态(注意是就绪状态,不是运行状态,也就是说,当阻塞线程阻塞被解除后,必须重新等待线程调度器再次调度它)
*调用sleep()方法经过了指定的时间
*线程调用的阻塞式IO已经返回
*线程成功的获得了试图取得的同步监视器
*线程正在等待某一个通知时,其他线程发出了一个通知
*处于挂起状态的线程被调用了resume()方法

————————————————————————————————————
线程死亡:
(1)线程会以如下三种方式结束,结束后就处于死亡状态:
**run()和call()方法执行完成,线程正常结束
**线程抛出了一个未捕获的Exception或者Error
**直接调用了该线程的stop()方法来结束该线程—该方法容易导致死锁。

(2)为了测试某个线程是否已经死亡,可以调用该线程对象的isAlive()方法,当线程处于 就绪 运行 阻塞三种状态时返回true,当处于新建 死亡状态时,返回false。
(3)不要对死亡的线程调用start()方法。

——————————————————————————
控制线程:
(1)Java的线程支持提供一些便捷的工具方法,通过这些便捷的工具方法可以很好的控制线程的执行。
(2)join线程:
Thread提供了然一个线程等待另一个线程完成的方法–join()方法,当在某个程序执行流中调用其他线程的join()方法时,调用线程将被阻塞,直到被join()方法加入的join线程执行完为止。
程序实例:

public class JoinThread  extends Thread{     //提供一个有参数的构造器,用于设置该线程的名字     public JoinThread(String name){           super(name);     }     //重写run()方法,定义线程执行体     public void run(){           for (int i = 0; i < 100; i++) {                System.out.println(getName()+ " "+i);           }     }     public static void main(String[] args) {           //启动子线程           new  JoinThread("新线程").start();           for (int i = 0; i < 100; i++) {                if (i==20) {                     JoinThread  jt=new JoinThread("被Join的线程");                     jt.start();                     //main线程调用了jt线程的Join()方法,main线程必须等到jt线程结束后才会向下执行。                }                System.out.println(Thread.currentThread().getName()+"  "+ i);           }     }}

oin()方法有如下三种重载形式:
***join() 等待被join()的线程执行完成
***join(long millis) 等待被join线程的时间最长为mills毫秒。如果在mills毫秒内被join的线程还没有执行结束,则不再等待。
***join(long mills, int nanos) 等待被join线程的时间最长为mills毫秒加上nanos微秒。
————————————————————————————————

后台进程:
(1)有一种进程,它是在后台运行的,它的任务是为其他线程提供服务,这种线程被称为后台线程。JVM的垃圾回收线程就是典型的后台线程。
(2)后台线程有个特征,如果所有的前台线程都死亡,后台线程会自动死亡。
(3)调用Thread对象的setDaemon(true)方法可以将指定线程设置为后台线程。程序实例:
public class DaemonThead extends Thread {
//定义后台线程的线程执行体和普通线程没有区别:
public void run(){
for (int i = 0; i < 100; i++) {
System.out.println(getName()+ ” “+i);
}
}

 public static void main(String[] args) {       DaemonThead   t = new DaemonThead();       //将此线程设置为后台线程       t.setDaemon(true);       //启动后台线程       t.start();       for (int i = 0; i < 10; i++) {            System.out.println(Thread.currentThread().getName()+ " "+i);       }       //程序执行到此处,前台线程(main)结束,后台线程也随之结束       //后台线程无法运行到999 }

}

0 0
原创粉丝点击