【0】README
0.1) 本文描述转自 core java volume 1, 源代码为原创,旨在理解 java线程——中断线程+线程状态+线程属性(优先级) 的相关知识;
【1】中断线程
1.1)当线程的run方法执行方法体中最后一条语句后, 并经由return语句返回时, 或出现了在方法中没有捕获的异常时,线程将终止;
1.2)强制线程终止: interrupt 方法可以用来请求终止线程;
- 1.2.1)判断线程是否已经终止: Thread.currentThread().isInterrupted()
- 1.2.2)但是,如果线程被阻塞, 就无法检测中断状态,这是产生 InterruptedException异常的地方;
public void run()
{
try
{
while(!Thread.currentThread().isInterrupted())
.....
}
catch(){}
finally(){}
}
- 1.2.3)中断状态时的线程调用 sleep, 不仅不会休眠, 相反, 抛出IntertupptedException;
Annotation)有两个非常类似的方法, interrupted 和 isInterrupted
- A1)Interrupted 方法是一个静态方法: 它检测当前的线程是否中断, 而且,该方法会清除该线程的中断状态;
- A2)isInterrupted 方法是一个实例方法: 可用来检验是否有线程被中断, 调用这个方法不会改变中断状态;
1.3)有两种方法用来抛出 InterrupttedException
- 1.3.1)在catch 子句中调用 Thread.currentThread().interrrupt() 来设置中断状态;
void fun()
{
try{}
catch()
{ Thread.currentThread().interrupte();}
}
- 1.3.2)或者用throws 标记你的方法, 不采用 try 语句块捕获这个异常
void func() throws InterruptedException
{
sleep(delay);
}
【2】线程状态
2.1)线程有6种状态(status):
- S1) new(新创建);
- S2) Runnable(可运行);
- S3) Blocked(被阻塞);
- S4) Waiting(等待);
- S5) Timed waiting(计时等待);
- S6) Terminated(被终止);
- Attention)记住, 在任何时刻,一个可运行线程可能正在运行也可能没有运行(这就是为什么将这个状态称为 可运行而不是 运行);
【3】被阻塞线程和等待线程
3.1)阻塞状态:当一个线程试图获取一个内部的对象锁,而该锁被其他线程持有, 则该线程进入阻塞状态;
3.2)等待状态:当线程等待另一个线程通知调度器一个条件时, 它进入等待状态;(在调用 Object.wait 或 Thread.join 方法 或是等待java.util.concurrent 库中的Lock 或 Condition时, 就会出现这种case);
3.3)超时参数:调用它们导致线程进入计时等待状态, 这一状态将一直保持到超时期满或者接收到适当的通知, 方法有:Thread.sleep , Object.wait, Thread.join, Lock.tryLock ,Condition.await;
【4】被终止的线程
4.0)终止的原因(Reasons):
- R1)因为run方法正常退出而终止;
R2)因为一个没有捕获的异常终止了run方法而意外死亡;
M1)start方法:开启线程(抑或是分配CPU), 它执行Runnable接口的 run 方法;
- M2)yield()方法的作用是:暂停当前正在执行的线程对象,并执行其他线程。;
- M3)Thread的非静态方法join()方法:让一个线程B“加入”到另外一个线程A的尾部。在A执行完毕之前,B不能工作。例如:
Thread t = new MyThread();
t.start();
t.join();
- M3.1)另外,join()方法还有带超时限制的重载版本。 例如t.join(5000);则让线程等待5000毫秒,如果超过这个时间,则停止等待,变为可运行状态。
线程的加入join()对线程栈导致的结果是线程栈发生了变化,当然这些变化都是瞬时的。下面给示意图
- M4)Thread.sleep方法: 使当前线程睡眠至少多少毫秒
- M5) void notify() : 唤醒在此对象监视器上等待的单个线程。
- M6) void notifyAll(): 唤醒在此对象监视器上等待的所有线程。
- M7) void wait() :导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
- M8)synchronized : 同步方法或同步块的关键字;
【5】线程属性
5.1)线程优先级
- 5.1.1)设置线程的优先级:线程默认的优先级是创建它的执行线程的优先级。可以通过setPriority(int newPriority)更改线程的优先级。例如:
Thread t = new MyThread();
t.setPriority(8);
t.start();
- 线程优先级为1~10之间的正整数,JVM从不会改变一个线程的优先级。
- 5.1.1.1)线程默认优先级是5,Thread类中有三个常量,定义线程优先级范围:
- 5.1.1.2)static int MAX_PRIORITY :线程可以具有的最高优先级。
- 5.1.1.3)static int MIN_PRIORITY :线程可以具有的最低优先级。
- 5.1.1.4)static int NORM_PRIORITY :分配给线程的默认优先级 == 5。
5.2)守护线程
- 5.2.1)通过调用 t.setDaemon(true) 来将线程转换为 守护线程(daemon thread);
- 5.2.2)守护线程的唯一用途: 为其他线程提供服务;
- 5.2.3)看个荔枝:计时线程就是一个荔枝。它定时发送“计时器滴答”信号给其他线程或清空过时的高速缓存项的线程。当只剩下守护线程时, 虚拟机就退出了,因为如果只有守护线程, 就没必要继续运行程序了;
5.3)未捕获异常处理器
- 5.3.1)出现的问题: 线程的run方法不能抛出任何被检测的异常, 但是,不被检测的异常会导致线程死亡;
- 5.3.2)解决方法:在线程死亡之前, 异常被传递到一个用于未捕获异常的处理器;
- 5.3.2.1)该处理器必须属于一个实现了 Thread.UncaughtExceptionHandler 接口的类。 这个接口只有一个方法: void uncaughtExceptionHandler ;
- 5.3.2.2)可以用 setUncaughtExceptionHandler 方法为任何线程安装一个 处理器。 也可以用 Thread的静态方法 setDefaultUncaughtExceptionHandler 为所有线程安装一个默认处理器;
- 5.3.2.3)如果不安装默认的处理器, 默认处理器就为空。 但是,如果不为独立的线程安装处理器,此时的处理器就是该线程的 ThreadGroup 对象了;(但是建议,不要在程序中使用线程组 ThreadGroup);