线程概念:现代操作系统调度的最小单元是线程,也叫轻量级进程(Light Weight Process),在一个进程中可以创建多个线程,这些线程都拥有各自的计数器、堆栈和局部变量等属性,并且能够访问共享的内存变量。处理器在这些线程上高速切换。
线程优先级
现代操作系统基本采用时分的形式调度运行的线程。线程分配到的时间片多少也就决定了使用处理器资源多少,而线程优先级就是决定线程需要多或少分配一些处理器资源的线程属性。
在Java线程中,通过一个整型成员变量priority来控制优先级,优先级范围从1~10,在线程构建的时候可以通过setPriority(int)
方法来修改优先级,默认优先级是5,优先级高的线程分配时间片的数量要多于优先级低的线程。
设置线程优先级时,针对频繁阻塞(休眠或I/O操作)的线程需要设置较高优先级,而偏重计算(需要较多CPU时间或者偏运算)的线程则设置较低的优先级,确保处理器不会被独占。
在不同的JVM以及操作系统上,线程规划会存在差异,有些操作系统甚至会忽略对线程优先级的设定。线程优先级不能作为程序正确性的依赖,因为操作系统可以完全不用理会Java线程对于优先级的设定。
线程的状态
Java线程在运行的生命周期中可能处于6种不同的状态,在给定的一个时刻,线程只能处于其中一个状态。
状态名称 | 说明 |
---|---|
NEW | 初始状态,线程被创建,但是还没有调用start()。 |
RUNNABLE | 运行状态,Java线程将操作系统中的就绪和运行两种状态统称为“运行中”。 |
BLOCKED | 阻塞状态,表示线程阻塞于锁。 |
WAITING | 等待状态,表示线程进入等待状态,进入该状态表示当前线程需要等待其他线程做出一些特定动作(通知或中断)。 |
TIME_WAITING | 超时等待状态,该状态不同于WAITING,它是可以在指定的时间自行返回的。 |
TERMINATED | 终止状态,表示当前线程已经执行完毕。 |
Daemon线程
Daemon线程是一种支持型线程,因为它主要被用作程序中后台调度以及支持性工作。这意味着,当一个Java虚拟机中不存在非Daemon线程的时候,Java虚拟机将会退出。可以通过调用Thread.setDaemon(true)
将线程设置为Daemon线程。
Daemon属性需要在启动线程之前设置,不能在启动线程之后设置。
Daemon线程被用作完成支持性工作,但是在Java虚拟机退出时Daemon线程中的finally块不一定会执行。在构建Daemon线程时,不能依靠finally块中的内容来确保执行关闭或清理资源的逻辑。
启动和终止线程
启动线程
线程对象在初始化完成之后,调用start()方法就可以启动这个线程。线程start()方法的含义是:当前线程同步告知Java虚拟机,只要线程规划器空闲,应立即启动调用start()方法的线程。
中断线程
中断可以理解为线程的一个标识位属性,它表示一个运行中的线程是否被其他线程进行了中断操作。其他线程通过调用该线程的interrupt()
方法对其进行中断操作。
线程通过检查自身是否被中断来进行响应,线程通过方法isInterrupted()
来进行判断是否被中断,也可以调用静态方法Thread.interrupted()
对当前线程的中断标识位进行复位。如果该线程已经处于终结状态,即使该线程被中断过,在调用该线程对象的isInterrupted()时依旧会返回false。
从Java的API中可以看到,许多声明抛出InterruptedException的方法(例如Thread.sleep(long)方法)这些方法在抛出InterruptedException之前,Java虚拟机会先将该线程已经处于终结状态,即使该线程被中断过,在调用该线程对象的isInterrupted()时依旧返回false。
suspend()、resume()、stop()
suspend()、resume()、stop()表示线程的暂停、恢复、停止操作。
不建议使用的原因主要有:以suspend()方法为例,在调用后,线程不会释放已经占有的资源(比如锁),而是占有着资源进入睡眠状态,这样容易引发死锁问题。同样,stop()方法在终结一个线程时不会保证线程的资源正常释放,通常是没有给予线程完成资源释放工作的机会,因此会导致程序可能工作在不确定状态下。
安全地终止线程
中断状态是线程的一个标识位,而中断操作是一种简便的线程间交互方式,而这种交互方式最适合用来取消或停止任务。除了中断以外,还可以利用一个volatile修饰的boolean变量来控制是否需要停止任务并终止该线程。