线程在Java中占据着重要的位置,同时包含着很多的内容,从本文到同步、线程消息通知、线程安全集合类,再到线程池、线程调度,以及线程与I/O之间的关系等等,都值得认真研究一番。本文尝试归纳线程的生命周期,从线程的创建到线程管理这些基本内容。
重要方法
以下是线程生命周期中一些重要的方法,其中有些是已经过时,不建议使用的方法。
|
|
线程创建
继承Thread类
|
|
实现Runnable接口
这里用了一个经典的卖票的例子,但却是线程不安全的,因为自增或者自减操作本身不是原子性的,一旦出现线程竞争就会导致数据不一致,比如下面两个线程分别卖完票之后,居然都出现了剩余99张票的情况,这就分明是错误的。如果要想修改的话可以将int类型修改为AtomicInteger原子类或者用synchronized这个关键字修饰自减整个操作。
线程启动
当准备要运行程序代码时候,就调用start方法,这个方法会做一些准备工作之后调用线程内部的run方法。在start()
方法被调用之后,新的thread可说是“活跃的(alive)”,可以通过isAlive()
方法判断线程的状态,如果返回结果是true,则该线程已经被启动并且正在运行run()
这个方法,否则该线程可能还没有启动或者已经被终结了。
线程终止
一且启动后,thread只能执行一个method;run()
方法。这个method可以很复杂,它
可以永远地执行下去,且它也可以调用其他method.无论如何,一旦run()
方法完成
了执行动作,thread也就必须完成它的执行动作。因此,终结thread的唯一办法就是安排run()
方法完成。
- 线程的
stop()
方法,但是stop()
方法有个固有的问题(内部的race condition),因此stop()
方法已经被废除且不应该使用。 - 设定标记,通过判断外界标记条件是否符合要求来终止线程运行。
interrupt()
方法,当你想终结thread的时候,通常会想立即地完成它的blocking method,此时可以使用Thread的interrupt()方法来中断任何的blocking method.但是此方法会带来一个问题就是,中断任何的blocked method 都会抛出InterruptedException.比如sleep()
、wait()
、join()
方法等等,都是blocking method.- 异常造成的终止,
run()
这个method不能抛出checked异常,但如同其他的Java method,它可以抛出unchecked异常。(这里简单说下:Checked exception 是在编译阶段的异常,强制检查,必须要catch的,比如IOException;unchecked exception分为Error和Runtime exception,是 runtime 阶段碰到的异常. 在编译的时候不需要检查 (checked),也无法检查的,比如NPE、ArrayIndexOutOfBoundsException等等.)如果run方法在运行时不能catch到运行时异常,也会造成线程的终止。
线程善后
一个完成run()
方法的线程就是已经终结的,不再是活跃的(isAlive()
方法会返回false)。一般来说,之后你就不应该再占据该thread的引用以便让该thread在终结时能够被同收。一个还要占据thread引用的场景就是要判别该线程是否已经完成工作,通过join()
方法来完成。join()
方法经常用在想知道是否该线程已经完成,当调用该方法时,join()
方法会被block住直到thread完成它的run()
方法。如果thread已经完成它的run()
方法,join()
方法就会立即返回,不再block。
-EOF-