首先需要申明一点,java多线程在最新的api中,已经不推荐使用旧的方法了。java的多线程是协作式的而非抢占式的。
如果我们希望将一个java线程中断,thread中提供了多种方法stop(),resume(),suspend(), 但是在编写代码的时候我们会发现,在最新的jdk中java已经将这些方法都注上@Deprecated注解,也就是说这些方法jdk已经不再推荐使用了,
为什么不推荐使用呢,stop()方法不安全,它会导致线程不正确的释放资源,resume()方法和suspend()方法结合使用,suspend()挂起线程,该方法将线程挂起后,并不会释放该线程持有的对象锁,这就会很大几率导致线程死锁。
为了有效的防止这种问题,有的人提出如下解决方案
private static class MyThread extends Thread{
private volatile boolean flag = false;
@Override
public void run(){
while(!flag){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
interrupt();
throw new RuntimeException("error thread is interrupted");
}
System.out.println("thread is run");
}
}
}
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(100);
thread.flag = true;
}
通过一个flag变量,来判断线程是否处于中断状态。如果没有中断,则继续运行,如果中断了则不可以继续执行。其实这种方法大部分情况下是没有问题的,但是在有些时候会出现问题。
就像上面代码所示,在while代码块中我们进行了100毫秒的线程休眠,在这段休眠的时期,如果其他线程将这个flag的值改成true,但是当前线程并不会知道,它必须要将while代码块的所有代码执行完毕才会转到while条件判断;我们会发现System.out.printlin("thread is run");这行代码还是被执行了,但是实际上如果flag被改为true之后,这行代码理应不会执行的。这里就造成了线程处理的中断情况的非常不及时的问题。
所以在这里我们可以使用Thread类提供的interrupte(),和isInterrupted()方法来协作式开发。
如下
private static class MyThread extends Thread{
private volatile boolean flag = false;
@Override
public void run(){
while(!flag || !isInterrupted()){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
interrupt();
throw new RuntimeException("error thread is interrupted");
}
System.out.println("thread is run");
}
}
}
public static void main(String[] args) throws InterruptedException {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(10);
thread.flag = true;
thread.interrupt();
}
interrupte()方法表示中断一个线程,注意这里的中断线程并不是强制将该线程直接中断,而是将线程的中断标志位改成true,至于是否中断是由线程本身的实现决定,也就是run()方法里面的逻辑确定。我们可以在run()方法中判断!isInterrupted(),判断线程是否已经被中断,来确定是否执行下去。
java中任何一个阻塞方法都会存在InterruptedException异常,如果当前线程中断了,必定会跳到catch语句块中,我们在语句快中抛出异常,我们知道java线程死亡可以是线程执行结束,也可以是中途抛出异常,那么这时线程是真正的死亡了,这样就永远不会执行到System.out.println("thread is run")语句了
由此我们可以看出java多线程是协作式的,而非抢占式的