参考了 《Java核心技术》 卷I 第14章 多线程 14.1-14.4
1.线程概念
在面试中经常问到的一个问题,线程和进程的区别是什么? 本质在于每个进程的一整套变量,而线程是共享数据的,基于共享变量,线程之间的通信比进程之间的通信更加高效(这里又有面试题,进程之间的通信方式有哪些),此外,与进程相比,线程更加轻量,创建销毁一个线程比进程的代价小的多。
下面通过代码来看下
|
|
MyRunnable实现了Runnable接口,并实现了run方法
|
|
注意,不要直接调用Thread类或者Runnable的对象的run方法,直接调用run方法,只会执行同一个线程中的任务,而不会执行新线程,应该调用Thread类的start方法,这样才会创建一个新线程并执行run方法。
2.中断线程
当线程run方法执行完最后一条语句,return返回,或者出现了没有捕获的异常时,线程将终止,在Java早期版本中有一个stop方法,可以调用强制终止线程,但现在已经弃用了。因此除stop之外没有一种可以强制终止线程的方法。
然而interrupt方法可以请求终止线程,当调用interrupt方法,线程的中断状态将被置位,这是每一个线程都具有的标志位,每个线程都应该不时地检查这个标志,以判断线程是否被中断。还是刚刚例子:
|
|
|
|
console会输出true和0,因此可以证明调用interrupt方法只是置了标志位而已,并没有终止程序。
当一个被阻塞的线程(比如调用sleep或者wait方法)上调用interrupt方法,阻塞线程将抛出InterruptedException(抛出异常以后会将interrupt状态进行清除)。但是如果你先调用interrupt方法,而后在线程中调用sleep方法,它不会sleep,相反,会将interrupt状态清除(置为false),并抛出InterruptedException,可以看下下面程序
|
|
|
|
输出
|
|
可以看到在sleep之前,就对线程进行了interrupt调用,线程不会sleep。
还需要注意对InterruptedException异常处理要足够重视,不要在catch子句中什么都不做,可以有两种做法:
|
|
这样调用者可以对其检测,还可以抛出InterruptedException,由上级调用者捕获这一异常
|
|
但是注意实现Runnable接口的类的run方法是不允许抛出异常的。具体可以看下这里:http://stackoverflow.com/questions/11410042/why-cannot-run-of-runnable-throw-checked-exceptions
3.线程状态
现成6种状态:New,Runnable,Blocked,Waiting,Timed wating,Terminated,可以调用getState方法。
具体状态之间的转换关系:
4.线程属性
在Java中,每个线程都有一个优先级,默认情况下,一个线程继承他父亲线程的优先级,同时可以用setPriority方法提高或降低任何一个线程优先级。
通过setDaemon(true)可以设置一个线程为守护线程,注意此方法必须在启动线程之前调用。
之前说过run方法是不能抛出任何checked exception,但是他可以被unchecked exception所终止,在线程死亡之前,异常可以设置传递到一个用于捕获异常的处理器,具体可以看下core java 14.4.3中的详细介绍。