转载

Java多线程之线程的创建、中断、状态与属性

多进程与多线程的本质区别在于:每个进程拥有自己的一整套变量,而线程则共享数据。如果需要执行一个比较耗时的任务,应该使用独立的线程。

可以通过实现 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 {             输出栈踪迹到标准错误流         }     } }
原文  https://segmentfault.com/a/1190000004907240
正文到此结束
Loading...