1.线程的生命周期
线程是一个动态执行的过程,它也有一个从产生到死亡的过程。
(1)生命周期的五种状态
新建(new Thread)
当创建Thread类的一个实例(对象)时,此线程进入新建状态(未被启动)。
例如:Thread t1=new Thread();
就绪(runnable)
线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。例如:t1.start();
运行(running)
线程获得CPU资源正在执行任务(run()方法),此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,线程将一直运行到结束。
死亡(dead)Terminated(终止状态)
当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。
自然终止:正常运行run()方法后终止
异常终止:调用stop()方法让一个线程终止运行
堵塞(blocked)
由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。
正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。
正在等待:调用wait()方法。(调用motify()方法回到就绪状态)
被另一个线程所阻塞:调用suspend()方法。(调用resume()方法恢复)
新建、就绪状态
使用new 关键字创建一个线程时,该线程处于新建状态
线程对象调用 start()方法时,该线程处于就绪状态(线程获得CPU,等待执行)
线程的启动是从调用start()方法开始的,而不是run()方法
永远不要调用线程对象的run()方法
如果直接调用 run() 方法,系统会把该线程对象当成普通对象,run()方法也将变成一个普通方法(而不是线程执行体)而立即执行。
如果直接调用了 run() 方法,则该线程不再处于新建状态,不能再次调用 start()方法,否则会报IllegalThreadStateException异常
如果直接调用了 run() 方法,则在run() 方法里不能直接通过this.getName() 方法获得线程名(此时获取的是对象名,因为此时已经没有线程体了,线程对象变成了普通对象),而是通过Thread.currentThread().getName() 获得。
如果希望线程对象调用start() 方法后立即执行run() 方法(线程体),可通过Thread.sleep(1)让主线程睡眠1毫秒,而给其他线程执行机会。
运行、阻塞状态
如果CPU是单核,则在任一时刻都只有一个线程在执行。当线程数据大于核数时,就会出现线程轮换。
所有桌面和服务器系统都采用的是抢占式调度策略,即当前线程在系统允许的执行时间之后,就给其他线程获得执行机会,且优先给优化级高的线程。
有些小型系统如手机会采用协作式调度策略,即只能当前线程主动放弃所占资源(调用sleep()或yield()方法)
线程从阻塞状态解除后只能转变为就绪状态,而就绪状态变为运行状态只能由系统线程调度转换。
线程调用了yield()方法也会重新进入就绪状态
发生以下情况时,线程将进入阻塞状态:
调用sleep()方法时。此时会放弃它所占用的处理器资源。【过了sleep指定时间不再阻塞】
调用一个阻塞式IO方法还没有返回之前,该线程被阻塞。【阻塞IO方法返回后不再阻塞】
试图获取一个正被其他线程所持有的同步监视器。【拿到监听器不再阻塞】
等待通知时(notify)。【其他线程调用了notify时不再阻塞】
调用suspend()方法将程序挂起时。【线程调用resume()方法时撤销挂起时不再阻塞】
线程死亡
线程死亡情况:
线程正常结束(run或call方法执行完)
线程抛出一个未捕获的Exception或Error
线程自己调用stop()方法(该方法容易导致死锁)
一旦子线程启动后,它就拥有和主线程相同的地位,不受主线程的影响。
线程对象只能调用一次start()方法,且只能在新建状态时才能调用。否则会抛出IllegalThreadStateException异常

842

被折叠的 条评论
为什么被折叠?



