Java并发编程基础(一)
1. Java线程的状态
1.1 New
初始状态,创建线程但还没有调用start()方法。
1.2 Runnable
运行状态,Java线程的运行状态包括运行和就绪两种状态。
1.3 Block
阻塞状态,线程获取锁失败时进入阻塞状态。
1.4 Waiting
等待状态,进入等待状态的线程要需要等待其他线程的一些特定动作,如通知或中断。
1.5 Terminated
终止状态,表示退出当前线程。
2. Java线程状态变迁图
注意:阻塞状态是Java线程阻塞于synchronize修饰的同步方法或同步块(获取锁失败时),但阻塞在Java.Concurent包中Lock接口的线程状态却是等待状态3. 中断
3.1 理解中断
中断可以认为是线程的一个boolean类型的标志位属性,当一个线程(本线程或其他线程均可)调用方法Thread.interrupt()时该boolean值被设置为true,表示线程将被中断,即一个运行中的线程可被本线程或另一个线程中断。
3.2 中断的相关方法
方法 | 调用主体 | 作用 |
---|---|---|
public void interrupt() | Thread类实例对象 | 使被中断线程的中断标志位设置为true |
public boolean isInterrupted() | Thread类实例对象 | 判断线程的中断状态 |
public static boolean interrupted() | Thread类静态方法 | 对当前线程的中断标志位进行复位 |
3.3 线程的suspend()、resume()、stop()方法(均已过期)
●suspend():暂停线程。调用此方法后,线程虽进入睡眠状态,但不会释放占有的资源(比如锁),这样可能导致死锁的发生。
●resume():恢复处于睡眠状态的线程。
●stop():终结线程。该方法不保证线程在终结后能正常的释放线程资源,通常情况下不给予线程释放资源的机会,这将导致线程处于不确定的工作状态下。
注意:正因为suspend()、resume()、stop()自带的缺陷,所以这些方法才被标注为已过期。线程的暂停和恢复功能可通过等待/通知制来实现。
3.4 中断的使用
中断线程可分为三种类型:(1)中断非阻塞线程 (2)中断阻塞线程 (3)不可中断线程
●(1)中断非阻塞线程。中断方式有采用共享变量中断、采用中断机制。
- ●采用共享变量中断:利用一个自定义volatile boolean变量充当线程中断的标志位。
public class Test1 {
public volatile boolean on = false; //volatile变量修改后其他线程立即可见
public static void main(String[] args) {
Thread thread = new Thread( new Runnable() {
@Override
public void run() {
while(!on) { //当前线程没有被中断时
//执行正常的任务
//若当前线程被中断,即on被设置为true时,就会跳出这个循环
}
//执行到这时,说明线程已被中断,可以在这进行线程中断后资源的释放操作。
}
} );
}
}
复制代码
-
●采用中断机制:通过调用线程的中断方法实现中断。
-
Thread thread = new Thread( new Runnable() { @Override public void run() { while(!Thread.currentThread().isInterrupted()) { //当前线程没有被中断时 //执行正常的任务 //若当前线程被中断,即有线程调用了Thread.interrupt()方法时,就会跳出这个循环 } //执行到这时,说明线程已被中断,可以在这进行线程中断后资源的释放操作。 } }); 复制代码
-
小结:
-
●要实现非阻塞线程中断,程序要能够检测到中断标志位的变化(如通过while循环判断),否则即使中断标志位为true,也无法实现中断。
-
●上述两种中断非阻塞线程的方式在本质上是一致的,即都是通过感应中断标志位的变化来实现中断的逻辑。
-
●上述两种方式是安全的,因为线程在中断后有机会去清理资源。
●(2)中断阻塞线程。当线程调用Object.wait()、Thread.sleep()等方法时,线程处于阻塞状态。此时调用线程的中断方法会抛出InterruptedException异常来实现线程的中断。需要注意的是,InterruptedException异常抛出后中断标志位被设置为false,即isInterruped()方法的返回值为false,此时我们需要调用Thread.interrupt()方法再次把中断标志位设置为true,否则线程又将继续执行下去。 这里分享一点个人心得:有些资料会把线程的等待状态称为等待阻塞,线程的阻塞则称为同步阻塞。按照这种思路,线程调用Object.wait()方法时进入的状态为等待阻塞状态,也是线程的等待状态,这里容易混乱。
Thread thread = new Thread( new Runnable() {
@Override
public void run() {
while(!Thread.currentThread().isInterrupted()) {
try {
Thread.currentThread().sleep(5000);//当线程执行到这而又被中断时,这里将抛出InterruptedException异常。
} catch (InterruptedException e) {
Thread.currentThread().interrupt();//这里需要把中断标志位再次设置为true,否则无法跳出循环从而实先中断。
e.printStackTrace();
}
}
//执行到这时,说明线程已被中断,可以在这进行线程中断后资源的释放操作。
}
});
复制代码
●(3)不可中断线程。线程在使用synchronize同步块获取锁后是无法被中断的。