多进程与多线程的本质区别在于:每个进程拥有自己的一整套变量,而线程则共享数据。如果需要执行一个比较耗时的任务,应该使用独立的线程。
可以通过实现 Runnable
接口或继承 Thread
类来创建独立的线程。
1) 实现 Ruannable
接口
class MyRunnable implements Runnable { public void run() { task code } } Ruannable r = new MyRuannable(); Thread t = new Thread(r); t.start();
2) 继承 Thread
类
class MyThread extends Thread { public void run() { task code } } Thread t = new MyThread(); t.start();
对于 Thread
类或 Runnable
对象,启动新线程调用的是 start()
方法,直接调用 run()
方法只会在同一个线程中执行任务。 start()
会启动这个线程,引发调用 run()
方法。 start()
方法会立即返回,并且新线程并行运行。
如果有很多任务,为每个任务创建一个独立的线程付出的代价太大,可以使用线程池来解决这个问题。
当线程的 run()
方法方法体执行完毕(自然终止)或在方法中出现没有捕获的异常时(意外终止),线程将终止。另外,可以使用 interrupt()
方法发送中断请求强制线程终止。
每个线程都有 boolean
标志的中断状态位,想弄清当前线程是否被中断(中断状态位是否被置位),需要当前线程自己判断。并且,被中断的线程可以决定如何响应中断。如果被中断线程被阻塞,就无法检测中断状态,就会产生 InterruptedException
异常。
public void run() { try { do some work while(! Thread.currentThread().isInterrupted() && more work to do) { do more work } } catch(InterruptedException e) { // thread was interrupted during sleep or wait (in blocked) } finally { cleanup if required } }
当产生异常时,有两种处理方式选择。
1) 在 catch
子句中设置中断状态。
catch(InterruptedException e) { Thread.currentThread().interrupt(); }
2) 不采用 try
语句块捕获异常,交给调用者处理。
void mySubTask() throws InterruptedException {}
测试当前线程是否被中断有 interrupted()
和 isInterrupted()
两个方法。
interrupted()
是一个静态方法,有副作用,会把中断状态位置为 false
;
isInterrupted()
是一个实例方法,无副作用。
线程有6种状态,可以调用 getState()
获取线程状态。
New:新创建状态,在可运行前还有些工作要做;
Runnable:可运行状态,可能正在运行也可能没有运行,是否运行需看操作系统调度;
Blocked:被阻塞状态,不活动,可能由于请求锁失败;
Waiting:等待状态,不活动,等待通知,比如调用 Thread.join()
方法;
Timed Waiting:计时等待状态,不活动,等待超时或通知,比如调用 Thread.sleep(long millis)
或 join(long millis)
方法;
Terminated:被终止状态,线程可能由于自然死亡或意外死亡。
每一个线程都有一个优先级,默认继承父线程。注意,不要将程序功能的正确性依赖于优先级。可以通过 setPriority(int newPriority)
方法设置线程优先级,最小优先级 MIN_PRIORITY
为1,默认优先级 NORM_PRIORITY
为5,最高优先级 MAX_PRIORITY
为10。
当操作系统的线程调度器有机会选择新线程时,会首先选择拥有较高优先级的线程。调用 Thread
类的静态方法 yield()
可使当前执行线程处于让步状态,如果有可运行的线程优先级大于等于此线程,那么这些线程将被调度。
守护线程的唯一用途是为其他线程提供服务,通过调用 t.setDaemon(true)
将线程转化为守护线程。如果只剩下守护线程,虚拟机就会退出。
注意,守护线程应该永远不去访问固有资源,因为这些操作可能会发生中断。
线程的 run()
方法不能抛出任何被检测的异常,但可能会抛出不被检测的异常,导致线程终止。就在线程死亡之前,异常被传递到未捕获异常处理器,进行处理,比如使用日志API发送异常到日志文件。
class MyUncaughtExceptionHandler implements UncaughtExceptionHandler { void uncaughtException(Thread t, Throwable e) { // t - terminated thread without exception catch // e - uncaught exception object do something like send exception info to log file } }
为线程设置处理器可通过方法 setUncaughtExceptionHandler()
或静态方法 setDefaultUncaughtExceptionHandler()
完成。如果不设置未捕获异常处理器,那么默认处理器为空。
方法 getUncaughtExceptionHandler()
用于获取未捕获异常处理器,但是有副作用,如果返回值为空,那么就会将 ThreadGroup
对象设置为处理器。线程组 ThreadGroup
对象的执行流大致如下:
if(该线程组有父线程组) { 父线程组的uncaughtException方法被调用 } else { if(Thread.getDefaultExceptionHandler()返回非空处理器) { 调用该处理器 } else { if(Throwable是ThreadDeath的一个实例) { // 由过时方法stop产生 什么都不做 } else { 输出栈踪迹到标准错误流 } } }